Merge "Create a new constant for system app to start a voice service."
diff --git a/Android.bp b/Android.bp
index c202408..834c9b0 100644
--- a/Android.bp
+++ b/Android.bp
@@ -305,6 +305,7 @@
"core/java/android/service/euicc/IUpdateSubscriptionNicknameCallback.aidl",
"core/java/android/service/gatekeeper/IGateKeeperService.aidl",
"core/java/android/service/contentcapture/IContentCaptureService.aidl",
+ "core/java/android/service/contentcapture/IContentCaptureServiceCallback.aidl",
"core/java/android/service/notification/INotificationListener.aidl",
"core/java/android/service/notification/IStatusBarNotificationHolder.aidl",
"core/java/android/service/notification/IConditionListener.aidl",
@@ -476,6 +477,7 @@
"media/java/android/media/IMediaRouterClient.aidl",
"media/java/android/media/IMediaRouterService.aidl",
"media/java/android/media/IMediaSession2.aidl",
+ "media/java/android/media/IMediaSession2Service.aidl",
"media/java/android/media/IMediaScannerListener.aidl",
"media/java/android/media/IMediaScannerService.aidl",
"media/java/android/media/IPlaybackConfigDispatcher.aidl",
@@ -1317,7 +1319,6 @@
"ext",
"framework",
"voip-common",
- "android.test.mock.impl",
],
local_sourcepaths: frameworks_base_subdirs,
installable: false,
diff --git a/api/current.txt b/api/current.txt
index 05e8c62..6316ee8 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5245,8 +5245,8 @@
method public android.app.Notification clone();
method public int describeContents();
method public boolean getAllowSystemGeneratedContextualActions();
- method public android.app.PendingIntent getAppOverlayIntent();
method public int getBadgeIconType();
+ method public android.app.Notification.BubbleMetadata getBubbleMetadata();
method public java.lang.String getChannelId();
method public java.lang.String getGroup();
method public int getGroupAlertBehavior();
@@ -5459,6 +5459,25 @@
method public android.app.Notification.BigTextStyle setSummaryText(java.lang.CharSequence);
}
+ public static final class Notification.BubbleMetadata implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getDesiredHeight();
+ method public android.graphics.drawable.Icon getIcon();
+ method public android.app.PendingIntent getIntent();
+ method public java.lang.CharSequence getTitle();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.app.Notification.BubbleMetadata> CREATOR;
+ }
+
+ public static class Notification.BubbleMetadata.Builder {
+ ctor public Notification.BubbleMetadata.Builder();
+ method public android.app.Notification.BubbleMetadata build();
+ method public android.app.Notification.BubbleMetadata.Builder setDesiredHeight(int);
+ method public android.app.Notification.BubbleMetadata.Builder setIcon(android.graphics.drawable.Icon);
+ method public android.app.Notification.BubbleMetadata.Builder setIntent(android.app.PendingIntent);
+ method public android.app.Notification.BubbleMetadata.Builder setTitle(java.lang.CharSequence);
+ }
+
public static class Notification.Builder {
ctor public Notification.Builder(android.content.Context, java.lang.String);
ctor public deprecated Notification.Builder(android.content.Context);
@@ -5478,9 +5497,9 @@
method public static android.app.Notification.Builder recoverBuilder(android.content.Context, android.app.Notification);
method public android.app.Notification.Builder setActions(android.app.Notification.Action...);
method public android.app.Notification.Builder setAllowSystemGeneratedContextualActions(boolean);
- method public android.app.Notification.Builder setAppOverlayIntent(android.app.PendingIntent);
method public android.app.Notification.Builder setAutoCancel(boolean);
method public android.app.Notification.Builder setBadgeIconType(int);
+ method public android.app.Notification.Builder setBubbleMetadata(android.app.Notification.BubbleMetadata);
method public android.app.Notification.Builder setCategory(java.lang.String);
method public android.app.Notification.Builder setChannelId(java.lang.String);
method public android.app.Notification.Builder setChronometerCountDown(boolean);
@@ -5695,8 +5714,8 @@
public final class NotificationChannel implements android.os.Parcelable {
ctor public NotificationChannel(java.lang.String, java.lang.CharSequence, int);
+ method public boolean canBubble();
method public boolean canBypassDnd();
- method public boolean canOverlayApps();
method public boolean canShowBadge();
method public int describeContents();
method public void enableLights(boolean);
@@ -5712,7 +5731,7 @@
method public android.net.Uri getSound();
method public long[] getVibrationPattern();
method public boolean hasUserSetImportance();
- method public void setAllowAppOverlay(boolean);
+ method public void setAllowBubbles(boolean);
method public void setBypassDnd(boolean);
method public void setDescription(java.lang.String);
method public void setGroup(java.lang.String);
@@ -5746,7 +5765,7 @@
public class NotificationManager {
method public java.lang.String addAutomaticZenRule(android.app.AutomaticZenRule);
- method public boolean areAppOverlaysAllowed();
+ method public boolean areBubblesAllowed();
method public boolean areNotificationsEnabled();
method public boolean canNotifyAsPackage(java.lang.String);
method public void cancel(int);
@@ -7663,6 +7682,7 @@
field public static final int ACTIVITY_RESUMED = 1; // 0x1
field public static final int ACTIVITY_STOPPED = 23; // 0x17
field public static final int CONFIGURATION_CHANGE = 5; // 0x5
+ field public static final int DEVICE_SHUTDOWN = 26; // 0x1a
field public static final int FOREGROUND_SERVICE_START = 19; // 0x13
field public static final int FOREGROUND_SERVICE_STOP = 20; // 0x14
field public static final int KEYGUARD_HIDDEN = 18; // 0x12
@@ -12305,6 +12325,7 @@
method public java.lang.String getPositionDescription();
method public int getResourceId(int, int);
method public android.content.res.Resources getResources();
+ method public int getSourceStyleResourceId(int, int);
method public java.lang.String getString(int);
method public java.lang.CharSequence getText(int);
method public java.lang.CharSequence[] getTextArray(int);
@@ -16438,9 +16459,9 @@
public class BiometricManager {
method public int canAuthenticate();
- field public static final int BIOMETRIC_ERROR_NO_BIOMETRICS = 11; // 0xb
+ field public static final int BIOMETRIC_ERROR_HW_UNAVAILABLE = 1; // 0x1
+ field public static final int BIOMETRIC_ERROR_NONE_ENROLLED = 11; // 0xb
field public static final int BIOMETRIC_ERROR_NO_HARDWARE = 12; // 0xc
- field public static final int BIOMETRIC_ERROR_UNAVAILABLE = 1; // 0x1
field public static final int BIOMETRIC_SUCCESS = 0; // 0x0
}
@@ -16483,6 +16504,7 @@
method public android.hardware.biometrics.BiometricPrompt build();
method public android.hardware.biometrics.BiometricPrompt.Builder setDescription(java.lang.CharSequence);
method public android.hardware.biometrics.BiometricPrompt.Builder setNegativeButton(java.lang.CharSequence, java.util.concurrent.Executor, android.content.DialogInterface.OnClickListener);
+ method public android.hardware.biometrics.BiometricPrompt.Builder setRequireConfirmation(boolean);
method public android.hardware.biometrics.BiometricPrompt.Builder setSubtitle(java.lang.CharSequence);
method public android.hardware.biometrics.BiometricPrompt.Builder setTitle(java.lang.CharSequence);
}
@@ -22664,6 +22686,7 @@
method public deprecated double getCarrierPhase();
method public deprecated double getCarrierPhaseUncertainty();
method public double getCn0DbHz();
+ method public int getCodeType();
method public int getConstellationType();
method public int getMultipathIndicator();
method public double getPseudorangeRateMetersPerSecond();
@@ -22679,6 +22702,7 @@
method public boolean hasCarrierFrequencyHz();
method public deprecated boolean hasCarrierPhase();
method public deprecated boolean hasCarrierPhaseUncertainty();
+ method public boolean hasCodeType();
method public boolean hasSnrInDb();
method public void writeToParcel(android.os.Parcel, int);
field public static final int ADR_STATE_CYCLE_SLIP = 4; // 0x4
@@ -22687,6 +22711,21 @@
field public static final int ADR_STATE_RESET = 2; // 0x2
field public static final int ADR_STATE_UNKNOWN = 0; // 0x0
field public static final int ADR_STATE_VALID = 1; // 0x1
+ field public static final int CODE_TYPE_A = 0; // 0x0
+ field public static final int CODE_TYPE_B = 1; // 0x1
+ field public static final int CODE_TYPE_C = 2; // 0x2
+ field public static final int CODE_TYPE_CODELESS = 13; // 0xd
+ field public static final int CODE_TYPE_I = 3; // 0x3
+ field public static final int CODE_TYPE_L = 4; // 0x4
+ field public static final int CODE_TYPE_M = 5; // 0x5
+ field public static final int CODE_TYPE_P = 6; // 0x6
+ field public static final int CODE_TYPE_Q = 7; // 0x7
+ field public static final int CODE_TYPE_S = 8; // 0x8
+ field public static final int CODE_TYPE_UNKNOWN = -1; // 0xffffffff
+ field public static final int CODE_TYPE_W = 9; // 0x9
+ field public static final int CODE_TYPE_X = 10; // 0xa
+ field public static final int CODE_TYPE_Y = 11; // 0xb
+ field public static final int CODE_TYPE_Z = 12; // 0xc
field public static final android.os.Parcelable.Creator<android.location.GnssMeasurement> CREATOR;
field public static final int MULTIPATH_INDICATOR_DETECTED = 1; // 0x1
field public static final int MULTIPATH_INDICATOR_NOT_DETECTED = 2; // 0x2
@@ -25440,6 +25479,7 @@
method public java.lang.Object setAuxEffectSendLevel(float);
method public java.lang.Object setDataSource(android.media.DataSourceDesc);
method public java.lang.Object setDisplay(android.view.SurfaceHolder);
+ method public void setDrmEventCallback(java.util.concurrent.Executor, android.media.MediaPlayer2.DrmEventCallback);
method public java.lang.Object setNextDataSource(android.media.DataSourceDesc);
method public java.lang.Object setNextDataSources(java.util.List<android.media.DataSourceDesc>);
method public java.lang.Object setPlaybackParams(android.media.PlaybackParams);
@@ -25518,6 +25558,33 @@
field public static final int SEEK_PREVIOUS_SYNC = 0; // 0x0
}
+ public static class MediaPlayer2.DrmEventCallback {
+ ctor public MediaPlayer2.DrmEventCallback();
+ method public void onDrmConfig(android.media.MediaPlayer2, android.media.DataSourceDesc, android.media.MediaDrm);
+ method public android.media.MediaPlayer2.DrmPreparationInfo onDrmInfo(android.media.MediaPlayer2, android.media.DataSourceDesc, android.media.MediaPlayer2.DrmInfo);
+ method public byte[] onDrmKeyRequest(android.media.MediaPlayer2, android.media.DataSourceDesc, android.media.MediaDrm.KeyRequest);
+ method public void onDrmPrepared(android.media.MediaPlayer2, android.media.DataSourceDesc, int, byte[]);
+ }
+
+ public static final class MediaPlayer2.DrmInfo {
+ method public java.util.Map<java.util.UUID, byte[]> getPssh();
+ method public java.util.List<java.util.UUID> getSupportedSchemes();
+ }
+
+ public static final class MediaPlayer2.DrmPreparationInfo {
+ }
+
+ public static final class MediaPlayer2.DrmPreparationInfo.Builder {
+ ctor public MediaPlayer2.DrmPreparationInfo.Builder();
+ method public android.media.MediaPlayer2.DrmPreparationInfo build();
+ method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setInitData(byte[]);
+ method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setKeySetId(byte[]);
+ method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setKeyType(int);
+ method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setMimeType(java.lang.String);
+ method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setOptionalParameters(java.util.Map<java.lang.String, java.lang.String>);
+ method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setUuid(java.util.UUID);
+ }
+
public static class MediaPlayer2.EventCallback {
ctor public MediaPlayer2.EventCallback();
method public void onCallCompleted(android.media.MediaPlayer2, android.media.DataSourceDesc, int, int);
@@ -25545,6 +25612,10 @@
field public static final java.lang.String WIDTH = "android.media.mediaplayer.width";
}
+ public static final class MediaPlayer2.NoDrmSchemeException extends android.media.MediaDrmException {
+ ctor public MediaPlayer2.NoDrmSchemeException(java.lang.String);
+ }
+
public static class MediaPlayer2.TrackInfo {
method public android.media.MediaFormat getFormat();
method public java.lang.String getLanguage();
@@ -25636,6 +25707,7 @@
field public static final int VOICE_CALL = 4; // 0x4
field public static final int VOICE_COMMUNICATION = 7; // 0x7
field public static final int VOICE_DOWNLINK = 3; // 0x3
+ field public static final int VOICE_PERFORMANCE = 10; // 0xa
field public static final int VOICE_RECOGNITION = 6; // 0x6
field public static final int VOICE_UPLINK = 2; // 0x2
}
@@ -29725,8 +29797,10 @@
method public java.lang.String getMacAddress();
method public int getNetworkId();
method public int getRssi();
+ method public int getRxLinkSpeedMbps();
method public java.lang.String getSSID();
method public android.net.wifi.SupplicantState getSupplicantState();
+ method public int getTxLinkSpeedMbps();
method public void writeToParcel(android.os.Parcel, int);
field public static final java.lang.String FREQUENCY_UNITS = "MHz";
field public static final java.lang.String LINK_SPEED_UNITS = "Mbps";
@@ -48182,6 +48256,7 @@
field public int data;
field public int density;
field public int resourceId;
+ field public int sourceStyleResourceId;
field public java.lang.CharSequence string;
field public int type;
}
@@ -52943,19 +53018,8 @@
ctor public InspectionCompanion.UninitializedPropertyMapException();
}
- public final class IntEnumMapping {
- method public java.lang.String nameOf(int);
- }
-
- public static final class IntEnumMapping.Builder {
- ctor public IntEnumMapping.Builder();
- method public android.view.inspector.IntEnumMapping.Builder addValue(java.lang.String, int);
- method public android.view.inspector.IntEnumMapping build();
- method public void clear();
- }
-
public final class IntFlagMapping {
- method public java.lang.String[] namesOf(int);
+ method public java.util.Set<java.lang.String> get(int);
}
public static final class IntFlagMapping.Builder {
@@ -52963,7 +53027,6 @@
method public android.view.inspector.IntFlagMapping.Builder addFlag(java.lang.String, int);
method public android.view.inspector.IntFlagMapping.Builder addFlag(java.lang.String, int, int);
method public android.view.inspector.IntFlagMapping build();
- method public void clear();
}
public abstract interface PropertyMapper {
@@ -52975,7 +53038,7 @@
method public abstract int mapFloat(java.lang.String, int);
method public abstract int mapGravity(java.lang.String, int);
method public abstract int mapInt(java.lang.String, int);
- method public abstract int mapIntEnum(java.lang.String, int, android.view.inspector.IntEnumMapping);
+ method public abstract int mapIntEnum(java.lang.String, int, android.util.SparseArray<java.lang.String>);
method public abstract int mapIntFlag(java.lang.String, int, android.view.inspector.IntFlagMapping);
method public abstract int mapLong(java.lang.String, int);
method public abstract int mapObject(java.lang.String, int);
diff --git a/api/system-current.txt b/api/system-current.txt
index 78f3471..acbc2a7 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -94,7 +94,6 @@
field public static final java.lang.String MANAGE_CONTENT_CAPTURE = "android.permission.MANAGE_CONTENT_CAPTURE";
field public static final java.lang.String MANAGE_CONTENT_SUGGESTIONS = "android.permission.MANAGE_CONTENT_SUGGESTIONS";
field public static final java.lang.String MANAGE_DEBUGGING = "android.permission.MANAGE_DEBUGGING";
- field public static final java.lang.String MANAGE_DEVICE_ADMINS = "android.permission.MANAGE_DEVICE_ADMINS";
field public static final java.lang.String MANAGE_IPSEC_TUNNELS = "android.permission.MANAGE_IPSEC_TUNNELS";
field public static final java.lang.String MANAGE_ROLE_HOLDERS = "android.permission.MANAGE_ROLE_HOLDERS";
field public static final java.lang.String MANAGE_ROLLBACKS = "android.permission.MANAGE_ROLLBACKS";
@@ -151,6 +150,7 @@
field public static final java.lang.String REGISTER_CALL_PROVIDER = "android.permission.REGISTER_CALL_PROVIDER";
field public static final java.lang.String REGISTER_CONNECTION_MANAGER = "android.permission.REGISTER_CONNECTION_MANAGER";
field public static final java.lang.String REGISTER_SIM_SUBSCRIPTION = "android.permission.REGISTER_SIM_SUBSCRIPTION";
+ field public static final java.lang.String REMOTE_DISPLAY_PROVIDER = "android.permission.REMOTE_DISPLAY_PROVIDER";
field public static final java.lang.String REMOVE_DRM_CERTIFICATES = "android.permission.REMOVE_DRM_CERTIFICATES";
field public static final java.lang.String REMOVE_TASKS = "android.permission.REMOVE_TASKS";
field public static final java.lang.String RESET_PASSWORD = "android.permission.RESET_PASSWORD";
@@ -3301,6 +3301,7 @@
}
public final class MediaRecorder.AudioSource {
+ field public static final int ECHO_REFERENCE = 1997; // 0x7cd
field public static final int HOTWORD = 1999; // 0x7cf
field public static final int RADIO_TUNER = 1998; // 0x7ce
}
@@ -3908,24 +3909,24 @@
package android.net.wifi {
- public abstract class DppStatusCallback {
- ctor public DppStatusCallback();
+ public abstract class EasyConnectStatusCallback {
+ ctor public EasyConnectStatusCallback();
method public abstract void onConfiguratorSuccess(int);
method public abstract void onEnrolleeSuccess(int);
method public abstract void onFailure(int);
method public abstract void onProgress(int);
- field public static final int DPP_EVENT_FAILURE = -7; // 0xfffffff9
- field public static final int DPP_EVENT_FAILURE_AUTHENTICATION = -2; // 0xfffffffe
- field public static final int DPP_EVENT_FAILURE_BUSY = -5; // 0xfffffffb
- field public static final int DPP_EVENT_FAILURE_CONFIGURATION = -4; // 0xfffffffc
- field public static final int DPP_EVENT_FAILURE_INVALID_NETWORK = -9; // 0xfffffff7
- field public static final int DPP_EVENT_FAILURE_INVALID_URI = -1; // 0xffffffff
- field public static final int DPP_EVENT_FAILURE_NOT_COMPATIBLE = -3; // 0xfffffffd
- field public static final int DPP_EVENT_FAILURE_NOT_SUPPORTED = -8; // 0xfffffff8
- field public static final int DPP_EVENT_FAILURE_TIMEOUT = -6; // 0xfffffffa
- field public static final int DPP_EVENT_PROGRESS_AUTHENTICATION_SUCCESS = 0; // 0x0
- field public static final int DPP_EVENT_PROGRESS_RESPONSE_PENDING = 1; // 0x1
- field public static final int DPP_EVENT_SUCCESS_CONFIGURATION_SENT = 0; // 0x0
+ field public static final int EASY_CONNECT_EVENT_FAILURE = -7; // 0xfffffff9
+ field public static final int EASY_CONNECT_EVENT_FAILURE_AUTHENTICATION = -2; // 0xfffffffe
+ field public static final int EASY_CONNECT_EVENT_FAILURE_BUSY = -5; // 0xfffffffb
+ field public static final int EASY_CONNECT_EVENT_FAILURE_CONFIGURATION = -4; // 0xfffffffc
+ field public static final int EASY_CONNECT_EVENT_FAILURE_INVALID_NETWORK = -9; // 0xfffffff7
+ field public static final int EASY_CONNECT_EVENT_FAILURE_INVALID_URI = -1; // 0xffffffff
+ field public static final int EASY_CONNECT_EVENT_FAILURE_NOT_COMPATIBLE = -3; // 0xfffffffd
+ field public static final int EASY_CONNECT_EVENT_FAILURE_NOT_SUPPORTED = -8; // 0xfffffff8
+ field public static final int EASY_CONNECT_EVENT_FAILURE_TIMEOUT = -6; // 0xfffffffa
+ field public static final int EASY_CONNECT_EVENT_PROGRESS_AUTHENTICATION_SUCCESS = 0; // 0x0
+ field public static final int EASY_CONNECT_EVENT_PROGRESS_RESPONSE_PENDING = 1; // 0x1
+ field public static final int EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_SENT = 0; // 0x0
}
public deprecated class RttManager {
@@ -4156,10 +4157,10 @@
method public void save(android.net.wifi.WifiConfiguration, android.net.wifi.WifiManager.ActionListener);
method public void setDeviceMobilityState(int);
method public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
- method public void startDppAsConfiguratorInitiator(java.lang.String, int, int, android.os.Handler, android.net.wifi.DppStatusCallback);
- method public void startDppAsEnrolleeInitiator(java.lang.String, android.os.Handler, android.net.wifi.DppStatusCallback);
+ 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 stopDppSession();
+ method public void stopEasyConnectSession();
method public void unregisterNetworkRequestMatchCallback(android.net.wifi.WifiManager.NetworkRequestMatchCallback);
field public static final int CHANGE_REASON_ADDED = 0; // 0x0
field public static final int CHANGE_REASON_CONFIG_CHANGE = 2; // 0x2
@@ -4169,8 +4170,8 @@
field public static final int DEVICE_MOBILITY_STATE_LOW_MVMT = 2; // 0x2
field public static final int DEVICE_MOBILITY_STATE_STATIONARY = 3; // 0x3
field public static final int DEVICE_MOBILITY_STATE_UNKNOWN = 0; // 0x0
- field public static final int DPP_NETWORK_ROLE_AP = 1; // 0x1
- field public static final int DPP_NETWORK_ROLE_STA = 0; // 0x0
+ field public static final int EASY_CONNECT_NETWORK_ROLE_AP = 1; // 0x1
+ field public static final int EASY_CONNECT_NETWORK_ROLE_STA = 0; // 0x0
field public static final java.lang.String EXTRA_CHANGE_REASON = "changeReason";
field public static final java.lang.String EXTRA_MULTIPLE_NETWORKS_CHANGED = "multipleChanges";
field public static final java.lang.String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state";
@@ -4445,6 +4446,10 @@
method public abstract java.lang.Object onTransactStarted(android.os.IBinder, int);
}
+ public static class Build.VERSION {
+ field public static final java.lang.String PREVIEW_SDK_FINGERPRINT;
+ }
+
public final class ConfigUpdate {
field public static final java.lang.String ACTION_UPDATE_CARRIER_ID_DB = "android.os.action.UPDATE_CARRIER_ID_DB";
field public static final java.lang.String ACTION_UPDATE_CARRIER_PROVISIONING_URLS = "android.intent.action.UPDATE_CARRIER_PROVISIONING_URLS";
@@ -4863,6 +4868,8 @@
method public final android.os.IBinder onBind(android.content.Intent);
method public abstract int onCountPermissionApps(java.util.List<java.lang.String>, boolean, boolean);
method public abstract java.util.List<android.permission.RuntimePermissionPresentationInfo> onGetAppPermissions(java.lang.String);
+ method public abstract void onGetRuntimePermissionsBackup(android.os.UserHandle, java.io.OutputStream);
+ method public abstract java.util.List<android.permission.RuntimePermissionUsageInfo> onPermissionUsageResult(boolean, long);
method public abstract void onRevokeRuntimePermission(java.lang.String, java.lang.String);
method public abstract java.util.Map<java.lang.String, java.util.List<java.lang.String>> onRevokeRuntimePermissions(java.util.Map<java.lang.String, java.util.List<java.lang.String>>, boolean, int, java.lang.String);
field public static final java.lang.String SERVICE_INTERFACE = "android.permission.PermissionControllerService";
@@ -4891,11 +4898,12 @@
public final class RuntimePermissionUsageInfo implements android.os.Parcelable {
ctor public RuntimePermissionUsageInfo(java.lang.CharSequence, int);
method public int describeContents();
- method public java.lang.CharSequence getName();
method public int getAppAccessCount();
+ method public java.lang.CharSequence getName();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.permission.RuntimePermissionUsageInfo> CREATOR;
}
+
}
package android.permissionpresenterservice {
@@ -7251,7 +7259,6 @@
method public void callSessionInviteParticipantsRequestDelivered();
method public void callSessionInviteParticipantsRequestFailed(android.telephony.ims.ImsReasonInfo);
method public void callSessionMayHandover(int, int);
- method public void callSessionRttAudioIndicatorChanged(android.telephony.ims.ImsStreamMediaProfile);
method public void callSessionMergeComplete(android.telephony.ims.stub.ImsCallSessionImplBase);
method public void callSessionMergeFailed(android.telephony.ims.ImsReasonInfo);
method public void callSessionMergeStarted(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile);
@@ -7262,6 +7269,7 @@
method public void callSessionResumeFailed(android.telephony.ims.ImsReasonInfo);
method public void callSessionResumeReceived(android.telephony.ims.ImsCallProfile);
method public void callSessionResumed(android.telephony.ims.ImsCallProfile);
+ method public void callSessionRttAudioIndicatorChanged(android.telephony.ims.ImsStreamMediaProfile);
method public void callSessionRttMessageReceived(java.lang.String);
method public void callSessionRttModifyRequestReceived(android.telephony.ims.ImsCallProfile);
method public void callSessionRttModifyResponseReceived(int);
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 4beb699..5a7ec8b 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -1,3 +1,11 @@
+package android {
+
+ public static final class Manifest.permission {
+ field public static final java.lang.String MANAGE_DEVICE_ADMINS = "android.permission.MANAGE_DEVICE_ADMINS";
+ }
+
+}
+
package android.app {
public class Notification implements android.os.Parcelable {
diff --git a/api/test-current.txt b/api/test-current.txt
index a421da4..6ddb341 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -501,10 +501,19 @@
package android.graphics {
+ public final class Bitmap implements android.os.Parcelable {
+ method public void eraseColor(long);
+ }
+
public final class ImageDecoder implements java.lang.AutoCloseable {
method public static android.graphics.ImageDecoder.Source createSource(android.content.res.Resources, java.io.InputStream, int);
}
+ public class Paint {
+ method public void setColor(long);
+ method public void setShadowLayer(float, float, float, long);
+ }
+
}
package android.graphics.drawable {
@@ -624,6 +633,7 @@
method public void resetCarrierFrequencyHz();
method public deprecated void resetCarrierPhase();
method public deprecated void resetCarrierPhaseUncertainty();
+ method public void resetCodeType();
method public void resetSnrInDb();
method public void set(android.location.GnssMeasurement);
method public void setAccumulatedDeltaRangeMeters(double);
@@ -635,6 +645,7 @@
method public deprecated void setCarrierPhase(double);
method public deprecated void setCarrierPhaseUncertainty(double);
method public void setCn0DbHz(double);
+ method public void setCodeType(int);
method public void setConstellationType(int);
method public void setMultipathIndicator(int);
method public void setPseudorangeRateMetersPerSecond(double);
@@ -939,6 +950,11 @@
field public static final android.os.Parcelable.Creator<android.os.IncidentReportArgs> CREATOR;
}
+ public final class MessageQueue {
+ method public int postSyncBarrier();
+ method public void removeSyncBarrier(int);
+ }
+
public final class NativeHandle implements java.io.Closeable {
ctor public NativeHandle();
ctor public NativeHandle(java.io.FileDescriptor, boolean);
@@ -951,11 +967,6 @@
method public boolean hasSingleFileDescriptor();
}
- public final class MessageQueue {
- method public int postSyncBarrier();
- method public void removeSyncBarrier(int);
- }
-
public final class PowerManager {
method public int getPowerSaveMode();
method public boolean setDynamicPowerSavings(boolean, int);
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 0fa7cff..7e2df27 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -25,6 +25,8 @@
import "frameworks/base/core/proto/android/app/settings_enums.proto";
import "frameworks/base/core/proto/android/app/job/enums.proto";
import "frameworks/base/core/proto/android/bluetooth/enums.proto";
+import "frameworks/base/core/proto/android/bluetooth/hci/enums.proto";
+import "frameworks/base/core/proto/android/bluetooth/hfp/enums.proto";
import "frameworks/base/core/proto/android/net/networkcapabilities.proto";
import "frameworks/base/core/proto/android/os/enums.proto";
import "frameworks/base/core/proto/android/server/connectivity/data_stall_event.proto";
@@ -182,6 +184,10 @@
DataStallEvent data_stall_event = 121;
RescuePartyResetReported rescue_party_reset_reported = 122;
SignedConfigReported signed_config_reported = 123;
+ GnssNiEventReported gnss_ni_event_reported = 124;
+ BluetoothLinkLayerConnectionEvent bluetooth_link_layer_connection_event = 125;
+ BluetoothAclConnectionStateChanged bluetooth_acl_connection_state_changed = 126;
+ BluetoothScoConnectionStateChanged bluetooth_sco_connection_state_changed = 127;
}
// Pulled events will start at field 10000.
@@ -1297,10 +1303,12 @@
}
/**
- * Logs when a Bluetooth device connects and disconnects.
+ * Logs when profiles on a Bluetooth device connects and disconnects.
*
* Logged from:
- * packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterProperties.java
+ * packages/apps/Bluetooth/src/com/android/bluetooth/btservice/RemoteDevices.java
+ *
+ * Next Tag: 5
*/
message BluetoothConnectionStateChanged {
// The state of the connection.
@@ -1309,13 +1317,152 @@
// An identifier that can be used to match connect and disconnect events.
// Currently is last two bytes of a hash of a device level ID and
// the mac address of the bluetooth device that is connected.
- optional int32 obfuscated_id = 2;
+ // Deprecated: use obfuscated_id instead, this one is always 0 for Q+
+ optional int32 OBSOLETE_obfuscated_id = 2 [deprecated = true];
// The profile that is connected. Eg. GATT, A2DP, HEADSET.
// From android.bluetooth.BluetoothAdapter.java
+ // Default: 0 when not used
optional int32 bt_profile = 3;
+ // An identifier that can be used to match events for this device.
+ // Currently, this is a salted hash of the MAC address of this Bluetooth device.
+ // Salt: Randomly generated 256 bit value
+ // Hash algorithm: HMAC-SHA256
+ // Size: 32 byte
+ // Default: null or empty if the device identifier is not known
+ optional bytes obfuscated_id = 4 [(android.os.statsd.log_mode) = MODE_BYTES];
}
/**
+ * Logs when a Bluetooth device connects and disconnects over ACL
+ *
+ * Logged from:
+ * packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterProperties.java
+ *
+ * Next Tag: 3
+ */
+message BluetoothAclConnectionStateChanged {
+ // An identifier that can be used to match events for this device.
+ // Currently, this is a salted hash of the MAC address of this Bluetooth device.
+ // Salt: Randomly generated 256 bit value
+ // Hash algorithm: HMAC-SHA256
+ // Size: 32 byte
+ // Default: null or empty if the device identifier is not known
+ optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
+ // The state of the connection.
+ // Eg: CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED.
+ optional android.bluetooth.ConnectionStateEnum state = 2;
+}
+
+/**
+ * Logs when a Bluetooth device connects and disconnects over SCO
+ *
+ * Logged from:
+ * packages/apps/Bluetooth/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
+ * packages/apps/Bluetooth/src/com/android/bluetooth/hfp/HeadsetClientStateMachine.java
+ *
+ * Next Tag: 4
+ */
+message BluetoothScoConnectionStateChanged {
+ // An identifier that can be used to match events for this device.
+ // Currently, this is a salted hash of the MAC address of this Bluetooth device.
+ // Salt: Randomly generated 256 bit value
+ // Hash algorithm: HMAC-SHA256
+ // Size: 32 byte
+ // Default: null or empty if the device identifier is not known
+ optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
+ // The state of the connection.
+ // Eg: CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED.
+ optional android.bluetooth.ConnectionStateEnum state = 2;
+ // Codec used for this SCO connection
+ // Default: UNKNOWN
+ optional android.bluetooth.hfp.ScoCodec codec = 3;
+}
+
+// Logs when there is an event affecting Bluetooth device's link layer connection.
+// - This event is triggered when there is a related HCI command or event
+// - Users of this metrics can deduce Bluetooth device's connection state from these events
+// - HCI commands are logged before the command is sent, after receiving command status, and after
+// receiving command complete
+// - HCI events are logged when they arrive
+//
+// Low level log from system/bt
+//
+// Bluetooth classic commands:
+// - CMD_CREATE_CONNECTION
+// - CMD_DISCONNECT
+// - CMD_CREATE_CONNECTION_CANCEL
+// - CMD_ACCEPT_CONNECTION_REQUEST
+// - CMD_REJECT_CONNECTION_REQUEST
+// - CMD_SETUP_ESCO_CONNECTION
+// - CMD_ACCEPT_ESCO_CONNECTION
+// - CMD_REJECT_ESCO_CONNECTION
+// - CMD_ENH_SETUP_ESCO_CONNECTION
+// - CMD_ENH_ACCEPT_ESCO_CONNECTION
+//
+// Bluetooth low energy commands:
+// - CMD_BLE_CREATE_LL_CONN [Only logged on error or when initiator filter policy is 0x00]
+// - CMD_BLE_CREATE_CONN_CANCEL [Only logged when there is an error]
+// - CMD_BLE_EXTENDED_CREATE_CONNECTION [Only logged on error or when initiator filter policy is 0x00]
+// - CMD_BLE_CLEAR_WHITE_LIST
+// - CMD_BLE_ADD_WHITE_LIST
+// - CMD_BLE_REMOVE_WHITE_LIST
+//
+// Bluetooth classic events:
+// - EVT_CONNECTION_COMP
+// - EVT_CONNECTION_REQUEST
+// - EVT_DISCONNECTION_COMP
+// - EVT_ESCO_CONNECTION_COMP
+// - EVT_ESCO_CONNECTION_CHANGED
+//
+// Bluetooth low energy meta events:
+// - BLE_EVT_CONN_COMPLETE_EVT
+// - BLE_EVT_ENHANCED_CONN_COMPLETE_EVT
+//
+// Next tag: 10
+message BluetoothLinkLayerConnectionEvent {
+ // An identifier that can be used to match events for this device.
+ // Currently, this is a salted hash of the MAC address of this Bluetooth device.
+ // Salt: Randomly generated 256 bit value
+ // Hash algorithm: HMAC-SHA256
+ // Size: 32 byte
+ // Default: null or empty if the device identifier is not known
+ optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
+ // Connection handle of this connection if available
+ // Range: 0x0000 - 0x0EFF (12 bits)
+ // Default: 0xFFFF if the handle is unknown
+ optional int32 connection_handle = 2;
+ // Direction of the link
+ // Default: DIRECTION_UNKNOWN
+ optional android.bluetooth.DirectionEnum direction = 3;
+ // Type of this link
+ // Default: LINK_TYPE_UNKNOWN
+ optional android.bluetooth.LinkTypeEnum type = 4;
+
+ // Reason metadata for this link layer connection event, rules for interpretation:
+ // 1. If hci_cmd is set and valid, hci_event can be either EVT_COMMAND_STATUS or
+ // EVT_COMMAND_COMPLETE, ignore hci_ble_event in this case
+ // 2. If hci_event is set to EVT_BLE_META, look at hci_ble_event; otherwise, if hci_event is
+ // set and valid, ignore hci_ble_event
+
+ // HCI command associated with this event
+ // Default: CMD_UNKNOWN
+ optional android.bluetooth.hci.CommandEnum hci_cmd = 5;
+ // HCI event associated with this event
+ // Default: EVT_UNKNOWN
+ optional android.bluetooth.hci.EventEnum hci_event = 6;
+ // HCI BLE meta event associated with this event
+ // Default: BLE_EVT_UNKNOWN
+ optional android.bluetooth.hci.BleMetaEventEnum hci_ble_event = 7;
+ // HCI command status code if this is triggerred by hci_cmd
+ // Default: STATUS_UNKNOWN
+ optional android.bluetooth.hci.StatusEnum cmd_status = 8;
+ // HCI reason code associated with this event
+ // Default: STATUS_UNKNOWN
+ optional android.bluetooth.hci.StatusEnum reason_code = 9;
+}
+
+
+/**
* Logs when something is plugged into or removed from the USB-C connector.
*
* Logged from:
@@ -3902,3 +4049,63 @@
// Which key was used to verify the config.
optional Key verified_with = 5;
}
+
+/*
+ * Logs GNSS Network-Initiated (NI) location events.
+ *
+ * Logged from:
+ * frameworks/base/services/core/java/com/android/server/location/GnssLocationProvider.java
+ */
+message GnssNiEventReported {
+ // The type of GnssNiEvent.
+ enum EventType {
+ UNKNOWN = 0;
+ NI_REQUEST = 1;
+ NI_RESPONSE = 2;
+ }
+ optional EventType event_type = 1;
+
+ // An ID generated by HAL to associate NI notifications and UI responses.
+ optional int32 notification_id = 2;
+
+ // A type which distinguishes different categories of NI request, such as VOICE, UMTS_SUPL etc.
+ optional int32 ni_type = 3;
+
+ // NI requires notification.
+ optional bool need_notify = 4;
+
+ // NI requires verification.
+ optional bool need_verify = 5;
+
+ // NI requires privacy override, no notification/minimal trace.
+ optional bool privacy_override = 6;
+
+ // Timeout period to wait for user response. Set to 0 for no timeout limit. Specified in
+ // seconds.
+ optional int32 timeout = 7;
+
+ // Default response when timeout.
+ optional int32 default_response = 8;
+
+ // String representing the requester of the network inititated location request.
+ optional string requestor_id = 9;
+
+ // Notification message text string representing the service(for eg. SUPL-service) who sent the
+ // network initiated location request.
+ optional string text = 10;
+
+ // requestorId decoding scheme.
+ optional int32 requestor_id_encoding = 11;
+
+ // Notification message text decoding scheme.
+ optional int32 text_encoding = 12;
+
+ // True if SUPL ES is enabled.
+ optional bool is_supl_es_enabled = 13;
+
+ // True if GNSS location is enabled.
+ optional bool is_location_enabled = 14;
+
+ // GNSS NI responses which define the response in NI structures.
+ optional int32 user_response = 15;
+}
diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt
index 4d3c5d1..5392a3c 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -1492,7 +1492,6 @@
Landroid/test/AndroidTestCase;->getTestContext()Landroid/content/Context;
Landroid/test/AndroidTestCase;->setTestContext(Landroid/content/Context;)V
Landroid/test/InstrumentationTestCase;->runMethod(Ljava/lang/reflect/Method;I)V
-Landroid/test/RepetitiveTest;->numIterations()I
Landroid/util/Singleton;-><init>()V
Landroid/util/XmlPullAttributes;-><init>(Lorg/xmlpull/v1/XmlPullParser;)V
Landroid/util/XmlPullAttributes;->mParser:Lorg/xmlpull/v1/XmlPullParser;
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 98c5a0fb..d374f1c 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -17,6 +17,7 @@
package android.app;
import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
+import static android.os.Process.myUid;
import static java.lang.Character.MIN_VALUE;
@@ -1025,7 +1026,7 @@
*/
@Nullable private ContentCaptureManager getContentCaptureManager() {
// ContextCapture disabled for system apps
- if (getApplicationInfo().isSystemApp()) return null;
+ if (!UserHandle.isApp(myUid())) return null;
if (mContentCaptureManager == null) {
mContentCaptureManager = getSystemService(ContentCaptureManager.class);
}
@@ -1048,9 +1049,8 @@
private void notifyContentCaptureManagerIfNeeded(@ContentCaptureNotificationType int type) {
final ContentCaptureManager cm = getContentCaptureManager();
- if (cm == null) {
- return;
- }
+ if (cm == null) return;
+
switch (type) {
case CONTENT_CAPTURE_START:
//TODO(b/111276913): decide whether the InteractionSessionId should be
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index d423260..e0b8d78 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -3705,11 +3705,16 @@
* Returns whether switching to provided user was successful.
*
* @param user the user to switch to.
+ *
+ * @throws IllegalArgumentException if the user is null.
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.MANAGE_USERS)
- public boolean switchUser(UserHandle user) {
+ public boolean switchUser(@NonNull UserHandle user) {
+ if (user == null) {
+ throw new IllegalArgumentException("UserHandle cannot be null.");
+ }
return switchUser(user.getIdentifier());
}
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 1f01e26..5cac048 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -320,4 +320,10 @@
/** Remove pending backup for the given userId. */
public abstract void clearPendingBackup(int userId);
+
+ /**
+ * When power button is very long pressed, call this interface to do some pre-shutdown work
+ * like persisting database etc.
+ */
+ public abstract void prepareForPossibleShutdown();
}
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 57132a7..ab8f234 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -16,6 +16,10 @@
package android.app;
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL;
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
+
import android.annotation.NonNull;
import android.annotation.UnsupportedAppUsage;
import android.app.ActivityManager.StackInfo;
@@ -32,7 +36,6 @@
import android.view.IWindowManager;
import android.view.InputDevice;
import android.view.MotionEvent;
-import android.view.Surface;
import android.view.SurfaceControl;
import android.view.SurfaceHolder;
import android.view.SurfaceSession;
@@ -82,7 +85,6 @@
private boolean mOpened; // Protected by mGuard.
private final SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction();
- private Surface mTmpSurface = new Surface();
/** The ActivityView is only allowed to contain one task. */
private final boolean mSingleTaskInstance;
@@ -319,20 +321,20 @@
private class SurfaceCallback implements SurfaceHolder.Callback {
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
- mTmpSurface = new Surface();
if (mVirtualDisplay == null) {
initVirtualDisplay(new SurfaceSession());
if (mVirtualDisplay != null && mActivityViewCallback != null) {
mActivityViewCallback.onActivityViewReady(ActivityView.this);
}
} else {
- // TODO (b/119209373): DisplayManager determines if a VirtualDisplay is on by
- // whether it has a surface. Setting a fake surface here so DisplayManager will
- // consider this display on.
- mVirtualDisplay.setSurface(mTmpSurface);
mTmpTransaction.reparent(mRootSurfaceControl,
mSurfaceView.getSurfaceControl().getHandle()).apply();
}
+
+ if (mVirtualDisplay != null) {
+ mVirtualDisplay.setDisplayState(true);
+ }
+
updateLocation();
}
@@ -346,10 +348,8 @@
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
- mTmpSurface.release();
- mTmpSurface = null;
if (mVirtualDisplay != null) {
- mVirtualDisplay.setSurface(null);
+ mVirtualDisplay.setDisplayState(false);
}
cleanTapExcludeRegion();
}
@@ -370,15 +370,11 @@
final int height = mSurfaceView.getHeight();
final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
- // TODO (b/119209373): DisplayManager determines if a VirtualDisplay is on by
- // whether it has a surface. Setting a fake surface here so DisplayManager will consider
- // this display on.
mVirtualDisplay = displayManager.createVirtualDisplay(
- DISPLAY_NAME + "@" + System.identityHashCode(this),
- width, height, getBaseDisplayDensity(), mTmpSurface,
- DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC
- | DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
- | DisplayManager.VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL);
+ DISPLAY_NAME + "@" + System.identityHashCode(this), width, height,
+ getBaseDisplayDensity(), null,
+ VIRTUAL_DISPLAY_FLAG_PUBLIC | VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
+ | VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL);
if (mVirtualDisplay == null) {
Log.e(TAG, "Failed to initialize ActivityView");
return;
@@ -443,11 +439,6 @@
displayReleased = false;
}
- if (mTmpSurface != null) {
- mTmpSurface.release();
- mTmpSurface = null;
- }
-
if (displayReleased && mActivityViewCallback != null) {
mActivityViewCallback.onActivityViewDestroyed(this);
}
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 163be8e..199c133 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -65,9 +65,9 @@
boolean areNotificationsEnabled(String pkg);
int getPackageImportance(String pkg);
- void setAppOverlaysAllowed(String pkg, int uid, boolean allowed);
- boolean areAppOverlaysAllowed(String pkg);
- boolean areAppOverlaysAllowedForPackage(String pkg, int uid);
+ void setBubblesAllowed(String pkg, int uid, boolean allowed);
+ boolean areBubblesAllowed(String pkg);
+ boolean areBubblesAllowedForPackage(String pkg, int uid);
void createNotificationChannelGroups(String pkg, in ParceledListSlice channelGroupList);
void createNotificationChannels(String pkg, in ParceledListSlice channelsList);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index b657a91..72819cb 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1276,7 +1276,7 @@
private String mShortcutId;
private CharSequence mSettingsText;
- private PendingIntent mAppOverlayIntent;
+ private BubbleMetadata mBubbleMetadata;
/** @hide */
@IntDef(prefix = { "GROUP_ALERT_" }, value = {
@@ -2278,7 +2278,7 @@
mGroupAlertBehavior = parcel.readInt();
if (parcel.readInt() != 0) {
- mAppOverlayIntent = PendingIntent.CREATOR.createFromParcel(parcel);
+ mBubbleMetadata = BubbleMetadata.CREATOR.createFromParcel(parcel);
}
mAllowSystemGeneratedContextualActions = parcel.readBoolean();
@@ -2396,7 +2396,7 @@
that.mBadgeIcon = this.mBadgeIcon;
that.mSettingsText = this.mSettingsText;
that.mGroupAlertBehavior = this.mGroupAlertBehavior;
- that.mAppOverlayIntent = this.mAppOverlayIntent;
+ that.mBubbleMetadata = this.mBubbleMetadata;
that.mAllowSystemGeneratedContextualActions = this.mAllowSystemGeneratedContextualActions;
if (!heavy) {
@@ -2719,9 +2719,9 @@
parcel.writeInt(mGroupAlertBehavior);
- if (mAppOverlayIntent != null) {
+ if (mBubbleMetadata != null) {
parcel.writeInt(1);
- mAppOverlayIntent.writeToParcel(parcel, 0);
+ mBubbleMetadata.writeToParcel(parcel, 0);
} else {
parcel.writeInt(0);
}
@@ -3141,11 +3141,11 @@
}
/**
- * Returns the intent that will be used to display app content in a floating window over the
- * existing foreground activity.
+ * Returns the bubble metadata that will be used to display app content in a floating window
+ * over the existing foreground activity.
*/
- public PendingIntent getAppOverlayIntent() {
- return mAppOverlayIntent;
+ public BubbleMetadata getBubbleMetadata() {
+ return mBubbleMetadata;
}
/**
@@ -3508,19 +3508,18 @@
}
/**
- * Sets the intent that will be used to display app content in a floating window
- * over the existing foreground activity.
+ * Sets the {@link BubbleMetadata} that will be used to display app content in a floating
+ * window over the existing foreground activity.
*
- * <p>This intent will be ignored unless this notification is posted to a channel that
- * allows {@link NotificationChannel#canOverlayApps() app overlays}.</p>
+ * <p>This data will be ignored unless the notification is posted to a channel that
+ * allows {@link NotificationChannel#canBubble() bubbles}.</p>
*
- * <p>Notifications with a valid and allowed app overlay intent will be displayed as
- * floating windows outside of the notification shade on unlocked devices. When a user
- * interacts with one of these windows, this app overlay intent will be invoked and
- * displayed.</p>
+ * <b>Notifications with a valid and allowed bubble metadata will display in collapsed state
+ * outside of the notification shade on unlocked devices. When a user interacts with the
+ * collapsed state, the bubble intent will be invoked and displayed.</b>
*/
- public Builder setAppOverlayIntent(PendingIntent intent) {
- mN.mAppOverlayIntent = intent;
+ public Builder setBubbleMetadata(BubbleMetadata data) {
+ mN.mBubbleMetadata = data;
return this;
}
@@ -8422,6 +8421,186 @@
}
}
+ /**
+ * Encapsulates the information needed to display a notification as a bubble.
+ *
+ * <p>A bubble is used to display app content in a floating window over the existing
+ * foreground activity. A bubble has a collapsed state represented by an icon,
+ * {@link BubbleMetadata.Builder#setIcon(Icon)} and an expanded state which is populated
+ * via {@link BubbleMetadata.Builder#setIntent(PendingIntent)}.</p>
+ *
+ * <b>Notifications with a valid and allowed bubble will display in collapsed state
+ * outside of the notification shade on unlocked devices. When a user interacts with the
+ * collapsed bubble, the bubble intent will be invoked and displayed.</b>
+ *
+ * @see Notification.Builder#setBubbleMetadata(BubbleMetadata)
+ */
+ public static final class BubbleMetadata implements Parcelable {
+
+ private PendingIntent mPendingIntent;
+ private CharSequence mTitle;
+ private Icon mIcon;
+ private int mDesiredHeight;
+
+ private BubbleMetadata(PendingIntent intent, CharSequence title, Icon icon, int height) {
+ mPendingIntent = intent;
+ mTitle = title;
+ mIcon = icon;
+ mDesiredHeight = height;
+ }
+
+ private BubbleMetadata(Parcel in) {
+ mPendingIntent = PendingIntent.CREATOR.createFromParcel(in);
+ mTitle = in.readCharSequence();
+ mIcon = Icon.CREATOR.createFromParcel(in);
+ mDesiredHeight = in.readInt();
+ }
+
+ /**
+ * @return the pending intent used to populate the floating window for this bubble.
+ */
+ public PendingIntent getIntent() {
+ return mPendingIntent;
+ }
+
+ /**
+ * @return the title that will appear along with the app content defined by
+ * {@link #getIntent()} for this bubble.
+ */
+ public CharSequence getTitle() {
+ return mTitle;
+ }
+
+ /**
+ * @return the icon that will be displayed for this bubble when it is collapsed.
+ */
+ public Icon getIcon() {
+ return mIcon;
+ }
+
+ /**
+ * @return the ideal height for the floating window that app content defined by
+ * {@link #getIntent()} for this bubble.
+ */
+ public int getDesiredHeight() {
+ return mDesiredHeight;
+ }
+
+ public static final Parcelable.Creator<BubbleMetadata> CREATOR =
+ new Parcelable.Creator<BubbleMetadata>() {
+
+ @Override
+ public BubbleMetadata createFromParcel(Parcel source) {
+ return new BubbleMetadata(source);
+ }
+
+ @Override
+ public BubbleMetadata[] newArray(int size) {
+ return new BubbleMetadata[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ mPendingIntent.writeToParcel(out, 0);
+ out.writeCharSequence(mTitle);
+ mIcon.writeToParcel(out, 0);
+ out.writeInt(mDesiredHeight);
+ }
+
+ /**
+ * Builder to construct a {@link BubbleMetadata} object.
+ */
+ public static class Builder {
+
+ private PendingIntent mPendingIntent;
+ private CharSequence mTitle;
+ private Icon mIcon;
+ private int mDesiredHeight;
+
+ /**
+ * Constructs a new builder object.
+ */
+ public Builder() {
+ }
+
+ /**
+ * Sets the intent that will be used when the bubble is expanded. This will display the
+ * app content in a floating window over the existing foreground activity.
+ */
+ public BubbleMetadata.Builder setIntent(PendingIntent intent) {
+ if (intent == null) {
+ throw new IllegalArgumentException("Bubble requires non-null pending intent");
+ }
+ mPendingIntent = intent;
+ return this;
+ }
+
+ /**
+ * Sets the title that will appear along with the app content for this bubble.
+ *
+ * <p>A title is required and should expect to fit on a single line and make sense when
+ * shown with the content defined by {@link #setIntent(PendingIntent)}.</p>
+ */
+ public BubbleMetadata.Builder setTitle(CharSequence title) {
+ if (TextUtils.isEmpty(title)) {
+ throw new IllegalArgumentException("Bubbles require non-null or empty title");
+ }
+ mTitle = title;
+ return this;
+ }
+
+ /**
+ * Sets the icon that will represent the bubble when it is collapsed.
+ *
+ * <p>An icon is required and should be representative of the content within the bubble.
+ * If your app produces multiple bubbles, the image should be unique for each of them.
+ * </p>
+ */
+ public BubbleMetadata.Builder setIcon(Icon icon) {
+ if (icon == null) {
+ throw new IllegalArgumentException("Bubbles require non-null icon");
+ }
+ mIcon = icon;
+ return this;
+ }
+
+ /**
+ * Sets the desired height for the app content defined by
+ * {@link #setIntent(PendingIntent)}, this height may not be respected if there is not
+ * enough space on the screen or if the provided height is too small to be useful.
+ */
+ public BubbleMetadata.Builder setDesiredHeight(int height) {
+ mDesiredHeight = Math.max(height, 0);
+ return this;
+ }
+
+ /**
+ * Creates the {@link BubbleMetadata} defined by this builder.
+ * <p>Will throw {@link IllegalStateException} if required fields have not been set
+ * on this builder.</p>
+ */
+ public BubbleMetadata build() {
+ if (mPendingIntent == null) {
+ throw new IllegalStateException("Must supply pending intent to bubble");
+ }
+ if (TextUtils.isEmpty(mTitle)) {
+ throw new IllegalStateException("Must supply a title for the bubble");
+ }
+ if (mIcon == null) {
+ throw new IllegalStateException("Must supply an icon for the bubble");
+ }
+ return new BubbleMetadata(mPendingIntent, mTitle, mIcon, mDesiredHeight);
+ }
+ }
+ }
+
+
// When adding a new Style subclass here, don't forget to update
// Builder.getNotificationStyleClass.
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 950e9aa..e95d62f 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -85,7 +85,7 @@
private static final String ATT_FG_SERVICE_SHOWN = "fgservice";
private static final String ATT_GROUP = "group";
private static final String ATT_BLOCKABLE_SYSTEM = "blockable_system";
- private static final String ATT_ALLOW_APP_OVERLAY = "app_overlay";
+ private static final String ATT_ALLOW_BUBBLE = "allow_bubble";
private static final String DELIMITER = ",";
/**
@@ -121,7 +121,7 @@
/**
* @hide
*/
- public static final int USER_LOCKED_ALLOW_APP_OVERLAY = 0x00000100;
+ public static final int USER_LOCKED_ALLOW_BUBBLE = 0x00000100;
/**
* @hide
@@ -134,7 +134,7 @@
USER_LOCKED_VIBRATION,
USER_LOCKED_SOUND,
USER_LOCKED_SHOW_BADGE,
- USER_LOCKED_ALLOW_APP_OVERLAY
+ USER_LOCKED_ALLOW_BUBBLE
};
private static final int DEFAULT_LIGHT_COLOR = 0;
@@ -144,7 +144,7 @@
NotificationManager.IMPORTANCE_UNSPECIFIED;
private static final boolean DEFAULT_DELETED = false;
private static final boolean DEFAULT_SHOW_BADGE = true;
- private static final boolean DEFAULT_ALLOW_APP_OVERLAY = true;
+ private static final boolean DEFAULT_ALLOW_BUBBLE = true;
@UnsupportedAppUsage
private final String mId;
@@ -168,7 +168,7 @@
private AudioAttributes mAudioAttributes = Notification.AUDIO_ATTRIBUTES_DEFAULT;
// If this is a blockable system notification channel.
private boolean mBlockableSystem = false;
- private boolean mAllowAppOverlay = DEFAULT_ALLOW_APP_OVERLAY;
+ private boolean mAllowBubbles = DEFAULT_ALLOW_BUBBLE;
private boolean mImportanceLockedByOEM;
/**
@@ -231,7 +231,7 @@
mAudioAttributes = in.readInt() > 0 ? AudioAttributes.CREATOR.createFromParcel(in) : null;
mLightColor = in.readInt();
mBlockableSystem = in.readBoolean();
- mAllowAppOverlay = in.readBoolean();
+ mAllowBubbles = in.readBoolean();
mImportanceLockedByOEM = in.readBoolean();
}
@@ -285,7 +285,7 @@
}
dest.writeInt(mLightColor);
dest.writeBoolean(mBlockableSystem);
- dest.writeBoolean(mAllowAppOverlay);
+ dest.writeBoolean(mAllowBubbles);
dest.writeBoolean(mImportanceLockedByOEM);
}
@@ -480,7 +480,7 @@
/**
* Sets whether notifications posted to this channel can appear outside of the notification
- * shade, floating over other apps' content.
+ * shade, floating over other apps' content as a bubble.
*
* <p>This value will be ignored for channels that aren't allowed to pop on screen (that is,
* channels whose {@link #getImportance() importance} is <
@@ -488,10 +488,10 @@
*
* <p>Only modifiable before the channel is submitted to
* * {@link NotificationManager#createNotificationChannel(NotificationChannel)}.</p>
- * @see Notification#getAppOverlayIntent()
+ * @see Notification#getBubbleMetadata()
*/
- public void setAllowAppOverlay(boolean allowAppOverlay) {
- mAllowAppOverlay = allowAppOverlay;
+ public void setAllowBubbles(boolean allowBubbles) {
+ mAllowBubbles = allowBubbles;
}
/**
@@ -610,16 +610,16 @@
* Returns whether notifications posted to this channel can display outside of the notification
* shade, in a floating window on top of other apps.
*/
- public boolean canOverlayApps() {
- return isAppOverlayAllowed() && getImportance() >= IMPORTANCE_HIGH;
+ public boolean canBubble() {
+ return isBubbleAllowed() && getImportance() >= IMPORTANCE_HIGH;
}
/**
- * Like {@link #canOverlayApps()}, but only checks the permission, not the importance.
+ * Like {@link #canBubble()}, but only checks the permission, not the importance.
* @hide
*/
- public boolean isAppOverlayAllowed() {
- return mAllowAppOverlay;
+ public boolean isBubbleAllowed() {
+ return mAllowBubbles;
}
/**
@@ -719,7 +719,7 @@
lockFields(safeInt(parser, ATT_USER_LOCKED, 0));
setFgServiceShown(safeBool(parser, ATT_FG_SERVICE_SHOWN, false));
setBlockableSystem(safeBool(parser, ATT_BLOCKABLE_SYSTEM, false));
- setAllowAppOverlay(safeBool(parser, ATT_ALLOW_APP_OVERLAY, DEFAULT_ALLOW_APP_OVERLAY));
+ setAllowBubbles(safeBool(parser, ATT_ALLOW_BUBBLE, DEFAULT_ALLOW_BUBBLE));
}
@Nullable
@@ -838,8 +838,8 @@
if (isBlockableSystem()) {
out.attribute(null, ATT_BLOCKABLE_SYSTEM, Boolean.toString(isBlockableSystem()));
}
- if (canOverlayApps() != DEFAULT_ALLOW_APP_OVERLAY) {
- out.attribute(null, ATT_ALLOW_APP_OVERLAY, Boolean.toString(canOverlayApps()));
+ if (canBubble() != DEFAULT_ALLOW_BUBBLE) {
+ out.attribute(null, ATT_ALLOW_BUBBLE, Boolean.toString(canBubble()));
}
out.endTag(null, TAG_CHANNEL);
@@ -883,7 +883,7 @@
record.put(ATT_DELETED, Boolean.toString(isDeleted()));
record.put(ATT_GROUP, getGroup());
record.put(ATT_BLOCKABLE_SYSTEM, isBlockableSystem());
- record.put(ATT_ALLOW_APP_OVERLAY, canOverlayApps());
+ record.put(ATT_ALLOW_BUBBLE, canBubble());
return record;
}
@@ -983,7 +983,7 @@
&& mShowBadge == that.mShowBadge
&& isDeleted() == that.isDeleted()
&& isBlockableSystem() == that.isBlockableSystem()
- && mAllowAppOverlay == that.mAllowAppOverlay
+ && mAllowBubbles == that.mAllowBubbles
&& Objects.equals(getId(), that.getId())
&& Objects.equals(getName(), that.getName())
&& Objects.equals(mDesc, that.mDesc)
@@ -1000,7 +1000,7 @@
getLockscreenVisibility(), getSound(), mLights, getLightColor(),
getUserLockedFields(),
isFgServiceShown(), mVibrationEnabled, mShowBadge, isDeleted(), getGroup(),
- getAudioAttributes(), isBlockableSystem(), mAllowAppOverlay,
+ getAudioAttributes(), isBlockableSystem(), mAllowBubbles,
mImportanceLockedByOEM);
result = 31 * result + Arrays.hashCode(mVibration);
return result;
@@ -1028,7 +1028,7 @@
+ ", mGroup='" + mGroup + '\''
+ ", mAudioAttributes=" + mAudioAttributes
+ ", mBlockableSystem=" + mBlockableSystem
- + ", mAllowAppOverlay=" + mAllowAppOverlay
+ + ", mAllowBubbles=" + mAllowBubbles
+ ", mImportanceLockedByOEM=" + mImportanceLockedByOEM
+ '}';
pw.println(prefix + output);
@@ -1055,7 +1055,7 @@
+ ", mGroup='" + mGroup + '\''
+ ", mAudioAttributes=" + mAudioAttributes
+ ", mBlockableSystem=" + mBlockableSystem
- + ", mAllowAppOverlay=" + mAllowAppOverlay
+ + ", mAllowBubbles=" + mAllowBubbles
+ ", mImportanceLockedByOEM=" + mImportanceLockedByOEM
+ '}';
}
@@ -1090,7 +1090,7 @@
mAudioAttributes.writeToProto(proto, NotificationChannelProto.AUDIO_ATTRIBUTES);
}
proto.write(NotificationChannelProto.IS_BLOCKABLE_SYSTEM, mBlockableSystem);
- proto.write(NotificationChannelProto.ALLOW_APP_OVERLAY, mAllowAppOverlay);
+ proto.write(NotificationChannelProto.ALLOW_APP_OVERLAY, mAllowBubbles);
proto.end(token);
}
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index aad3253..43614fe 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -1080,14 +1080,14 @@
* notification shade, floating over other apps' content.
*
* <p>This value will be ignored for notifications that are posted to channels that do not
- * allow app overlays ({@link NotificationChannel#canOverlayApps()}.
+ * allow bubbles ({@link NotificationChannel#canBubble()}.
*
- * @see Notification#getAppOverlayIntent()
+ * @see Notification#getBubbleMetadata()
*/
- public boolean areAppOverlaysAllowed() {
+ public boolean areBubblesAllowed() {
INotificationManager service = getService();
try {
- return service.areAppOverlaysAllowed(mContext.getPackageName());
+ return service.areBubblesAllowed(mContext.getPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/usage/EventList.java b/core/java/android/app/usage/EventList.java
index a79ad2f..aaae57e5 100644
--- a/core/java/android/app/usage/EventList.java
+++ b/core/java/android/app/usage/EventList.java
@@ -103,21 +103,4 @@
}
return result;
}
-
- /**
- * Remove events of certain type on or after a timestamp.
- * @param type The type of event to remove.
- * @param timeStamp the timeStamp on or after which to remove the event.
- */
- public void removeOnOrAfter(int type, long timeStamp) {
- for (int i = mEvents.size() - 1; i >= 0; i--) {
- UsageEvents.Event event = mEvents.get(i);
- if (event.mTimeStamp < timeStamp) {
- break;
- }
- if (event.mEventType == type) {
- mEvents.remove(i);
- }
- }
- }
}
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index d7a5328..2c5fe04 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -245,10 +245,18 @@
public static final int FLUSH_TO_DISK = 25;
/**
+ * An event type denoting that the device underwent a shutdown process.
+ * A DEVICE_SHUTDOWN event should be treated as if all started activities and foreground
+ * services are now stopped and no explicit {@link #ACTIVITY_STOPPED} and
+ * {@link #FOREGROUND_SERVICE_STOP} events will be generated for them.
+ */
+ public static final int DEVICE_SHUTDOWN = 26;
+
+ /**
* Keep in sync with the greatest event type value.
* @hide
*/
- public static final int MAX_EVENT_TYPE = 25;
+ public static final int MAX_EVENT_TYPE = 26;
/** @hide */
public static final int FLAG_IS_PACKAGE_INSTANT_APP = 1 << 0;
diff --git a/core/java/android/app/usage/UsageStats.java b/core/java/android/app/usage/UsageStats.java
index 308180b..94a2a3e 100644
--- a/core/java/android/app/usage/UsageStats.java
+++ b/core/java/android/app/usage/UsageStats.java
@@ -21,6 +21,7 @@
import static android.app.usage.UsageEvents.Event.ACTIVITY_RESUMED;
import static android.app.usage.UsageEvents.Event.ACTIVITY_STOPPED;
import static android.app.usage.UsageEvents.Event.CONTINUING_FOREGROUND_SERVICE;
+import static android.app.usage.UsageEvents.Event.DEVICE_SHUTDOWN;
import static android.app.usage.UsageEvents.Event.END_OF_DAY;
import static android.app.usage.UsageEvents.Event.FLUSH_TO_DISK;
import static android.app.usage.UsageEvents.Event.FOREGROUND_SERVICE_START;
@@ -119,12 +120,9 @@
public int mLastEvent;
/**
- * If an activity is visible(onStart(), onPause() states) or in foreground (onResume() state),
- * it has one entry in this map. When an activity becomes invisible (onStop() or onDestroy()),
- * it is removed from this map.
* Key is instanceId of the activity (ActivityRecode appToken hashCode)..
- * Value is this activity's last event, one of ACTIVITY_RESUMED or
- * ACTIVITY_PAUSED.
+ * Value is this activity's last event, one of ACTIVITY_RESUMED, ACTIVITY_PAUSED or
+ * ACTIVITY_STOPPED.
* {@hide}
*/
public SparseIntArray mActivities = new SparseIntArray();
@@ -560,6 +558,7 @@
mLastTimeForegroundServiceUsed = timeStamp;
mForegroundServices.put(className, eventType);
break;
+ case DEVICE_SHUTDOWN:
case FLUSH_TO_DISK:
// update usage of all active activities/services.
if (hasForegroundActivity()) {
diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/core/java/android/app/usage/UsageStatsManagerInternal.java
index 2edad35..cc3ab00 100644
--- a/core/java/android/app/usage/UsageStatsManagerInternal.java
+++ b/core/java/android/app/usage/UsageStatsManagerInternal.java
@@ -98,6 +98,12 @@
public abstract void prepareShutdown();
/**
+ * When the device power button is long pressed for 3.5 seconds, prepareForPossibleShutdown()
+ * is called.
+ */
+ public abstract void prepareForPossibleShutdown();
+
+ /**
* Returns true if the app has not been used for a certain amount of time. How much time?
* Could be hours, could be days, who knows?
*
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 636a70f..b845673 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -5555,26 +5555,24 @@
}
/**
- * @deprecated This function no longer does anything; it was an old
- * approach to managing preferred activities, which has been superseded
- * by (and conflicts with) the modern activity-based preferences.
+ * @deprecated This function no longer does anything. It is the platform's
+ * responsibility to assign preferred activities and this cannot be modified
+ * directly. To determine the activities resolved by the platform, use
+ * {@link #resolveActivity} or {@link #queryIntentActivities}.
*/
@Deprecated
public abstract void addPackageToPreferred(String packageName);
/**
- * @deprecated This function no longer does anything; it was an old
- * approach to managing preferred activities, which has been superseded
- * by (and conflicts with) the modern activity-based preferences.
+ * @deprecated This function no longer does anything. It is the platform's
+ * responsibility to assign preferred activities and this cannot be modified
+ * directly. To determine the activities resolved by the platform, use
+ * {@link #resolveActivity} or {@link #queryIntentActivities}.
*/
@Deprecated
public abstract void removePackageFromPreferred(String packageName);
/**
- * @deprecated This function no longer does anything; it was an old
- * approach to managing preferred activities, which has been superseded
- * by (and conflicts with) the modern activity-based preferences.
- *
* Retrieve the list of all currently configured preferred packages. The
* first package on the list is the most preferred, the last is the least
* preferred.
@@ -5582,15 +5580,16 @@
* @param flags Additional option flags to modify the data returned.
* @return A List of PackageInfo objects, one for each preferred
* application, in order of preference.
+ *
+ * @deprecated This function no longer does anything. It is the platform's
+ * responsibility to assign preferred activities and this cannot be modified
+ * directly. To determine the activities resolved by the platform, use
+ * {@link #resolveActivity} or {@link #queryIntentActivities}.
*/
@Deprecated
public abstract List<PackageInfo> getPreferredPackages(@PackageInfoFlags int flags);
/**
- * @deprecated This is a protected API that should not have been available
- * to third party applications. It is the platform's responsibility for
- * assigning preferred activities and this cannot be directly modified.
- *
* Add a new preferred activity mapping to the system. This will be used
* to automatically select the given activity component when
* {@link Context#startActivity(Intent) Context.startActivity()} finds
@@ -5604,20 +5603,26 @@
* this preference was made.
* @param activity The component name of the activity that is to be
* preferred.
+ *
+ * @deprecated This function no longer does anything. It is the platform's
+ * responsibility to assign preferred activities and this cannot be modified
+ * directly. To determine the activities resolved by the platform, use
+ * {@link #resolveActivity} or {@link #queryIntentActivities}.
*/
@Deprecated
public abstract void addPreferredActivity(IntentFilter filter, int match,
ComponentName[] set, ComponentName activity);
/**
- * @deprecated This is a protected API that should not have been available
- * to third party applications. It is the platform's responsibility for
- * assigning preferred activities and this cannot be directly modified.
- *
* Same as {@link #addPreferredActivity(IntentFilter, int,
ComponentName[], ComponentName)}, but with a specific userId to apply the preference
to.
* @hide
+ *
+ * @deprecated This function no longer does anything. It is the platform's
+ * responsibility to assign preferred activities and this cannot be modified
+ * directly. To determine the activities resolved by the platform, use
+ * {@link #resolveActivity} or {@link #queryIntentActivities}.
*/
@Deprecated
@UnsupportedAppUsage
@@ -5627,10 +5632,6 @@
}
/**
- * @deprecated This is a protected API that should not have been available
- * to third party applications. It is the platform's responsibility for
- * assigning preferred activities and this cannot be directly modified.
- *
* Replaces an existing preferred activity mapping to the system, and if that were not present
* adds a new preferred activity. This will be used
* to automatically select the given activity component when
@@ -5645,7 +5646,13 @@
* this preference was made.
* @param activity The component name of the activity that is to be
* preferred.
+ *
* @hide
+ *
+ * @deprecated This function no longer does anything. It is the platform's
+ * responsibility to assign preferred activities and this cannot be modified
+ * directly. To determine the activities resolved by the platform, use
+ * {@link #resolveActivity} or {@link #queryIntentActivities}.
*/
@Deprecated
@UnsupportedAppUsage
@@ -5653,10 +5660,6 @@
ComponentName[] set, ComponentName activity);
/**
- * @deprecated This is a protected API that should not have been available
- * to third party applications. It is the platform's responsibility for
- * assigning preferred activities and this cannot be directly modified.
- *
* Replaces an existing preferred activity mapping to the system, and if that were not present
* adds a new preferred activity. This will be used to automatically select the given activity
* component when {@link Context#startActivity(Intent) Context.startActivity()} finds multiple
@@ -5671,6 +5674,11 @@
* @param activity The component name of the activity that is to be preferred.
*
* @hide
+ *
+ * @deprecated This function no longer does anything. It is the platform's
+ * responsibility to assign preferred activities and this cannot be modified
+ * directly. To determine the activities resolved by the platform, use
+ * {@link #resolveActivity} or {@link #queryIntentActivities}.
*/
@Deprecated
@SystemApi
@@ -5681,6 +5689,11 @@
/**
* @hide
+ *
+ * @deprecated This function no longer does anything. It is the platform's
+ * responsibility to assign preferred activities and this cannot be modified
+ * directly. To determine the activities resolved by the platform, use
+ * {@link #resolveActivity} or {@link #queryIntentActivities}.
*/
@Deprecated
@UnsupportedAppUsage
@@ -5690,10 +5703,6 @@
}
/**
- * @deprecated This function no longer does anything; it was an old
- * approach to managing preferred activities, which has been superseded
- * by (and conflicts with) the modern activity-based preferences.
- *
* Remove all preferred activity mappings, previously added with
* {@link #addPreferredActivity}, from the
* system whose activities are implemented in the given package name.
@@ -5701,15 +5710,16 @@
*
* @param packageName The name of the package whose preferred activity
* mappings are to be removed.
+ *
+ * @deprecated This function no longer does anything. It is the platform's
+ * responsibility to assign preferred activities and this cannot be modified
+ * directly. To determine the activities resolved by the platform, use
+ * {@link #resolveActivity} or {@link #queryIntentActivities}.
*/
@Deprecated
public abstract void clearPackagePreferredActivities(String packageName);
/**
- * @deprecated This function no longer does anything; it was an old
- * approach to managing preferred activities, which has been superseded
- * by (and conflicts with) the modern activity-based preferences.
- *
* Retrieve all preferred activities, previously added with
* {@link #addPreferredActivity}, that are
* currently registered with the system.
@@ -5725,6 +5735,11 @@
* @return Returns the total number of registered preferred activities
* (the number of distinct IntentFilter records, not the number of unique
* activity components) that were found.
+ *
+ * @deprecated This function no longer does anything. It is the platform's
+ * responsibility to assign preferred activities and this cannot be modified
+ * directly. To determine the activities resolved by the platform, use
+ * {@link #resolveActivity} or {@link #queryIntentActivities}.
*/
@Deprecated
public abstract int getPreferredActivities(@NonNull List<IntentFilter> outFilters,
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 83563d0..45b5dca 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -137,6 +137,12 @@
public abstract void setLocationPackagesProvider(PackagesProvider provider);
/**
+ * Set the location extra packages provider.
+ * @param provider The packages provider.
+ */
+ public abstract void setLocationExtraPackagesProvider(PackagesProvider provider);
+
+ /**
* Sets the voice interaction packages provider.
* @param provider The packages provider.
*/
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 0fc50c6..dbf3574 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2656,6 +2656,23 @@
}
/**
+ * Matches a given {@code targetCode} against a set of release codeNames. Target codes can
+ * either be of the form {@code [codename]}" (e.g {@code "Q"}) or of the form
+ * {@code [codename].[fingerprint]} (e.g {@code "Q.cafebc561"}).
+ */
+ private static boolean matchTargetCode(@NonNull String[] codeNames,
+ @NonNull String targetCode) {
+ final String targetCodeName;
+ final int targetCodeIdx = targetCode.indexOf('.');
+ if (targetCodeIdx == -1) {
+ targetCodeName = targetCode;
+ } else {
+ targetCodeName = targetCode.substring(0, targetCodeIdx);
+ }
+ return ArrayUtils.contains(codeNames, targetCodeName);
+ }
+
+ /**
* Computes the targetSdkVersion to use at runtime. If the package is not
* compatible with this platform, populates {@code outError[0]} with an
* error message.
@@ -2698,7 +2715,7 @@
// If it's a pre-release SDK and the codename matches this platform, it
// definitely targets this SDK.
- if (ArrayUtils.contains(platformSdkCodenames, targetCode) || forceCurrentDev) {
+ if (matchTargetCode(platformSdkCodenames, targetCode) || forceCurrentDev) {
return Build.VERSION_CODES.CUR_DEVELOPMENT;
}
@@ -2831,7 +2848,7 @@
// If it's a pre-release SDK and the codename matches this platform, we
// definitely meet the minimum SDK requirement.
- if (ArrayUtils.contains(platformSdkCodenames, minCode)) {
+ if (matchTargetCode(platformSdkCodenames, minCode)) {
return Build.VERSION_CODES.CUR_DEVELOPMENT;
}
@@ -3760,9 +3777,11 @@
ai.flags |= ApplicationInfo.FLAG_MULTIARCH;
}
+ final boolean extractNativeLibsDefault =
+ owner.applicationInfo.targetSdkVersion < Build.VERSION_CODES.Q;
if (sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestApplication_extractNativeLibs,
- true)) {
+ extractNativeLibsDefault)) {
ai.flags |= ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS;
}
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index 508626b..d53834c 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -19,6 +19,7 @@
import android.annotation.AnyRes;
import android.annotation.ColorInt;
import android.annotation.Nullable;
+import android.annotation.StyleRes;
import android.annotation.StyleableRes;
import android.annotation.UnsupportedAppUsage;
import android.content.pm.ActivityInfo;
@@ -63,13 +64,15 @@
}
// STYLE_ prefixed constants are offsets within the typed data array.
- static final int STYLE_NUM_ENTRIES = 6;
+ // Keep this in sync with libs/androidfw/include/androidfw/AttributeResolution.h
+ static final int STYLE_NUM_ENTRIES = 7;
static final int STYLE_TYPE = 0;
static final int STYLE_DATA = 1;
static final int STYLE_ASSET_COOKIE = 2;
static final int STYLE_RESOURCE_ID = 3;
static final int STYLE_CHANGING_CONFIGURATIONS = 4;
static final int STYLE_DENSITY = 5;
+ static final int SYTLE_SOURCE_STYLE_RESOURCE_ID = 6;
@UnsupportedAppUsage
private final Resources mResources;
@@ -1098,6 +1101,31 @@
}
/**
+ * Returns the resource ID of the style against which the specified attribute was resolved,
+ * otherwise returns defValue.
+ *
+ * @param index Index of attribute whose source style to retrieve.
+ * @param defValue Value to return if the attribute is not defined or
+ * not a resource.
+ *
+ * @return Attribute source style resource ID or defValue if it was not resolved in any style.
+ * @throws RuntimeException if the TypedArray has already been recycled.
+ */
+ @StyleRes
+ public int getSourceStyleResourceId(@StyleableRes int index, @StyleRes int defValue) {
+ if (mRecycled) {
+ throw new RuntimeException("Cannot make calls to a recycled instance!");
+ }
+
+ index *= STYLE_NUM_ENTRIES;
+ final int resid = mData[index + SYTLE_SOURCE_STYLE_RESOURCE_ID];
+ if (resid != 0) {
+ return resid;
+ }
+ return defValue;
+ }
+
+ /**
* Determines whether there is an attribute at <var>index</var>.
* <p>
* <strong>Note:</strong> If the attribute was set to {@code @empty} or
@@ -1309,6 +1337,7 @@
data[index + STYLE_CHANGING_CONFIGURATIONS]);
outValue.density = data[index + STYLE_DENSITY];
outValue.string = (type == TypedValue.TYPE_STRING) ? loadStringValueAt(index) : null;
+ outValue.sourceStyleResourceId = data[index + SYTLE_SOURCE_STYLE_RESOURCE_ID];
return true;
}
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index eb3414d..8aac1bf 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -42,13 +42,13 @@
/**
* The hardware is unavailable. Try again later.
*/
- public static final int BIOMETRIC_ERROR_UNAVAILABLE =
+ public static final int BIOMETRIC_ERROR_HW_UNAVAILABLE =
BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE;
/**
* The user does not have any biometrics enrolled.
*/
- public static final int BIOMETRIC_ERROR_NO_BIOMETRICS =
+ public static final int BIOMETRIC_ERROR_NONE_ENROLLED =
BiometricConstants.BIOMETRIC_ERROR_NO_BIOMETRICS;
/**
@@ -58,8 +58,8 @@
BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT;
@IntDef({BIOMETRIC_SUCCESS,
- BIOMETRIC_ERROR_UNAVAILABLE,
- BIOMETRIC_ERROR_NO_BIOMETRICS,
+ BIOMETRIC_ERROR_HW_UNAVAILABLE,
+ BIOMETRIC_ERROR_NONE_ENROLLED,
BIOMETRIC_ERROR_NO_HARDWARE})
@interface BiometricError {}
@@ -95,8 +95,8 @@
* Determine if biometrics can be used. In other words, determine if {@link BiometricPrompt}
* can be expected to be shown (hardware available, templates enrolled, user-enabled).
*
- * @return Returns {@link #BIOMETRIC_ERROR_NO_BIOMETRICS} if the user does not have any
- * enrolled, or {@link #BIOMETRIC_ERROR_UNAVAILABLE} if none are currently
+ * @return Returns {@link #BIOMETRIC_ERROR_NONE_ENROLLED} if the user does not have any
+ * enrolled, or {@link #BIOMETRIC_ERROR_HW_UNAVAILABLE} if none are currently
* supported/enabled. Returns {@link #BIOMETRIC_SUCCESS} if a biometric can currently be
* used (enrolled and available).
*/
@@ -113,7 +113,7 @@
return BIOMETRIC_ERROR_NO_HARDWARE;
} else {
Slog.w(TAG, "hasEnrolledBiometrics(): Service not connected");
- return BIOMETRIC_ERROR_UNAVAILABLE;
+ return BIOMETRIC_ERROR_HW_UNAVAILABLE;
}
}
}
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index f652f85..c69b68e4 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -235,7 +235,6 @@
* requiring confirmation.
*
* @param requireConfirmation
- * @hide
*/
public Builder setRequireConfirmation(boolean requireConfirmation) {
mBundle.putBoolean(KEY_REQUIRE_CONFIRMATION, requireConfirmation);
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index cda8498..7e45441 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -436,6 +436,7 @@
public void setVirtualDisplaySurface(IVirtualDisplayCallback token, Surface surface) {
try {
mDm.setVirtualDisplaySurface(token, surface);
+ setVirtualDisplayState(token, surface != null);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
@@ -458,6 +459,14 @@
}
}
+ void setVirtualDisplayState(IVirtualDisplayCallback token, boolean isOn) {
+ try {
+ mDm.setVirtualDisplayState(token, isOn);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
/**
* Gets the stable device display size, in pixels.
*/
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index 2d81cdf..aae8afb 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -82,6 +82,9 @@
// No permissions required but must be same Uid as the creator.
void releaseVirtualDisplay(in IVirtualDisplayCallback token);
+ // No permissions required but must be same Uid as the creator.
+ void setVirtualDisplayState(in IVirtualDisplayCallback token, boolean isOn);
+
// Get a stable metric for the device's display size. No permissions required.
Point getStableDisplaySize();
diff --git a/core/java/android/hardware/display/VirtualDisplay.java b/core/java/android/hardware/display/VirtualDisplay.java
index d354666..bf62c95 100644
--- a/core/java/android/hardware/display/VirtualDisplay.java
+++ b/core/java/android/hardware/display/VirtualDisplay.java
@@ -104,6 +104,18 @@
}
}
+ /**
+ * Sets the on/off state for a virtual display.
+ *
+ * @param isOn Whether the display should be on or off.
+ * @hide
+ */
+ public void setDisplayState(boolean isOn) {
+ if (mToken != null) {
+ mGlobal.setVirtualDisplayState(mToken, isOn);
+ }
+ }
+
@Override
public String toString() {
return "VirtualDisplay{display=" + mDisplay + ", token=" + mToken
diff --git a/core/java/android/hardware/hdmi/HdmiAudioSystemClient.java b/core/java/android/hardware/hdmi/HdmiAudioSystemClient.java
index d382eb9..bdd5ab6 100644
--- a/core/java/android/hardware/hdmi/HdmiAudioSystemClient.java
+++ b/core/java/android/hardware/hdmi/HdmiAudioSystemClient.java
@@ -15,10 +15,12 @@
*/
package android.hardware.hdmi;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
+import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting.Visibility;
@@ -56,6 +58,21 @@
mHandler = handler == null ? new Handler(Looper.getMainLooper()) : handler;
}
+ /**
+ * Callback interface used to get the set System Audio Mode result.
+ *
+ * @hide
+ */
+ // TODO(b/110094868): unhide and add @SystemApi for Q
+ public interface SetSystemAudioModeCallback {
+ /**
+ * Called when the input was changed.
+ *
+ * @param result the result of the set System Audio Mode
+ */
+ void onComplete(int result);
+ }
+
/** @hide */
// TODO(b/110094868): unhide and add @SystemApi for Q
@Override
@@ -117,4 +134,34 @@
mPendingReportAudioStatus = true;
}
}
+
+ /**
+ * Set System Audio Mode on/off with audio system device.
+ *
+ * @param state true to set System Audio Mode on. False to set off.
+ * @param callback callback offer the setting result.
+ *
+ * @hide
+ */
+ // TODO(b/110094868): unhide and add @SystemApi for Q
+ public void setSystemAudioMode(boolean state, @NonNull SetSystemAudioModeCallback callback) {
+ // TODO(amyjojo): implement this when needed.
+ }
+
+ /**
+ * When device is switching to an audio only source, this method is called to broadcast
+ * a setSystemAudioMode on message to the HDMI CEC system without querying Active Source or
+ * TV supporting System Audio Control or not. This is to get volume control passthrough
+ * from STB even if TV does not support it.
+ *
+ * @hide
+ */
+ // TODO(b/110094868): unhide and add @SystemApi for Q
+ public void setSystemAudioModeOnForAudioOnlySource() {
+ try {
+ mService.setSystemAudioModeOnForAudioOnlySource();
+ } catch (RemoteException e) {
+ Log.d(TAG, "Failed to set System Audio Mode on for Audio Only source");
+ }
+ }
}
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
index f5d288e..a98b31a 100644
--- a/core/java/android/hardware/hdmi/HdmiControlManager.java
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -33,6 +33,8 @@
import android.util.ArrayMap;
import android.util.Log;
+import java.util.List;
+
/**
* The {@link HdmiControlManager} class is used to send HDMI control messages
* to attached CEC devices.
@@ -53,6 +55,10 @@
@Nullable private final IHdmiControlService mService;
+ private static final int INVALID_PHYSICAL_ADDRESS = 0xFFFF;
+
+ private int mPhysicalAddress = INVALID_PHYSICAL_ADDRESS;
+
/**
* Broadcast Action: Display OSD message.
* <p>Send when the service has a message to display on screen for events
@@ -404,6 +410,72 @@
}
/**
+ * Get a snapshot of the real-time status of the remote devices.
+ *
+ * @return a list of {@link HdmiDeviceInfo} of the devices connected to the current device.
+ *
+ * TODO(b/110094868): unhide for Q
+ * @hide
+ */
+ public List<HdmiDeviceInfo> getConnectedDevicesList() {
+ try {
+ return mService.getDeviceList();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Power off the target device.
+ *
+ * @param deviceInfo HdmiDeviceInfo of the device to be powered off
+ *
+ * TODO(b/110094868): unhide for Q
+ * @hide
+ */
+ public void powerOffRemoteDevice(HdmiDeviceInfo deviceInfo) {
+ try {
+ mService.powerOffRemoteDevice(
+ deviceInfo.getLogicalAddress(), deviceInfo.getDevicePowerStatus());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Power on the target device.
+ *
+ * @param deviceInfo HdmiDeviceInfo of the device to be powered on
+ *
+ * TODO(b/110094868): unhide for Q
+ * @hide
+ */
+ public void powerOnRemoteDevice(HdmiDeviceInfo deviceInfo) {
+ try {
+ mService.powerOnRemoteDevice(
+ deviceInfo.getLogicalAddress(), deviceInfo.getDevicePowerStatus());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Ask the target device to be the new Active Source.
+ *
+ * @param deviceInfo HdmiDeviceInfo of the target device
+ *
+ * TODO(b/110094868): unhide for Q
+ * @hide
+ */
+ public void askRemoteDeviceToBecomeActiveSource(HdmiDeviceInfo deviceInfo) {
+ try {
+ mService.askRemoteDeviceToBecomeActiveSource(deviceInfo.getPhysicalAddress());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Controls standby mode of the system. It will also try to turn on/off the connected devices if
* necessary.
*
@@ -432,6 +504,46 @@
}
/**
+ * Get the physical address of the device.
+ *
+ * @hide
+ */
+ public int getPhysicalAddress() {
+ if (mPhysicalAddress != INVALID_PHYSICAL_ADDRESS) {
+ return mPhysicalAddress;
+ }
+ try {
+ mPhysicalAddress = mService.getPhysicalAddress();
+ return mPhysicalAddress;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Check if the target device is connected to the current device. The
+ * API also returns true if the current device is the target.
+ *
+ * @param targetDevice {@link HdmiDeviceInfo} of the target device.
+ * @return true if {@code device} is directly or indirectly connected to the
+ *
+ * TODO(b/110094868): unhide for Q
+ * @hide
+ */
+ public boolean isTargetDeviceConnected(HdmiDeviceInfo targetDevice) {
+ mPhysicalAddress = getPhysicalAddress();
+ if (mPhysicalAddress == INVALID_PHYSICAL_ADDRESS) {
+ return false;
+ }
+ int targetPhysicalAddress = targetDevice.getPhysicalAddress();
+ if (targetPhysicalAddress == INVALID_PHYSICAL_ADDRESS) {
+ return false;
+ }
+ return HdmiUtils.getLocalPortFromPhysicalAddress(targetPhysicalAddress, mPhysicalAddress)
+ != HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE;
+ }
+
+ /**
* Listener used to get hotplug event from HDMI port.
*/
public interface HotplugEventListener {
diff --git a/core/java/android/hardware/hdmi/HdmiUtils.java b/core/java/android/hardware/hdmi/HdmiUtils.java
new file mode 100644
index 0000000..3081738
--- /dev/null
+++ b/core/java/android/hardware/hdmi/HdmiUtils.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.hdmi;
+
+/**
+ * Various utilities to handle HDMI CEC messages.
+ *
+ * TODO(b/110094868): unhide for Q
+ * @hide
+ */
+public class HdmiUtils {
+
+ /**
+ * Return value of {@link #getLocalPortFromPhysicalAddress(int, int)}
+ */
+ static final int TARGET_NOT_UNDER_LOCAL_DEVICE = -1;
+ static final int TARGET_SAME_PHYSICAL_ADDRESS = 0;
+
+ private HdmiUtils() { /* cannot be instantiated */ }
+
+ /**
+ * Method to parse target physical address to the port number on the current device.
+ *
+ * <p>This check assumes target address is valid.
+ *
+ * @param targetPhysicalAddress is the physical address of the target device
+ * @param myPhysicalAddress is the physical address of the current device
+ * @return
+ * If the target device is under the current device, return the port number of current device
+ * that the target device is connected to. This also applies to the devices that are indirectly
+ * connected to the current device.
+ *
+ * <p>If the target device has the same physical address as the current device, return
+ * {@link #TARGET_SAME_PHYSICAL_ADDRESS}.
+ *
+ * <p>If the target device is not under the current device, return
+ * {@link #TARGET_NOT_UNDER_LOCAL_DEVICE}.
+ */
+ public static int getLocalPortFromPhysicalAddress(
+ int targetPhysicalAddress, int myPhysicalAddress) {
+ if (myPhysicalAddress == targetPhysicalAddress) {
+ return TARGET_SAME_PHYSICAL_ADDRESS;
+ }
+
+ int mask = 0xF000;
+ int finalMask = 0xF000;
+ int maskedAddress = myPhysicalAddress;
+
+ while (maskedAddress != 0) {
+ maskedAddress = myPhysicalAddress & mask;
+ finalMask |= mask;
+ mask >>= 4;
+ }
+
+ int portAddress = targetPhysicalAddress & finalMask;
+ if ((portAddress & (finalMask << 4)) != myPhysicalAddress) {
+ return TARGET_NOT_UNDER_LOCAL_DEVICE;
+ }
+
+ mask <<= 4;
+ int port = portAddress & mask;
+ while ((port >> 4) != 0) {
+ port >>= 4;
+ }
+ return port;
+ }
+}
diff --git a/core/java/android/hardware/hdmi/IHdmiControlService.aidl b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
index 2b8d00b..1cd9920 100644
--- a/core/java/android/hardware/hdmi/IHdmiControlService.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
@@ -50,6 +50,7 @@
List<HdmiPortInfo> getPortInfo();
boolean canChangeSystemAudioMode();
boolean getSystemAudioMode();
+ int getPhysicalAddress();
void setSystemAudioMode(boolean enabled, IHdmiControlCallback callback);
void addSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener);
void removeSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener);
@@ -60,6 +61,9 @@
void setInputChangeListener(IHdmiInputChangeListener listener);
List<HdmiDeviceInfo> getInputDevices();
List<HdmiDeviceInfo> getDeviceList();
+ void powerOffRemoteDevice(int logicalAddress, int powerStatus);
+ void powerOnRemoteDevice(int logicalAddress, int powerStatus);
+ void askRemoteDeviceToBecomeActiveSource(int physicalAddress);
void sendVendorCommand(int deviceType, int targetAddress, in byte[] params,
boolean hasVendorId);
void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType);
@@ -73,4 +77,5 @@
void addHdmiMhlVendorCommandListener(IHdmiMhlVendorCommandListener listener);
void setStandbyMode(boolean isStandbyModeOn);
void reportAudioStatus(int deviceType, int volume, int maxVolume, boolean isMute);
+ void setSystemAudioModeOnForAudioOnlySource();
}
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 617125b3..c2963fd 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -191,6 +191,7 @@
}
setMtu(source.mMtu);
mTcpBufferSizes = source.mTcpBufferSizes;
+ mNat64Prefix = source.mNat64Prefix;
}
}
diff --git a/core/java/android/net/ipmemorystore/NetworkAttributes.java b/core/java/android/net/ipmemorystore/NetworkAttributes.java
index d7e5b27..b932d21 100644
--- a/core/java/android/net/ipmemorystore/NetworkAttributes.java
+++ b/core/java/android/net/ipmemorystore/NetworkAttributes.java
@@ -28,6 +28,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Objects;
+import java.util.StringJoiner;
/**
* A POD object to represent attributes of a single L2 network entry.
@@ -207,4 +208,52 @@
public int hashCode() {
return Objects.hash(assignedV4Address, groupHint, dnsAddresses, mtu);
}
+
+ /** Pretty print */
+ @Override
+ public String toString() {
+ final StringJoiner resultJoiner = new StringJoiner(" ", "{", "}");
+ final ArrayList<String> nullFields = new ArrayList<>();
+
+ if (null != assignedV4Address) {
+ resultJoiner.add("assignedV4Addr :");
+ resultJoiner.add(assignedV4Address.toString());
+ } else {
+ nullFields.add("assignedV4Addr");
+ }
+
+ if (null != groupHint) {
+ resultJoiner.add("groupHint :");
+ resultJoiner.add(groupHint);
+ } else {
+ nullFields.add("groupHint");
+ }
+
+ if (null != dnsAddresses) {
+ resultJoiner.add("dnsAddr : [");
+ for (final InetAddress addr : dnsAddresses) {
+ resultJoiner.add(addr.getHostAddress());
+ }
+ resultJoiner.add("]");
+ } else {
+ nullFields.add("dnsAddr");
+ }
+
+ if (null != mtu) {
+ resultJoiner.add("mtu :");
+ resultJoiner.add(mtu.toString());
+ } else {
+ nullFields.add("mtu");
+ }
+
+ if (!nullFields.isEmpty()) {
+ resultJoiner.add("; Null fields : [");
+ for (final String field : nullFields) {
+ resultJoiner.add(field);
+ }
+ resultJoiner.add("]");
+ }
+
+ return resultJoiner.toString();
+ }
}
diff --git a/core/java/android/net/ipmemorystore/SameL3NetworkResponse.java b/core/java/android/net/ipmemorystore/SameL3NetworkResponse.java
index 0cb37e9..d040dcc 100644
--- a/core/java/android/net/ipmemorystore/SameL3NetworkResponse.java
+++ b/core/java/android/net/ipmemorystore/SameL3NetworkResponse.java
@@ -128,4 +128,19 @@
public int hashCode() {
return Objects.hash(l2Key1, l2Key2, confidence);
}
+
+ @Override
+ /** Pretty print */
+ public String toString() {
+ switch (getNetworkSameness()) {
+ case NETWORK_SAME:
+ return "\"" + l2Key1 + "\" same L3 network as \"" + l2Key2 + "\"";
+ case NETWORK_DIFFERENT:
+ return "\"" + l2Key1 + "\" different L3 network from \"" + l2Key2 + "\"";
+ case NETWORK_NEVER_CONNECTED:
+ return "\"" + l2Key1 + "\" can't be tested against \"" + l2Key2 + "\"";
+ default:
+ return "Buggy sameness value ? \"" + l2Key1 + "\", \"" + l2Key2 + "\"";
+ }
+ }
}
diff --git a/core/java/android/net/ipmemorystore/Status.java b/core/java/android/net/ipmemorystore/Status.java
index 5b016ec..95e5042 100644
--- a/core/java/android/net/ipmemorystore/Status.java
+++ b/core/java/android/net/ipmemorystore/Status.java
@@ -26,6 +26,8 @@
public class Status {
public static final int SUCCESS = 0;
+ public static final int ERROR_DATABASE_CANNOT_BE_OPENED = -1;
+
public final int resultCode;
public Status(final int resultCode) {
@@ -47,4 +49,14 @@
public boolean isSuccess() {
return SUCCESS == resultCode;
}
+
+ /** Pretty print */
+ @Override
+ public String toString() {
+ switch (resultCode) {
+ case SUCCESS: return "SUCCESS";
+ case ERROR_DATABASE_CANNOT_BE_OPENED: return "DATABASE CANNOT BE OPENED";
+ default: return "Unknown value ?!";
+ }
+ }
}
diff --git a/core/java/android/net/ipmemorystore/Utils.java b/core/java/android/net/ipmemorystore/Utils.java
new file mode 100644
index 0000000..73d8c83
--- /dev/null
+++ b/core/java/android/net/ipmemorystore/Utils.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.ipmemorystore;
+
+import android.annotation.NonNull;
+
+/** {@hide} */
+public class Utils {
+ /** Pretty print */
+ public static String blobToString(final Blob blob) {
+ final StringBuilder sb = new StringBuilder("Blob : [");
+ if (blob.data.length <= 24) {
+ appendByteArray(sb, blob.data, 0, blob.data.length);
+ } else {
+ appendByteArray(sb, blob.data, 0, 16);
+ sb.append("...");
+ appendByteArray(sb, blob.data, blob.data.length - 8, blob.data.length);
+ }
+ sb.append("]");
+ return sb.toString();
+ }
+
+ // Adds the hex representation of the array between the specified indices (inclusive, exclusive)
+ private static void appendByteArray(@NonNull final StringBuilder sb, @NonNull final byte[] ar,
+ final int from, final int to) {
+ for (int i = from; i < to; ++i) {
+ sb.append(String.format("%02X", ar[i]));
+ }
+ }
+}
diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java
index b15a4d3..cbb3909 100644
--- a/core/java/android/os/BugreportManager.java
+++ b/core/java/android/os/BugreportManager.java
@@ -114,7 +114,6 @@
}
}
- // TODO(b/111441001) Connect up with BugreportListener methods.
private final class DumpstateListener extends IDumpstateListener.Stub
implements DeathRecipient {
private final BugreportListener mListener;
@@ -130,35 +129,35 @@
@Override
public void onProgress(int progress) throws RemoteException {
- // TODO(b/111441001): implement
+ mListener.onProgress(progress);
}
@Override
public void onError(int errorCode) throws RemoteException {
- // TODO(b/111441001): implement
+ mListener.onError(errorCode);
}
@Override
public void onFinished(long durationMs, String title, String description)
throws RemoteException {
- // TODO(b/111441001): implement
+ mListener.onFinished(durationMs, title, description);
}
// Old methods; should go away
@Override
public void onProgressUpdated(int progress) throws RemoteException {
- // TODO(b/111441001): implement
+ // TODO(b/111441001): remove from interface
}
@Override
public void onMaxProgressUpdated(int maxProgress) throws RemoteException {
- // TODO(b/111441001): implement
+ // TODO(b/111441001): remove from interface
}
@Override
public void onSectionComplete(String title, int status, int size, int durationMs)
throws RemoteException {
- // TODO(b/111441001): implement
+ // TODO(b/111441001): remove from interface
}
}
}
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 9fea873..2d61a4e 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -289,6 +289,26 @@
"ro.build.version.preview_sdk", 0);
/**
+ * The SDK fingerprint for a given prerelease SDK. This value will always be
+ * {@code REL} on production platform builds/devices.
+ *
+ * <p>When this value is not {@code REL}, it contains a string fingerprint of the API
+ * surface exposed by the preview SDK. Preview platforms with different API surfaces
+ * will have different {@code PREVIEW_SDK_FINGERPRINT}.
+ *
+ * <p>This attribute is intended for use by installers for finer grained targeting of
+ * packages. Applications targeting preview APIs should not use this field and should
+ * instead use {@code PREVIEW_SDK_INT} or use reflection or other runtime checks to
+ * detect the presence of an API or guard themselves against unexpected runtime
+ * behavior.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String PREVIEW_SDK_FINGERPRINT = SystemProperties.get(
+ "ro.build.version.preview_sdk_fingerprint", "REL");
+
+ /**
* The current development codename, or the string "REL" if this is
* a release build.
*/
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index b0b8f49..e4622db 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -480,21 +480,36 @@
return;
}
- if (getGlobalSettingsString(coreSettings, Settings.Global.GUP_DEV_OPT_OUT_APPS)
- .contains(ai.packageName)) {
+ // GUP_DEV_ALL_APPS
+ // 0: Default (Invalid values fallback to default as well)
+ // 1: All apps use Game Update Package
+ // 2: All apps use system graphics driver
+ int gupDevAllApps = coreSettings.getInt(Settings.Global.GUP_DEV_ALL_APPS, 0);
+ if (gupDevAllApps == 2) {
if (DEBUG) {
- Log.w(TAG, ai.packageName + " opts out from GUP.");
+ Log.w(TAG, "GUP is turned off on this device");
}
return;
}
- if (!getGlobalSettingsString(coreSettings, Settings.Global.GUP_DEV_OPT_IN_APPS)
- .contains(ai.packageName)
- && !onWhitelist(context, driverPackageName, ai.packageName)) {
- if (DEBUG) {
- Log.w(TAG, ai.packageName + " is not on the whitelist.");
+ if (gupDevAllApps != 1) {
+ // GUP_DEV_OPT_OUT_APPS has higher priority than GUP_DEV_OPT_IN_APPS
+ if (getGlobalSettingsString(coreSettings, Settings.Global.GUP_DEV_OPT_OUT_APPS)
+ .contains(ai.packageName)) {
+ if (DEBUG) {
+ Log.w(TAG, ai.packageName + " opts out from GUP.");
+ }
+ return;
}
- return;
+
+ if (!getGlobalSettingsString(coreSettings, Settings.Global.GUP_DEV_OPT_IN_APPS)
+ .contains(ai.packageName)
+ && !onWhitelist(context, driverPackageName, ai.packageName)) {
+ if (DEBUG) {
+ Log.w(TAG, ai.packageName + " is not on the whitelist.");
+ }
+ return;
+ }
}
ApplicationInfo driverInfo;
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index fdd7488..8ced722 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -356,16 +356,6 @@
void removeVpnUidRanges(int netId, in UidRange[] ranges);
/**
- * Start the clatd (464xlat) service on the given interface.
- */
- void startClatd(String interfaceName);
-
- /**
- * Stop the clatd (464xlat) service on the given interface.
- */
- void stopClatd(String interfaceName);
-
- /**
* Start listening for mobile activity state changes.
*/
void registerNetworkActivityListener(INetworkActivityListener listener);
diff --git a/core/java/android/permission/IPermissionController.aidl b/core/java/android/permission/IPermissionController.aidl
index 7a7bd83..249b622 100644
--- a/core/java/android/permission/IPermissionController.aidl
+++ b/core/java/android/permission/IPermissionController.aidl
@@ -18,6 +18,8 @@
import android.os.RemoteCallback;
import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+import android.os.UserHandle;
/**
* Interface for system apps to communication with the permission controller.
@@ -27,6 +29,7 @@
oneway interface IPermissionController {
void revokeRuntimePermissions(in Bundle request, boolean doDryRun, int reason,
String callerPackageName, in RemoteCallback callback);
+ void getRuntimePermissionBackup(in UserHandle user, in ParcelFileDescriptor pipe);
void getAppPermissions(String packageName, in RemoteCallback callback);
void revokeRuntimePermission(String packageName, String permissionName);
void countPermissionApps(in List<String> permissionNames, boolean countOnlyGranted,
diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java
index 0865b62..bfcca7c 100644
--- a/core/java/android/permission/PermissionControllerManager.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -36,10 +36,12 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.os.AsyncTask;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -51,6 +53,11 @@
import com.android.internal.infra.AbstractRemoteService;
import com.android.internal.util.Preconditions;
+import libcore.io.IoUtils;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
@@ -58,6 +65,7 @@
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
+import java.util.function.Consumer;
/**
* Interface for communicating with the permission controller.
@@ -118,6 +126,20 @@
}
/**
+ * Callback for delivering the result of {@link #getRuntimePermissionBackup}.
+ *
+ * @hide
+ */
+ public interface OnGetRuntimePermissionBackupCallback {
+ /**
+ * The result for {@link #getRuntimePermissionBackup}.
+ *
+ * @param backup The backup file
+ */
+ void onGetRuntimePermissionsBackup(@NonNull byte[] backup);
+ }
+
+ /**
* Callback for delivering the result of {@link #getAppPermissions}.
*
* @hide
@@ -219,6 +241,26 @@
}
/**
+ * Create a backup of the runtime permissions.
+ *
+ * @param user The user to be backed up
+ * @param executor Executor on which to invoke the callback
+ * @param callback Callback to receive the result
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS)
+ public void getRuntimePermissionBackup(@NonNull UserHandle user,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull OnGetRuntimePermissionBackupCallback callback) {
+ checkNotNull(executor);
+ checkNotNull(callback);
+
+ sRemoteService.scheduleRequest(new PendingGetRuntimePermissionBackup(sRemoteService,
+ user, executor, callback));
+ }
+
+ /**
* Gets the runtime permissions for an app.
*
* @param packageName The package for which to query.
@@ -355,6 +397,89 @@
}
/**
+ * Task to read a large amount of data from a remote service.
+ */
+ private static class FileReaderTask<Callback extends Consumer<byte[]>>
+ extends AsyncTask<Void, Void, byte[]> {
+ private ParcelFileDescriptor mLocalPipe;
+ private ParcelFileDescriptor mRemotePipe;
+
+ private final @NonNull Callback mCallback;
+
+ FileReaderTask(@NonNull Callback callback) {
+ mCallback = callback;
+ }
+
+ @Override
+ protected void onPreExecute() {
+ ParcelFileDescriptor[] pipe;
+ try {
+ pipe = ParcelFileDescriptor.createPipe();
+ } catch (IOException e) {
+ Log.e(TAG, "Could not create pipe needed to get runtime permission backup", e);
+ return;
+ }
+
+ mLocalPipe = pipe[0];
+ mRemotePipe = pipe[1];
+ }
+
+ /**
+ * Get the file descriptor the remote service should write the data to.
+ *
+ * <p>Needs to be closed <u>locally</u> before the FileReader can finish.
+ *
+ * @return The file the data should be written to
+ */
+ ParcelFileDescriptor getRemotePipe() {
+ return mRemotePipe;
+ }
+
+ @Override
+ protected byte[] doInBackground(Void... ignored) {
+ ByteArrayOutputStream combinedBuffer = new ByteArrayOutputStream();
+
+ try (InputStream in = new ParcelFileDescriptor.AutoCloseInputStream(mLocalPipe)) {
+ byte[] buffer = new byte[16 * 1024];
+
+ while (!isCancelled()) {
+ int numRead = in.read(buffer);
+ if (numRead == -1) {
+ break;
+ }
+
+ combinedBuffer.write(buffer, 0, numRead);
+ }
+ } catch (IOException | NullPointerException e) {
+ Log.e(TAG, "Error reading runtime permission backup", e);
+ combinedBuffer.reset();
+ }
+
+ return combinedBuffer.toByteArray();
+ }
+
+ /**
+ * Interrupt the reading of the data.
+ *
+ * <p>Needs to be called when canceling this task as it might be hung.
+ */
+ void interruptRead() {
+ IoUtils.closeQuietly(mLocalPipe);
+ }
+
+ @Override
+ protected void onCancelled() {
+ onPostExecute(new byte[]{});
+ }
+
+ @Override
+ protected void onPostExecute(byte[] backup) {
+ IoUtils.closeQuietly(mLocalPipe);
+ mCallback.accept(backup);
+ }
+ }
+
+ /**
* Request for {@link #revokeRuntimePermissions}
*/
private static final class PendingRevokeRuntimePermissionRequest extends
@@ -441,6 +566,68 @@
}
/**
+ * Request for {@link #getRuntimePermissionBackup}
+ */
+ private static final class PendingGetRuntimePermissionBackup extends
+ AbstractRemoteService.PendingRequest<RemoteService, IPermissionController>
+ implements Consumer<byte[]> {
+ private final @NonNull FileReaderTask<PendingGetRuntimePermissionBackup> mBackupReader;
+ private final @NonNull Executor mExecutor;
+ private final @NonNull OnGetRuntimePermissionBackupCallback mCallback;
+ private final @NonNull UserHandle mUser;
+
+ private PendingGetRuntimePermissionBackup(@NonNull RemoteService service,
+ @NonNull UserHandle user, @NonNull @CallbackExecutor Executor executor,
+ @NonNull OnGetRuntimePermissionBackupCallback callback) {
+ super(service);
+
+ mUser = user;
+ mExecutor = executor;
+ mCallback = callback;
+
+ mBackupReader = new FileReaderTask<>(this);
+ }
+
+ @Override
+ protected void onTimeout(RemoteService remoteService) {
+ mBackupReader.cancel(true);
+ mBackupReader.interruptRead();
+ }
+
+ @Override
+ public void run() {
+ mBackupReader.execute();
+
+ ParcelFileDescriptor remotePipe = mBackupReader.getRemotePipe();
+ try {
+ getService().getServiceInterface().getRuntimePermissionBackup(mUser, remotePipe);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error getting runtime permission backup", e);
+ } finally {
+ // Remote pipe end is duped by binder call. Local copy is not needed anymore
+ IoUtils.closeQuietly(remotePipe);
+ }
+ }
+
+ /**
+ * Called when the {@link #mBackupReader} finished reading the file.
+ *
+ * @param backup The data read
+ */
+ @Override
+ public void accept(byte[] backup) {
+ long token = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mCallback.onGetRuntimePermissionsBackup(backup));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+
+ finish();
+ }
+ }
+
+ /**
* Request for {@link #getAppPermissions}
*/
private static final class PendingGetAppPermissionRequest extends
diff --git a/core/java/android/permission/PermissionControllerService.java b/core/java/android/permission/PermissionControllerService.java
index 75d61e6..10e8c8d 100644
--- a/core/java/android/permission/PermissionControllerService.java
+++ b/core/java/android/permission/PermissionControllerService.java
@@ -33,11 +33,16 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
import android.os.RemoteCallback;
+import android.os.UserHandle;
import android.util.ArrayMap;
+import android.util.Log;
import com.android.internal.util.Preconditions;
+import java.io.IOException;
+import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -51,6 +56,7 @@
*/
@SystemApi
public abstract class PermissionControllerService extends Service {
+ private static final String LOG_TAG = PermissionControllerService.class.getSimpleName();
/**
* The {@link Intent} action that must be declared as handled by a service
@@ -83,6 +89,15 @@
@PermissionControllerManager.Reason int reason, @NonNull String callerPackageName);
/**
+ * Create a backup of the runtime permissions.
+ *
+ * @param user The user to back up
+ * @param out The stream to write the backup to
+ */
+ public abstract void onGetRuntimePermissionsBackup(@NonNull UserHandle user,
+ @NonNull OutputStream out);
+
+ /**
* Gets the runtime permissions for an app.
*
* @param packageName The package for which to query.
@@ -163,6 +178,18 @@
}
@Override
+ public void getRuntimePermissionBackup(UserHandle user, ParcelFileDescriptor pipe) {
+ checkNotNull(user);
+ checkNotNull(pipe);
+
+ enforceCallingPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS, null);
+
+ mHandler.sendMessage(obtainMessage(
+ PermissionControllerService::getRuntimePermissionsBackup,
+ PermissionControllerService.this, user, pipe));
+ }
+
+ @Override
public void getAppPermissions(String packageName, RemoteCallback callback) {
checkNotNull(packageName, "packageName");
checkNotNull(callback, "callback");
@@ -237,6 +264,15 @@
callback.sendResult(result);
}
+ private void getRuntimePermissionsBackup(@NonNull UserHandle user,
+ @NonNull ParcelFileDescriptor outFile) {
+ try (OutputStream out = new ParcelFileDescriptor.AutoCloseOutputStream(outFile)) {
+ onGetRuntimePermissionsBackup(user, out);
+ } catch (IOException e) {
+ Log.e(LOG_TAG, "Could not open pipe to write backup tp", e);
+ }
+ }
+
private void getAppPermissions(@NonNull String packageName, @NonNull RemoteCallback callback) {
List<RuntimePermissionPresentationInfo> permissions = onGetAppPermissions(packageName);
if (permissions != null && !permissions.isEmpty()) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 64aa062..757c03e 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7391,6 +7391,14 @@
private static final Validator DOZE_DOUBLE_TAP_GESTURE_VALIDATOR = BOOLEAN_VALIDATOR;
/**
+ * Whether the device should respond to the SLPI tap gesture.
+ * @hide
+ */
+ public static final String DOZE_TAP_SCREEN_GESTURE = "doze_tap_gesture";
+
+ private static final Validator DOZE_TAP_SCREEN_GESTURE_VALIDATOR = BOOLEAN_VALIDATOR;
+
+ /**
* Gesture that wakes up the lock screen.
* @hide
*/
@@ -7407,6 +7415,22 @@
private static final Validator DOZE_WAKE_SCREEN_GESTURE_VALIDATOR = BOOLEAN_VALIDATOR;
/**
+ * Gesture that skips media.
+ * @hide
+ */
+ public static final String SKIP_GESTURE = "skip_gesture";
+
+ private static final Validator SKIP_GESTURE_VALIDATOR = BOOLEAN_VALIDATOR;
+
+ /**
+ * Gesture that silences sound (alarms, notification, calls).
+ * @hide
+ */
+ public static final String SILENCE_GESTURE = "silence_gesture";
+
+ private static final Validator SILENCE_GESTURE_VALIDATOR = BOOLEAN_VALIDATOR;
+
+ /**
* The current night mode that has been selected by the user. Owned
* and controlled by UiModeManagerService. Constants are as per
* UiModeManager.
@@ -7708,6 +7732,23 @@
public static final String TV_INPUT_CUSTOM_LABELS = "tv_input_custom_labels";
/**
+ * Whether TV app uses non-system inputs.
+ *
+ * <p>
+ * The value is boolean (1 or 0), where 1 means non-system TV inputs are allowed,
+ * and 0 means non-system TV inputs are not allowed.
+ *
+ * <p>
+ * Devices such as sound bars may have changed the system property allow_third_party_inputs
+ * to false so the TV Application only uses HDMI and other built in inputs. This setting
+ * allows user to override the default and have the TV Application use third party TV inputs
+ * available on play store.
+ *
+ * @hide
+ */
+ public static final String TV_APP_USES_NON_SYSTEM_INPUTS = "tv_app_uses_non_system_inputs";
+
+ /**
* Whether automatic routing of system audio to USB audio peripheral is disabled.
* The value is boolean (1 or 0), where 1 means automatic routing is disabled,
* and 0 means automatic routing is enabled.
@@ -8445,6 +8486,7 @@
DOZE_ALWAYS_ON,
DOZE_PICK_UP_GESTURE,
DOZE_DOUBLE_TAP_GESTURE,
+ DOZE_TAP_SCREEN_GESTURE,
DOZE_WAKE_LOCK_SCREEN_GESTURE,
DOZE_WAKE_SCREEN_GESTURE,
NFC_PAYMENT_DEFAULT_COMPONENT,
@@ -8483,6 +8525,8 @@
NOTIFICATION_NEW_INTERRUPTION_MODEL,
TRUST_AGENTS_EXTEND_UNLOCK,
LOCK_SCREEN_WHEN_TRUST_LOST,
+ SKIP_GESTURE,
+ SILENCE_GESTURE,
};
/**
@@ -8599,6 +8643,7 @@
VALIDATORS.put(DOZE_ALWAYS_ON, DOZE_ALWAYS_ON_VALIDATOR);
VALIDATORS.put(DOZE_PICK_UP_GESTURE, DOZE_PICK_UP_GESTURE_VALIDATOR);
VALIDATORS.put(DOZE_DOUBLE_TAP_GESTURE, DOZE_DOUBLE_TAP_GESTURE_VALIDATOR);
+ VALIDATORS.put(DOZE_TAP_SCREEN_GESTURE, DOZE_TAP_SCREEN_GESTURE_VALIDATOR);
VALIDATORS.put(DOZE_WAKE_LOCK_SCREEN_GESTURE, DOZE_WAKE_LOCK_SCREEN_GESTURE_VALIDATOR);
VALIDATORS.put(DOZE_WAKE_SCREEN_GESTURE, DOZE_WAKE_SCREEN_GESTURE_VALIDATOR);
VALIDATORS.put(NFC_PAYMENT_DEFAULT_COMPONENT, NFC_PAYMENT_DEFAULT_COMPONENT_VALIDATOR);
@@ -8650,6 +8695,8 @@
VALIDATORS.put(TRUST_AGENTS_EXTEND_UNLOCK, TRUST_AGENTS_EXTEND_UNLOCK_VALIDATOR);
VALIDATORS.put(LOCK_SCREEN_CUSTOM_CLOCK_FACE, LOCK_SCREEN_CUSTOM_CLOCK_FACE_VALIDATOR);
VALIDATORS.put(LOCK_SCREEN_WHEN_TRUST_LOST, LOCK_SCREEN_WHEN_TRUST_LOST_VALIDATOR);
+ VALIDATORS.put(SKIP_GESTURE, SKIP_GESTURE_VALIDATOR);
+ VALIDATORS.put(SILENCE_GESTURE, SILENCE_GESTURE_VALIDATOR);
}
/**
@@ -9361,6 +9408,15 @@
"hdmi_system_audio_control_enabled";
/**
+ * Whether HDMI Routing Control feature is enabled. If enabled, the switch device will
+ * route to the correct input source on receiving Routing Control related messages. If
+ * disabled, you can only switch the input via controls on this device.
+ * @hide
+ */
+ public static final String HDMI_CEC_SWITCH_ENABLED =
+ "hdmi_cec_switch_enabled";
+
+ /**
* Whether TV will automatically turn on upon reception of the CEC command
* <Text View On> or <Image View On>. (0 = false, 1 = true)
*
@@ -11062,6 +11118,31 @@
/** {@hide} */
public static final String
BLUETOOTH_HEARING_AID_PRIORITY_PREFIX = "bluetooth_hearing_aid_priority_";
+ /**
+ * Enable/disable radio bug detection
+ *
+ * {@hide}
+ */
+ public static final String
+ ENABLE_RADIO_BUG_DETECTION = "enable_radio_bug_detection";
+
+ /**
+ * Count threshold of RIL wakelock timeout for radio bug detection
+ *
+ * {@hide}
+ */
+ public static final String
+ RADIO_BUG_WAKELOCK_TIMEOUT_COUNT_THRESHOLD =
+ "radio_bug_wakelock_timeout_count_threshold";
+
+ /**
+ * Count threshold of RIL system error for radio bug detection
+ *
+ * {@hide}
+ */
+ public static final String
+ RADIO_BUG_SYSTEM_ERROR_COUNT_THRESHOLD =
+ "radio_bug_system_error_count_threshold";
/**
* Activity manager specific settings.
@@ -11552,6 +11633,7 @@
* battery_level_collection_delay_ms (long)
* max_history_files (int)
* max_history_buffer_kb (int)
+ * battery_charged_delay_ms (int)
* </pre>
*
* <p>
@@ -11937,22 +12019,33 @@
"angle_gl_driver_selection_values";
/**
- * List of Apps selected to use Game Update Packages.
+ * Game Update Package global preference for all Apps.
+ * 0 = Default
+ * 1 = All Apps use Game Update Package
+ * 2 = All Apps use system graphics driver
+ * @hide
+ */
+ public static final String GUP_DEV_ALL_APPS = "gup_dev_all_apps";
+
+ /**
+ * List of Apps selected to use Game Update Package.
+ * i.e. <pkg1>,<pkg2>,...,<pkgN>
* @hide
*/
public static final String GUP_DEV_OPT_IN_APPS = "gup_dev_opt_in_apps";
/**
- * List of Apps selected not to use Game Update Packages.
+ * List of Apps selected not to use Game Update Package.
+ * i.e. <pkg1>,<pkg2>,...,<pkgN>
* @hide
*/
public static final String GUP_DEV_OPT_OUT_APPS = "gup_dev_opt_out_apps";
/**
- * Apps on the black list that are forbidden to useGame Update Package.
+ * Apps on the blacklist that are forbidden to use Game Update Package.
* @hide
*/
- public static final String GUP_BLACK_LIST = "gup_black_list";
+ public static final String GUP_BLACKLIST = "gup_blacklist";
/**
* Ordered GPU debug layer list for Vulkan
diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
index 0116961..aaba85b 100644
--- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
+++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
@@ -42,6 +42,7 @@
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillValue;
import android.view.autofill.IAugmentedAutofillManagerClient;
+import android.view.autofill.IAutofillWindowPresenter;
import com.android.internal.annotations.GuardedBy;
@@ -95,10 +96,10 @@
}
@Override
- public void onDestroyFillWindowRequest(int sessionId) {
+ public void onDestroyAllFillWindowsRequest() {
mHandler.sendMessage(
- obtainMessage(AugmentedAutofillService::handleOnDestroyFillWindowRequest,
- AugmentedAutofillService.this, sessionId));
+ obtainMessage(AugmentedAutofillService::handleOnDestroyAllFillWindowsRequest,
+ AugmentedAutofillService.this));
}
};
@@ -185,18 +186,21 @@
new FillCallback(proxy));
}
- private void handleOnDestroyFillWindowRequest(@NonNull int sessionId) {
- AutofillProxy proxy = null;
+ private void handleOnDestroyAllFillWindowsRequest() {
if (mAutofillProxies != null) {
- proxy = mAutofillProxies.get(sessionId);
+ final int size = mAutofillProxies.size();
+ for (int i = 0; i < size; i++) {
+ final int sessionId = mAutofillProxies.keyAt(i);
+ final AutofillProxy proxy = mAutofillProxies.valueAt(i);
+ if (proxy == null) {
+ // TODO(b/111330312): this might be fine, in which case we should logv it
+ Log.w(TAG, "No proxy for session " + sessionId);
+ return;
+ }
+ proxy.destroy();
+ }
+ mAutofillProxies.clear();
}
- if (proxy == null) {
- // TODO(b/111330312): this might be fine, in which case we should logv it
- Log.w(TAG, "No proxy for session " + sessionId);
- return;
- }
- proxy.destroy();
- mAutofillProxies.remove(sessionId);
}
private void handleOnUnbind() {
@@ -350,6 +354,16 @@
}
}
+ public void requestShowFillUi(int width, int height, Rect anchorBounds,
+ IAutofillWindowPresenter presenter) throws RemoteException {
+ mClient.requestShowFillUi(mSessionId, mFocusedId, width, height, anchorBounds,
+ presenter);
+ }
+
+ public void requestHideFillUi() throws RemoteException {
+ mClient.requestHideFillUi(mSessionId, mFocusedId);
+ }
+
private void update(@NonNull AutofillId focusedId, @NonNull AutofillValue focusedValue) {
synchronized (mLock) {
// TODO(b/111330312): should we close the popupwindow if the focused id changed?
diff --git a/core/java/android/service/autofill/augmented/FillWindow.java b/core/java/android/service/autofill/augmented/FillWindow.java
index 33b88e42..51b0f01 100644
--- a/core/java/android/service/autofill/augmented/FillWindow.java
+++ b/core/java/android/service/autofill/augmented/FillWindow.java
@@ -16,22 +16,25 @@
package android.service.autofill.augmented;
import static android.service.autofill.augmented.AugmentedAutofillService.DEBUG;
+import static android.service.autofill.augmented.AugmentedAutofillService.VERBOSE;
+
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import android.annotation.LongDef;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.annotation.TestApi;
-import android.app.Dialog;
import android.graphics.Rect;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
import android.service.autofill.augmented.AugmentedAutofillService.AutofillProxy;
import android.service.autofill.augmented.PresentationParams.Area;
import android.util.Log;
-import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
import android.view.WindowManager;
+import android.view.autofill.IAutofillWindowPresenter;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
@@ -71,7 +74,7 @@
/** Indicates the data being shown is a physical address */
public static final long FLAG_METADATA_ADDRESS = 0x1;
- // TODO(b/111330312): add moar flags
+ // TODO(b/111330312): add more flags
/** @hide */
@LongDef(prefix = { "FLAG" }, value = {
@@ -83,8 +86,17 @@
private final Object mLock = new Object();
private final CloseGuard mCloseGuard = CloseGuard.get();
+ private final @NonNull Handler mUiThreadHandler = new Handler(Looper.getMainLooper());
+ private final @NonNull FillWindowPresenter mFillWindowPresenter = new FillWindowPresenter();
+
@GuardedBy("mLock")
- private Dialog mDialog;
+ private WindowManager mWm;
+ @GuardedBy("mLock")
+ private View mFillView;
+ @GuardedBy("mLock")
+ private boolean mShowing;
+ @GuardedBy("mLock")
+ private Rect mBounds;
@GuardedBy("mLock")
private boolean mDestroyed;
@@ -140,51 +152,28 @@
// window instead of destroying. In fact, it might be better to allocate a full window
// initially, which is transparent (and let touches get through) everywhere but in the
// rect boundaries.
- destroy();
// TODO(b/111330312): make sure all touch events are handled, window is always closed,
// etc.
- mDialog = new Dialog(rootView.getContext()) {
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
- FillWindow.this.destroy();
+ mWm = rootView.getContext().getSystemService(WindowManager.class);
+ mFillView = rootView;
+ // Listen to the touch outside to destroy the window when typing is detected.
+ mFillView.setOnTouchListener(
+ (view, motionEvent) -> {
+ if (motionEvent.getAction() == MotionEvent.ACTION_OUTSIDE) {
+ if (VERBOSE) Log.v(TAG, "Outside touch detected, hiding the window");
+ hide();
+ }
+ return false;
}
- return false;
- }
- };
- mCloseGuard.open("destroy");
- final Window window = mDialog.getWindow();
- window.setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
- // Makes sure touch outside the dialog is received by the window behind the dialog.
- window.addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
- // Makes sure the touch outside the dialog is received by the dialog to dismiss it.
- window.addFlags(WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);
- // Makes sure keyboard shows up.
- window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
-
- final int height = rect.bottom - rect.top;
- final int width = rect.right - rect.left;
- final WindowManager.LayoutParams windowParams = window.getAttributes();
- windowParams.gravity = Gravity.TOP | Gravity.LEFT;
- windowParams.y = rect.top + height;
- windowParams.height = height;
- windowParams.x = rect.left;
- windowParams.width = width;
-
- window.setAttributes(windowParams);
- window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
- window.setBackgroundDrawableResource(android.R.color.transparent);
-
- mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
- final ViewGroup.LayoutParams diagParams = new ViewGroup.LayoutParams(width, height);
- mDialog.setContentView(rootView, diagParams);
-
+ );
+ mShowing = false;
+ mBounds = new Rect(area.getBounds());
if (DEBUG) {
Log.d(TAG, "Created FillWindow: params= " + smartSuggestion + " view=" + rootView);
}
-
+ mDestroyed = false;
mProxy.setFillWindow(this);
return true;
}
@@ -194,36 +183,87 @@
void show() {
// TODO(b/111330312): check if updated first / throw exception
if (DEBUG) Log.d(TAG, "show()");
-
synchronized (mLock) {
checkNotDestroyedLocked();
- if (mDialog == null) {
+ if (mWm == null || mFillView == null) {
throw new IllegalStateException("update() not called yet, or already destroyed()");
}
-
- mDialog.show();
if (mProxy != null) {
+ try {
+ mProxy.requestShowFillUi(mBounds.right - mBounds.left,
+ mBounds.bottom - mBounds.top,
+ /*anchorBounds=*/ null, mFillWindowPresenter);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Error requesting to show fill window", e);
+ }
mProxy.report(AutofillProxy.REPORT_EVENT_UI_SHOWN);
}
}
}
/**
+ * Hides the window.
+ *
+ * <p>The window is not destroyed and can be shown again
+ */
+ private void hide() {
+ if (DEBUG) Log.d(TAG, "hide()");
+ synchronized (mLock) {
+ checkNotDestroyedLocked();
+ if (mWm == null || mFillView == null) {
+ throw new IllegalStateException("update() not called yet, or already destroyed()");
+ }
+ if (mProxy != null && mShowing) {
+ try {
+ mProxy.requestHideFillUi();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Error requesting to hide fill window", e);
+ }
+ }
+ }
+ }
+
+ private void handleShow(WindowManager.LayoutParams p) {
+ if (DEBUG) Log.d(TAG, "handleShow()");
+ synchronized (mLock) {
+ if (mWm != null && mFillView != null) {
+ p.flags |= WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
+ if (!mShowing) {
+ mWm.addView(mFillView, p);
+ mShowing = true;
+ } else {
+ mWm.updateViewLayout(mFillView, p);
+ }
+ }
+ }
+ }
+
+ private void handleHide() {
+ if (DEBUG) Log.d(TAG, "handleHide()");
+ synchronized (mLock) {
+ if (mWm != null && mFillView != null && mShowing) {
+ mWm.removeView(mFillView);
+ mShowing = false;
+ }
+ }
+ }
+
+ /**
* Destroys the window.
*
* <p>Once destroyed, this window cannot be used anymore
*/
public void destroy() {
- if (DEBUG) Log.d(TAG, "destroy(): mDestroyed=" + mDestroyed + " mDialog=" + mDialog);
-
- synchronized (this) {
- if (mDestroyed || mDialog == null) return;
-
- mDialog.dismiss();
- mDialog = null;
- if (mProxy != null) {
- mProxy.report(AutofillProxy.REPORT_EVENT_UI_DESTROYED);
- }
+ if (DEBUG) {
+ Log.d(TAG,
+ "destroy(): mDestroyed=" + mDestroyed + " mShowing=" + mShowing + " mFillView="
+ + mFillView);
+ }
+ synchronized (mLock) {
+ if (mDestroyed) return;
+ hide();
+ mProxy.report(AutofillProxy.REPORT_EVENT_UI_DESTROYED);
+ mDestroyed = true;
mCloseGuard.close();
}
}
@@ -250,11 +290,15 @@
public void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
synchronized (this) {
pw.print(prefix); pw.print("destroyed: "); pw.println(mDestroyed);
- if (mDialog != null) {
- pw.print(prefix); pw.print("dialog: ");
- pw.println(mDialog.isShowing() ? "shown" : "hidden");
- pw.print(prefix); pw.print("window: ");
- pw.println(mDialog.getWindow().getAttributes());
+ if (mFillView != null) {
+ pw.print(prefix); pw.print("fill window: ");
+ pw.println(mShowing ? "shown" : "hidden");
+ pw.print(prefix); pw.print("fill view: ");
+ pw.println(mFillView);
+ pw.print(prefix); pw.print("mBounds: ");
+ pw.println(mBounds);
+ pw.print(prefix); pw.print("mWm: ");
+ pw.println(mWm);
}
}
}
@@ -264,4 +308,19 @@
public void close() throws Exception {
destroy();
}
+
+ private final class FillWindowPresenter extends IAutofillWindowPresenter.Stub {
+ @Override
+ public void show(WindowManager.LayoutParams p, Rect transitionEpicenter,
+ boolean fitsSystemWindows, int layoutDirection) {
+ if (DEBUG) Log.d(TAG, "FillWindowPresenter.show()");
+ mUiThreadHandler.sendMessage(obtainMessage(FillWindow::handleShow, FillWindow.this, p));
+ }
+
+ @Override
+ public void hide(Rect transitionEpicenter) {
+ if (DEBUG) Log.d(TAG, "FillWindowPresenter.hide()");
+ mUiThreadHandler.sendMessage(obtainMessage(FillWindow::handleHide, FillWindow.this));
+ }
+ }
}
diff --git a/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl b/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl
index b3ac2da1..fb6912a 100644
--- a/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl
+++ b/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl
@@ -36,5 +36,5 @@
in ComponentName activityComponent, in AutofillId focusedId,
in AutofillValue focusedValue, long requestTime, in IFillCallback callback);
- void onDestroyFillWindowRequest(int sessionId);
+ void onDestroyAllFillWindowsRequest();
}
diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java
index e5e028d..302e1a6 100644
--- a/core/java/android/service/contentcapture/ContentCaptureService.java
+++ b/core/java/android/service/contentcapture/ContentCaptureService.java
@@ -48,6 +48,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.Collections;
import java.util.List;
import java.util.Set;
@@ -77,6 +78,7 @@
"android.service.contentcapture.ContentCaptureService";
private Handler mHandler;
+ private IContentCaptureServiceCallback mCallback;
/**
* Binder that receives calls from the system server.
@@ -84,9 +86,15 @@
private final IContentCaptureService mServerInterface = new IContentCaptureService.Stub() {
@Override
- public void onConnectedStateChanged(boolean state) {
- mHandler.sendMessage(obtainMessage(ContentCaptureService::handleOnConnectedStateChanged,
- ContentCaptureService.this, state));
+ public void onConnected(IBinder callback) {
+ mHandler.sendMessage(obtainMessage(ContentCaptureService::handleOnConnected,
+ ContentCaptureService.this, callback));
+ }
+
+ @Override
+ public void onDisconnected() {
+ mHandler.sendMessage(obtainMessage(ContentCaptureService::handleOnDisconnected,
+ ContentCaptureService.this));
}
@Override
@@ -166,7 +174,16 @@
*/
public final void setContentCaptureWhitelist(@Nullable List<String> packages,
@Nullable List<ComponentName> activities) {
- //TODO(b/122595322): implement
+ final IContentCaptureServiceCallback callback = mCallback;
+ if (callback == null) {
+ Log.w(TAG, "setContentCaptureWhitelist(): no server callback");
+ return;
+ }
+ try {
+ callback.setContentCaptureWhitelist(packages, activities);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
}
/**
@@ -177,7 +194,16 @@
*/
public final void setActivityContentCaptureEnabled(@NonNull ComponentName activity,
boolean enabled) {
- //TODO(b/122595322): implement
+ final IContentCaptureServiceCallback callback = mCallback;
+ if (callback == null) {
+ Log.w(TAG, "setActivityContentCaptureEnabled(): no server callback");
+ return;
+ }
+ try {
+ callback.setActivityContentCaptureEnabled(activity, enabled);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
}
/**
@@ -188,7 +214,16 @@
*/
public final void setPackageContentCaptureEnabled(@NonNull String packageName,
boolean enabled) {
- //TODO(b/122595322): implement
+ final IContentCaptureServiceCallback callback = mCallback;
+ if (callback == null) {
+ Log.w(TAG, "setPackageContentCaptureEnabled(): no server callback");
+ return;
+ }
+ try {
+ callback.setPackageContentCaptureEnabled(packageName, enabled);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
}
/**
@@ -197,7 +232,12 @@
*/
@NonNull
public final Set<ComponentName> getContentCaptureDisabledActivities() {
- //TODO(b/122595322): implement
+ final IContentCaptureServiceCallback callback = mCallback;
+ if (callback == null) {
+ Log.w(TAG, "getContentCaptureDisabledActivities(): no server callback");
+ return Collections.emptySet();
+ }
+ //TODO(b/122595322): implement (using SyncResultReceiver)
return null;
}
@@ -207,7 +247,12 @@
*/
@NonNull
public final Set<String> getContentCaptureDisabledPackages() {
- //TODO(b/122595322): implement
+ final IContentCaptureServiceCallback callback = mCallback;
+ if (callback == null) {
+ Log.w(TAG, "getContentCaptureDisabledPackages(): no server callback");
+ return Collections.emptySet();
+ }
+ //TODO(b/122595322): implement (using SyncResultReceiver)
return null;
}
@@ -307,12 +352,14 @@
}
}
- private void handleOnConnectedStateChanged(boolean state) {
- if (state) {
- onConnected();
- } else {
- onDisconnected();
- }
+ private void handleOnConnected(@NonNull IBinder callback) {
+ mCallback = IContentCaptureServiceCallback.Stub.asInterface(callback);
+ onConnected();
+ }
+
+ private void handleOnDisconnected() {
+ onDisconnected();
+ mCallback = null;
}
//TODO(b/111276913): consider caching the InteractionSessionId for the lifetime of the session,
@@ -323,15 +370,21 @@
mSessionUids.put(sessionId, uid);
onCreateContentCaptureSession(context, new ContentCaptureSessionId(sessionId));
- final int flags = context.getFlags();
- if ((flags & ContentCaptureContext.FLAG_DISABLED_BY_FLAG_SECURE) != 0) {
- setClientState(clientReceiver, ContentCaptureSession.STATE_DISABLED_BY_FLAG_SECURE,
- mClientInterface.asBinder());
- return;
+ final int clientFlags = context.getFlags();
+ int stateFlags = 0;
+ if ((clientFlags & ContentCaptureContext.FLAG_DISABLED_BY_FLAG_SECURE) != 0) {
+ stateFlags |= ContentCaptureSession.STATE_FLAG_SECURE;
}
+ if ((clientFlags & ContentCaptureContext.FLAG_DISABLED_BY_APP) != 0) {
+ stateFlags |= ContentCaptureSession.STATE_BY_APP;
+ }
+ if (stateFlags == 0) {
+ stateFlags = ContentCaptureSession.STATE_ACTIVE;
+ } else {
+ stateFlags |= ContentCaptureSession.STATE_DISABLED;
- setClientState(clientReceiver, ContentCaptureSession.STATE_ACTIVE,
- mClientInterface.asBinder());
+ }
+ setClientState(clientReceiver, stateFlags, mClientInterface.asBinder());
}
private void handleSendEvents(int uid,
diff --git a/core/java/android/service/contentcapture/IContentCaptureService.aidl b/core/java/android/service/contentcapture/IContentCaptureService.aidl
index 1b4cccf..a8dd213 100644
--- a/core/java/android/service/contentcapture/IContentCaptureService.aidl
+++ b/core/java/android/service/contentcapture/IContentCaptureService.aidl
@@ -16,6 +16,7 @@
package android.service.contentcapture;
+import android.os.IBinder;
import android.service.contentcapture.SnapshotData;
import android.view.contentcapture.ContentCaptureContext;
@@ -29,7 +30,8 @@
* @hide
*/
oneway interface IContentCaptureService {
- void onConnectedStateChanged(boolean state);
+ void onConnected(IBinder callback);
+ void onDisconnected();
void onSessionStarted(in ContentCaptureContext context, String sessionId, int uid,
in IResultReceiver clientReceiver);
void onSessionFinished(String sessionId);
diff --git a/core/java/android/service/contentcapture/IContentCaptureServiceCallback.aidl b/core/java/android/service/contentcapture/IContentCaptureServiceCallback.aidl
new file mode 100644
index 0000000..e84bd6f
--- /dev/null
+++ b/core/java/android/service/contentcapture/IContentCaptureServiceCallback.aidl
@@ -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.service.contentcapture;
+
+import android.content.ComponentName;
+import com.android.internal.os.IResultReceiver;
+
+import java.util.List;
+
+/**
+ * Interface from the Content Capture service to the system.
+ *
+ * @hide
+ */
+oneway interface IContentCaptureServiceCallback {
+ void setContentCaptureWhitelist(in List<String> packages, in List<ComponentName> activities);
+ void setActivityContentCaptureEnabled(in ComponentName activity, boolean enabled);
+ void setPackageContentCaptureEnabled(in String packageName, boolean enabled);
+ void getContentCaptureDisabledActivities(in IResultReceiver receiver);
+ void getContentCaptureDisabledPackages(in IResultReceiver receiver);
+}
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 85b6b88..44353b1 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -33,8 +33,7 @@
import android.icu.util.ULocale;
import android.os.Parcel;
import android.os.Parcelable;
-import android.os.SystemProperties;
-import android.provider.Settings;
+import android.sysprop.DisplayProperties;
import android.text.style.AbsoluteSizeSpan;
import android.text.style.AccessibilityClickableSpan;
import android.text.style.AccessibilityURLSpan;
@@ -2059,7 +2058,7 @@
return ((locale != null && !locale.equals(Locale.ROOT)
&& ULocale.forLocale(locale).isRightToLeft())
// If forcing into RTL layout mode, return RTL as default
- || SystemProperties.getBoolean(Settings.Global.DEVELOPMENT_FORCE_RTL, false))
+ || DisplayProperties.debug_force_rtl().orElse(false))
? View.LAYOUT_DIRECTION_RTL
: View.LAYOUT_DIRECTION_LTR;
}
diff --git a/core/java/android/util/TypedValue.java b/core/java/android/util/TypedValue.java
index ea4464d..99106be 100644
--- a/core/java/android/util/TypedValue.java
+++ b/core/java/android/util/TypedValue.java
@@ -216,6 +216,12 @@
* */
public int density;
+ /**
+ * If the Value came from a style resource, this holds the corresponding style resource id
+ * against which the attribute was resolved.
+ */
+ public int sourceStyleResourceId;
+
/* ------------------------------------------------------------ */
/** Return the data for this value as a float. Only use for values
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index abefd55..32974ac 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -76,8 +76,8 @@
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.SystemClock;
-import android.os.SystemProperties;
import android.os.Trace;
+import android.sysprop.DisplayProperties;
import android.text.InputType;
import android.text.TextUtils;
import android.util.AttributeSet;
@@ -812,14 +812,6 @@
private static final String CONTENT_CAPTURE_LOG_TAG = "View.ContentCapture";
/**
- * When set to true, apps will draw debugging information about their layouts.
- *
- * @hide
- */
- @UnsupportedAppUsage
- public static final String DEBUG_LAYOUT_PROPERTY = "debug.layout";
-
- /**
* When set to true, this view will save its attribute data.
*
* @hide
@@ -27833,7 +27825,7 @@
/**
* Show where the margins, bounds and layout bounds are for each view.
*/
- boolean mDebugLayout = SystemProperties.getBoolean(DEBUG_LAYOUT_PROPERTY, false);
+ boolean mDebugLayout = DisplayProperties.debug_layout().orElse(false);
/**
* Point used to compute visible regions.
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 8e4dc67..27d4ea4 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -75,6 +75,7 @@
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.Trace;
+import android.sysprop.DisplayProperties;
import android.util.AndroidRuntimeException;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -7071,7 +7072,7 @@
}
// Layout debugging
- boolean layout = SystemProperties.getBoolean(View.DEBUG_LAYOUT_PROPERTY, false);
+ boolean layout = DisplayProperties.debug_layout().orElse(false);
if (layout != mAttachInfo.mDebugLayout) {
mAttachInfo.mDebugLayout = layout;
if (!mHandler.hasMessages(MSG_INVALIDATE_WORLD)) {
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index c630177..dfd9a2e 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -187,6 +187,7 @@
/**
* An animation listener to be notified when the animation starts, ends or repeats.
*/
+ @UnsupportedAppUsage
private AnimationListener mListener;
/**
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 93941d0..888a4c5 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -2997,5 +2997,23 @@
afm.post(() -> afm.autofill(sessionId, ids, values));
}
}
+
+ @Override
+ public void requestShowFillUi(int sessionId, AutofillId id, int width, int height,
+ Rect anchorBounds, IAutofillWindowPresenter presenter) {
+ final AutofillManager afm = mAfm.get();
+ if (afm != null) {
+ afm.post(() -> afm.requestShowFillUi(sessionId, id, width, height, anchorBounds,
+ presenter));
+ }
+ }
+
+ @Override
+ public void requestHideFillUi(int sessionId, AutofillId id) {
+ final AutofillManager afm = mAfm.get();
+ if (afm != null) {
+ afm.post(() -> afm.requestHideFillUi(id, false));
+ }
+ }
}
}
diff --git a/core/java/android/view/autofill/IAugmentedAutofillManagerClient.aidl b/core/java/android/view/autofill/IAugmentedAutofillManagerClient.aidl
index 67cd0bf..140507c 100644
--- a/core/java/android/view/autofill/IAugmentedAutofillManagerClient.aidl
+++ b/core/java/android/view/autofill/IAugmentedAutofillManagerClient.aidl
@@ -21,6 +21,7 @@
import android.graphics.Rect;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillValue;
+import android.view.autofill.IAutofillWindowPresenter;
/**
* Object running in the application process and responsible to provide the functionalities
@@ -29,6 +30,24 @@
* @hide
*/
interface IAugmentedAutofillManagerClient {
- Rect getViewCoordinates(in AutofillId id);
- void autofill(int sessionId, in List<AutofillId> ids, in List<AutofillValue> values);
+ /**
+ * Gets the coordinates of the input field view.
+ */
+ Rect getViewCoordinates(in AutofillId id);
+
+ /**
+ * Autofills the activity with the contents of the values.
+ */
+ void autofill(int sessionId, in List<AutofillId> ids, in List<AutofillValue> values);
+
+ /**
+ * Requests showing the fill UI.
+ */
+ void requestShowFillUi(int sessionId, in AutofillId id, int width, int height,
+ in Rect anchorBounds, in IAutofillWindowPresenter presenter);
+
+ /**
+ * Requests hiding the fill UI.
+ */
+ void requestHideFillUi(int sessionId, in AutofillId id);
}
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index ff45efd..81b2e01 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -29,12 +29,12 @@
import android.os.RemoteException;
import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.IResultReceiver;
import com.android.internal.util.Preconditions;
import com.android.internal.util.SyncResultReceiver;
import java.io.PrintWriter;
-import java.util.concurrent.atomic.AtomicBoolean;
/*
* NOTE: all methods in this class should return right away, or do the real work in a handler
@@ -62,8 +62,10 @@
static final boolean VERBOSE = false;
static final boolean DEBUG = true; // STOPSHIP if not set to false
- @NonNull
- private final AtomicBoolean mDisabled = new AtomicBoolean();
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private boolean mDisabled;
@NonNull
private final Context mContext;
@@ -71,11 +73,16 @@
@Nullable
private final IContentCaptureManager mService;
+ // Flags used for starting session.
+ @GuardedBy("mLock")
+ private int mFlags;
+
// TODO(b/119220549): use UI Thread directly (as calls are one-way) or a shared thread / handler
// held at the Application level
@NonNull
private final Handler mHandler;
+ @GuardedBy("mLock")
private MainContentCaptureSession mMainSession;
/** @hide */
@@ -114,20 +121,25 @@
@NonNull
@UiThread
public MainContentCaptureSession getMainContentCaptureSession() {
- if (mMainSession == null) {
- mMainSession = new MainContentCaptureSession(mContext, mHandler, mService,
- mDisabled);
- if (VERBOSE) {
- Log.v(TAG, "getDefaultContentCaptureSession(): created " + mMainSession);
+ synchronized (mLock) {
+ if (mMainSession == null) {
+ mMainSession = new MainContentCaptureSession(mContext, mHandler, mService,
+ mDisabled);
+ if (VERBOSE) {
+ Log.v(TAG, "getDefaultContentCaptureSession(): created " + mMainSession);
+ }
}
+ return mMainSession;
}
- return mMainSession;
}
/** @hide */
public void onActivityStarted(@NonNull IBinder applicationToken,
@NonNull ComponentName activityComponent, int flags) {
- getMainContentCaptureSession().start(applicationToken, activityComponent, flags);
+ synchronized (mLock) {
+ mFlags |= flags;
+ getMainContentCaptureSession().start(applicationToken, activityComponent, mFlags);
+ }
}
/** @hide */
@@ -173,7 +185,9 @@
* Checks whether content capture is enabled for this activity.
*/
public boolean isContentCaptureEnabled() {
- return mService != null && !mDisabled.get();
+ synchronized (mLock) {
+ return mService != null && !mDisabled;
+ }
}
/**
@@ -183,7 +197,9 @@
* it on {@link android.app.Activity#onCreate(android.os.Bundle, android.os.PersistableBundle)}.
*/
public void setContentCaptureEnabled(boolean enabled) {
- //TODO(b/111276913): implement (need to finish / disable all sessions)
+ synchronized (mLock) {
+ mFlags |= enabled ? 0 : ContentCaptureContext.FLAG_DISABLED_BY_APP;
+ }
}
/**
@@ -198,20 +214,22 @@
/** @hide */
public void dump(String prefix, PrintWriter pw) {
- pw.print(prefix); pw.println("ContentCaptureManager");
-
- pw.print(prefix); pw.print("Disabled: "); pw.println(mDisabled.get());
- pw.print(prefix); pw.print("Context: "); pw.println(mContext);
- pw.print(prefix); pw.print("User: "); pw.println(mContext.getUserId());
- if (mService != null) {
- pw.print(prefix); pw.print("Service: "); pw.println(mService);
- }
- if (mMainSession != null) {
- final String prefix2 = prefix + " ";
- pw.print(prefix); pw.println("Main session:");
- mMainSession.dump(prefix2, pw);
- } else {
- pw.print(prefix); pw.println("No sessions");
+ synchronized (mLock) {
+ pw.print(prefix); pw.println("ContentCaptureManager");
+ pw.print(prefix); pw.print("Disabled: "); pw.println(mDisabled);
+ pw.print(prefix); pw.print("Context: "); pw.println(mContext);
+ pw.print(prefix); pw.print("User: "); pw.println(mContext.getUserId());
+ if (mService != null) {
+ pw.print(prefix); pw.print("Service: "); pw.println(mService);
+ }
+ pw.print(prefix); pw.print("Flags: "); pw.println(mFlags);
+ if (mMainSession != null) {
+ final String prefix2 = prefix + " ";
+ pw.print(prefix); pw.println("Main session:");
+ mMainSession.dump(prefix2, pw);
+ } else {
+ pw.print(prefix); pw.println("No sessions");
+ }
}
}
diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java
index d9a8416..7bfc5b4 100644
--- a/core/java/android/view/contentcapture/ContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ContentCaptureSession.java
@@ -21,6 +21,7 @@
import android.annotation.CallSuper;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.util.DebugUtils;
import android.util.Log;
import android.view.View;
import android.view.ViewStructure;
@@ -56,42 +57,71 @@
*
* @hide
*/
- public static final int STATE_UNKNOWN = 0;
+ // NOTE: not prefixed by STATE_ so it's not printed on getStateAsString()
+ public static final int UNKNWON_STATE = 0x0;
/**
* Service's startSession() was called, but server didn't confirm it was created yet.
*
* @hide
*/
- public static final int STATE_WAITING_FOR_SERVER = 1;
+ public static final int STATE_WAITING_FOR_SERVER = 0x1;
/**
* Session is active.
*
* @hide
*/
- public static final int STATE_ACTIVE = 2;
+ public static final int STATE_ACTIVE = 0x2;
/**
* Session is disabled because there is no service for this user.
*
* @hide
*/
- public static final int STATE_DISABLED_NO_SERVICE = 3;
+ public static final int STATE_DISABLED = 0x4;
/**
* Session is disabled because its id already existed on server.
*
* @hide
*/
- public static final int STATE_DISABLED_DUPLICATED_ID = 4;
+ public static final int STATE_DUPLICATED_ID = 0x8;
+
+ /**
+ * Session is disabled because service is not set for user.
+ *
+ * @hide
+ */
+ public static final int STATE_NO_SERVICE = 0x10;
/**
* Session is disabled by FLAG_SECURE
*
* @hide
*/
- public static final int STATE_DISABLED_BY_FLAG_SECURE = 5;
+ public static final int STATE_FLAG_SECURE = 0x20;
+
+ /**
+ * Session is disabled manually by the specific app.
+ *
+ * @hide
+ */
+ public static final int STATE_BY_APP = 0x40;
+
+ /**
+ * Session is disabled because session start was never replied.
+ *
+ * @hide
+ */
+ public static final int STATE_NO_RESPONSE = 0x80;
+
+ /**
+ * Session is disabled because an internal error.
+ *
+ * @hide
+ */
+ public static final int STATE_INTERNAL_ERROR = 0x100;
private static final int INITIAL_CHILDREN_CAPACITY = 5;
@@ -110,7 +140,7 @@
@Nullable
protected final String mId;
- private int mState = STATE_UNKNOWN;
+ private int mState = UNKNWON_STATE;
// Lazily created on demand.
private ContentCaptureSessionId mContentCaptureSessionId;
@@ -382,21 +412,7 @@
*/
@NonNull
protected static String getStateAsString(int state) {
- switch (state) {
- case STATE_UNKNOWN:
- return "UNKNOWN";
- case STATE_WAITING_FOR_SERVER:
- return "WAITING_FOR_SERVER";
- case STATE_ACTIVE:
- return "ACTIVE";
- case STATE_DISABLED_NO_SERVICE:
- return "DISABLED_NO_SERVICE";
- case STATE_DISABLED_DUPLICATED_ID:
- return "DISABLED_DUPLICATED_ID";
- case STATE_DISABLED_BY_FLAG_SECURE:
- return "DISABLED_FLAG_SECURE";
- default:
- return "INVALID:" + state;
- }
+ return state + " (" + (state == UNKNWON_STATE ? "UNKNOWN"
+ : DebugUtils.flagsToString(ContentCaptureSession.class, "STATE_", state)) + ")";
}
}
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index a29aaf0..a3ff8c0 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -88,6 +88,7 @@
*/
public static final String EXTRA_BINDER = "binder";
+ // TODO(b/111276913): make sure disabled state is in sync with manager's disabled
@NonNull
private final AtomicBoolean mDisabled;
@@ -113,7 +114,7 @@
@Nullable
private DeathRecipient mDirectServiceVulture;
- private int mState = STATE_UNKNOWN;
+ private int mState = UNKNWON_STATE;
@Nullable
private IBinder mApplicationToken;
@@ -133,11 +134,11 @@
/** @hide */
protected MainContentCaptureSession(@NonNull Context context, @NonNull Handler handler,
@Nullable IContentCaptureManager systemServerInterface,
- @NonNull AtomicBoolean disabled) {
+ @NonNull boolean disabled) {
mContext = context;
mHandler = handler;
mSystemServerInterface = systemServerInterface;
- mDisabled = disabled;
+ mDisabled = new AtomicBoolean(disabled);
}
@Override
@@ -184,10 +185,13 @@
private void handleStartSession(@NonNull IBinder token, @NonNull ComponentName componentName,
int flags) {
- if (mState != STATE_UNKNOWN) {
- // TODO(b/111276913): revisit this scenario
- Log.w(TAG, "ignoring handleStartSession(" + token + ") while on state "
- + getStateAsString(mState));
+ if (handleHasStarted()) {
+ // TODO(b/122959591): make sure this is expected (and when), or use Log.w
+ if (DEBUG) {
+ Log.d(TAG, "ignoring handleStartSession(" + token + "/"
+ + ComponentName.flattenToShortString(componentName) + " while on state "
+ + getStateAsString(mState));
+ }
return;
}
mState = STATE_WAITING_FOR_SERVER;
@@ -196,7 +200,7 @@
if (VERBOSE) {
Log.v(TAG, "handleStartSession(): token=" + token + ", act="
- + getActivityDebugName() + ", id=" + mId);
+ + getDebugState() + ", id=" + mId);
}
try {
@@ -211,7 +215,7 @@
binder = resultData.getBinder(EXTRA_BINDER);
if (binder == null) {
Log.wtf(TAG, "No " + EXTRA_BINDER + " extra result");
- handleResetState();
+ handleResetSession(STATE_DISABLED | STATE_INTERNAL_ERROR);
return;
}
}
@@ -233,7 +237,6 @@
* @param binder handle to {@code IContentCaptureDirectManager}
*/
private void handleSessionStarted(int resultCode, @Nullable IBinder binder) {
- mState = resultCode;
if (binder != null) {
mDirectServiceInterface = IContentCaptureDirectManager.Stub.asInterface(binder);
mDirectServiceVulture = () -> {
@@ -247,26 +250,33 @@
}
}
- // TODO(b/111276913): change the resultCode to use flags so there's just one flag for
- // disabled stuff
- if (resultCode == STATE_DISABLED_NO_SERVICE || resultCode == STATE_DISABLED_DUPLICATED_ID
- || resultCode == STATE_DISABLED_BY_FLAG_SECURE) {
- mDisabled.set(true);
- handleResetSession(/* resetState= */ false);
+ if ((resultCode & STATE_DISABLED) != 0) {
+ handleResetSession(resultCode);
} else {
+ mState = resultCode;
mDisabled.set(false);
}
if (VERBOSE) {
- Log.v(TAG, "handleSessionStarted() result: code=" + resultCode + ", id=" + mId
+ Log.v(TAG, "handleSessionStarted() result: id=" + mId + " resultCode=" + resultCode
+ ", state=" + getStateAsString(mState) + ", disabled=" + mDisabled.get()
+ ", binder=" + binder + ", events=" + (mEvents == null ? 0 : mEvents.size()));
}
}
private void handleSendEvent(@NonNull ContentCaptureEvent event, boolean forceFlush) {
+ if (!handleHasStarted()
+ && event.getType() != ContentCaptureEvent.TYPE_SESSION_STARTED) {
+ // TODO(b/120494182): comment when this could happen (dialogs?)
+ Log.v(TAG, "handleSendEvent(" + getDebugState() + ", "
+ + ContentCaptureEvent.getTypeAsString(event.getType())
+ + "): session not started yet");
+ return;
+ }
if (mEvents == null) {
if (VERBOSE) {
- Log.v(TAG, "Creating buffer for " + MAX_BUFFER_SIZE + " events");
+ Log.v(TAG, "handleSendEvent(" + getDebugState() + ", "
+ + ContentCaptureEvent.getTypeAsString(event.getType())
+ + "): cCreating buffer for " + MAX_BUFFER_SIZE + " events");
}
mEvents = new ArrayList<>(MAX_BUFFER_SIZE);
}
@@ -301,15 +311,14 @@
if (mState != STATE_ACTIVE && numberEvents >= MAX_BUFFER_SIZE) {
// Callback from startSession hasn't been called yet - typically happens on system
// apps that are started before the system service
- // TODO(b/111276913): try to ignore session while system is not ready / boot
+ // TODO(b/122959591): try to ignore session while system is not ready / boot
// not complete instead. Similarly, the manager service should return right away
// when the user does not have a service set
if (DEBUG) {
- Log.d(TAG, "Closing session for " + getActivityDebugName()
- + " after " + numberEvents + " delayed events and state "
- + getStateAsString(mState));
+ Log.d(TAG, "Closing session for " + getDebugState()
+ + " after " + numberEvents + " delayed events");
}
- handleResetState();
+ handleResetSession(STATE_DISABLED | STATE_NO_RESPONSE);
// TODO(b/111276913): blacklist activity / use special flag to indicate that
// when it's launched again
return;
@@ -318,14 +327,23 @@
handleForceFlush();
}
+ private boolean handleHasStarted() {
+ return mState != UNKNWON_STATE;
+ }
+
private void handleScheduleFlush(boolean checkExisting) {
+ if (!handleHasStarted()) {
+ Log.v(TAG, "handleScheduleFlush(" + getDebugState() + "): session not started yet");
+ return;
+ }
if (checkExisting && mHandler.hasMessages(MSG_FLUSH)) {
// "Renew" the flush message by removing the previous one
mHandler.removeMessages(MSG_FLUSH);
}
mNextFlush = SystemClock.elapsedRealtime() + FLUSHING_FREQUENCY_MS;
if (VERBOSE) {
- Log.v(TAG, "Scheduled to flush in " + FLUSHING_FREQUENCY_MS + "ms: " + mNextFlush);
+ Log.v(TAG, "handleScheduleFlush(" + getDebugState() + "): scheduled to flush in "
+ + FLUSHING_FREQUENCY_MS + "ms: " + TimeUtils.formatUptime(mNextFlush));
}
mHandler.sendMessageDelayed(
obtainMessage(MainContentCaptureSession::handleFlushIfNeeded, this)
@@ -345,7 +363,8 @@
if (mDirectServiceInterface == null) {
if (VERBOSE) {
- Log.v(TAG, "handleForceFlush(): hold your horses, client not ready: " + mEvents);
+ Log.v(TAG, "handleForceFlush(" + getDebugState()
+ + "): hold your horses, client not ready: " + mEvents);
}
if (!mHandler.hasMessages(MSG_FLUSH)) {
handleScheduleFlush(/* checkExisting= */ false);
@@ -356,14 +375,14 @@
final int numberEvents = mEvents.size();
try {
if (DEBUG) {
- Log.d(TAG, "Flushing " + numberEvents + " event(s) for " + getActivityDebugName());
+ Log.d(TAG, "Flushing " + numberEvents + " event(s) for " + getDebugState());
}
mHandler.removeMessages(MSG_FLUSH);
final ParceledListSlice<ContentCaptureEvent> events = handleClearEvents();
mDirectServiceInterface.sendEvents(events);
} catch (RemoteException e) {
- Log.w(TAG, "Error sending " + numberEvents + " for " + getActivityDebugName()
+ Log.w(TAG, "Error sending " + numberEvents + " for " + getDebugState()
+ ": " + e);
}
}
@@ -386,7 +405,7 @@
if (DEBUG) {
Log.d(TAG, "Destroying session (ctx=" + mContext + ", id=" + mId + ") with "
+ (mEvents == null ? 0 : mEvents.size()) + " event(s) for "
- + getActivityDebugName());
+ + getDebugState());
}
try {
@@ -395,21 +414,19 @@
mSystemServerInterface.finishSession(mContext.getUserId(), mId);
} catch (RemoteException e) {
Log.e(TAG, "Error destroying system-service session " + mId + " for "
- + getActivityDebugName() + ": " + e);
+ + getDebugState() + ": " + e);
}
}
- private void handleResetState() {
- handleResetSession(/* resetState= */ true);
- }
-
// TODO(b/122454205): once we support multiple sessions, we might need to move some of these
// clearings out.
- private void handleResetSession(boolean resetState) {
- if (resetState) {
- mState = STATE_UNKNOWN;
+ private void handleResetSession(int newState) {
+ if (VERBOSE) {
+ Log.v(TAG, "handleResetSession(" + getActivityName() + "): from "
+ + getStateAsString(mState) + " to " + getStateAsString(newState));
}
-
+ mState = newState;
+ mDisabled.set((newState & STATE_DISABLED) != 0);
// TODO(b/122454205): must reset children (which currently is owned by superclass)
mApplicationToken = null;
mComponentName = null;
@@ -496,8 +513,7 @@
}
pw.print(prefix); pw.print("mDisabled: "); pw.println(mDisabled.get());
pw.print(prefix); pw.print("isEnabled(): "); pw.println(isContentCaptureEnabled());
- pw.print(prefix); pw.print("state: "); pw.print(mState); pw.print(" (");
- pw.print(getStateAsString(mState)); pw.println(")");
+ pw.print(prefix); pw.print("state: "); pw.println(getStateAsString(mState));
if (mApplicationToken != null) {
pw.print(prefix); pw.print("app token: "); pw.println(mApplicationToken);
}
@@ -527,8 +543,13 @@
/**
* Gets a string that can be used to identify the activity on logging statements.
*/
- private String getActivityDebugName() {
- return mComponentName == null ? mContext.getPackageName()
- : mComponentName.flattenToShortString();
+ private String getActivityName() {
+ return mComponentName == null
+ ? "pkg:" + mContext.getPackageName()
+ : "act:" + mComponentName.flattenToShortString();
+ }
+
+ private String getDebugState() {
+ return getActivityName() + " (state=" + getStateAsString(mState) + ")";
}
}
diff --git a/core/java/android/view/inspector/InspectableProperty.java b/core/java/android/view/inspector/InspectableProperty.java
index 5b957156..e2a763e 100644
--- a/core/java/android/view/inspector/InspectableProperty.java
+++ b/core/java/android/view/inspector/InspectableProperty.java
@@ -105,7 +105,6 @@
/**
* One entry in an enumeration packed into a primitive {int}.
*
- * @see IntEnumMapping
* @hide
*/
@Target({TYPE})
diff --git a/core/java/android/view/inspector/IntEnumMapping.java b/core/java/android/view/inspector/IntEnumMapping.java
deleted file mode 100644
index 69f6dce..0000000
--- a/core/java/android/view/inspector/IntEnumMapping.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.view.inspector;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-
-import java.util.ArrayList;
-
-/**
- * Maps the values of an {int} property to string names for properties that encode enumerations.
- *
- * An {@link InspectionCompanion} may provide an instance of this class to a {@link PropertyMapper}
- * for enumerations packed into primitive {int} properties.
- *
- * This class is immutable, and must be constructed by a {@link Builder}.
- *
- * @see PropertyMapper#mapIntEnum(String, int, IntEnumMapping)
- */
-public final class IntEnumMapping {
- private final Value[] mValues;
-
- /**
- * Map from a property value to a string name.
- *
- * @param value The value of a property
- * @return The name of the enumeration value, null if the value is not mapped
- */
- @Nullable
- public String nameOf(int value) {
- for (Value valueTuple : mValues) {
- if (valueTuple.mValue == value) {
- return valueTuple.mName;
- }
- }
-
- return null;
- }
-
- /**
- * Create a new instance from a builder.
- *
- * This constructor is private, use {@link Builder#build()} instead.
- *
- * @param builder A builder to create from
- */
- private IntEnumMapping(Builder builder) {
- mValues = builder.mValues.toArray(new Value[builder.mValues.size()]);
- }
-
- /**
- * A builder for {@link IntEnumMapping}
- */
- public static final class Builder {
- private final ArrayList<Value> mValues;
-
- public Builder() {
- mValues = new ArrayList<>();
- }
-
- /**
- * Add a new entry to this mapping.
- *
- * @param name Name of the enumeration value
- * @param value Int value of the enumeration value
- * @return This builder
- */
- @NonNull
- public Builder addValue(@NonNull String name, int value) {
- mValues.add(new Value(name, value));
- return this;
- }
-
- /**
- * Clear the builder, allowing for recycling.
- */
- public void clear() {
- mValues.clear();
- }
-
- /**
- * Build a new {@link IntEnumMapping} from this builder
- *
- * @return A new mapping
- */
- @NonNull
- public IntEnumMapping build() {
- return new IntEnumMapping(this);
- }
- }
-
- /**
- * Inner class that holds the name and value of an enumeration value.
- */
- private static final class Value {
- @NonNull private final String mName;
- private final int mValue;
-
- private Value(@NonNull String name, int value) {
- mName = name;
- mValue = value;
- }
- }
-}
diff --git a/core/java/android/view/inspector/IntFlagMapping.java b/core/java/android/view/inspector/IntFlagMapping.java
index dcb87e1..8f7dfd5 100644
--- a/core/java/android/view/inspector/IntFlagMapping.java
+++ b/core/java/android/view/inspector/IntFlagMapping.java
@@ -19,14 +19,20 @@
import android.annotation.NonNull;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
/**
- * Maps the values of an {int} property to arrays of string for properties that encode flags.
+ * Maps the values of an {@code int} property to arrays of string for properties that encode flags.
*
* An {@link InspectionCompanion} may provide an instance of this class to a {@link PropertyMapper}
- * for flag values packed into primitive {int} properties.
+ * for flag values packed into primitive {@code int} properties.
*
- * Each flag has a
+ * Each flag has a mask and a target value, for non-exclusive flags, the target can also be used as
+ * the mask. A given integer value is compared against each flag to find what flags are active for
+ * it by bitwise anding it with the mask and comparing the result against the target, that is,
+ * {@code (value & mask) == target}.
*
* This class is immutable, and must be constructed by a {@link Builder}.
*
@@ -42,8 +48,8 @@
* @return The names of the enabled flags
*/
@NonNull
- public String[] namesOf(int value) {
- ArrayList<String> enabledFlagNames = new ArrayList<>(mFlags.length);
+ public Set<String> get(int value) {
+ final Set<String> enabledFlagNames = new HashSet<>(mFlags.length);
for (Flag flag : mFlags) {
if (flag.isEnabledFor(value)) {
@@ -51,7 +57,7 @@
}
}
- return enabledFlagNames.toArray(new String[enabledFlagNames.size()]);
+ return Collections.unmodifiableSet(enabledFlagNames);
}
/**
@@ -81,7 +87,7 @@
* The target value will be used as a mask, to handle the common case where flag values
* are not mutually exclusive. The flag will be considered enabled for a property value if
* the result of bitwise anding the target and the value equals the target, that is:
- * {(value & target) == target}.
+ * {@code (value & target) == target}.
*
* @param name The name of the flag
* @param target The value to compare against
@@ -97,7 +103,7 @@
* Add a new flag with a mask.
*
* The flag will be considered enabled for a property value if the result of bitwise anding
- * the value and the mask equals the target, that is: {(value & mask) == target}.
+ * the value and the mask equals the target, that is: {@code (value & mask) == target}.
*
* @param name The name of the flag
* @param target The value to compare against
@@ -111,13 +117,6 @@
}
/**
- * Clear the builder, allowing for recycling.
- */
- public void clear() {
- mFlags.clear();
- }
-
- /**
* Build a new {@link IntFlagMapping} from this builder.
*
* @return A new mapping
@@ -143,7 +142,7 @@
}
/**
- * Compare the supplied property value against the mask and taget.
+ * Compare the supplied property value against the mask and target.
*
* @param value The value to check
* @return True if this flag is enabled
diff --git a/core/java/android/view/inspector/PropertyMapper.java b/core/java/android/view/inspector/PropertyMapper.java
index 5fb291b..e20582b 100644
--- a/core/java/android/view/inspector/PropertyMapper.java
+++ b/core/java/android/view/inspector/PropertyMapper.java
@@ -18,6 +18,7 @@
import android.annotation.AttrRes;
import android.annotation.NonNull;
+import android.util.SparseArray;
/**
* An interface for mapping the string names of inspectable properties to integer identifiers.
@@ -154,7 +155,7 @@
int mapIntEnum(
@NonNull String name,
@AttrRes int attributeId,
- @NonNull IntEnumMapping mapping);
+ @NonNull SparseArray<String> mapping);
/**
* Map a string name to an integer ID for a flag set packed into an int property.
diff --git a/core/java/android/view/inspector/PropertyReader.java b/core/java/android/view/inspector/PropertyReader.java
index fd83e8d..a8b7ecc 100644
--- a/core/java/android/view/inspector/PropertyReader.java
+++ b/core/java/android/view/inspector/PropertyReader.java
@@ -25,7 +25,13 @@
/**
* An interface for reading the properties of an inspectable object.
*
- * Used as the parameter for {@link InspectionCompanion#readProperties(Object, PropertyReader)}.
+ * {@code PropertyReader} is defined as an interface that will be called by
+ * {@link InspectionCompanion#readProperties(Object, PropertyReader)}. This approach allows a
+ * client inspector to read the values of primitive properties without the overhead of
+ * instantiating a class to hold the property values for each inspection pass. If an inspectable
+ * remains unchanged between reading passes, it should be possible for a {@code PropertyReader} to
+ * avoid new allocations for subsequent reading passes.
+ *
* It has separate methods for all primitive types to avoid autoboxing overhead if a concrete
* implementation is able to work with primitives. Implementations should be prepared to accept
* {null} as the value of {@link PropertyReader#readObject(int, Object)}.
@@ -38,7 +44,7 @@
*
* @param id Identifier of the property from a {@link PropertyMapper}
* @param value Value of the property
- * @throws PropertyTypeMismatchException If the property ID is not mapped as a {boolean}
+ * @throws PropertyTypeMismatchException If the property ID is not mapped as a {@code boolean}
*/
void readBoolean(int id, boolean value);
@@ -47,7 +53,7 @@
*
* @param id Identifier of the property from a {@link PropertyMapper}
* @param value Value of the property
- * @throws PropertyTypeMismatchException If the property ID is not mapped as a {byte}
+ * @throws PropertyTypeMismatchException If the property ID is not mapped as a {@code byte}
*/
void readByte(int id, byte value);
@@ -56,7 +62,7 @@
*
* @param id Identifier of the property from a {@link PropertyMapper}
* @param value Value of the property
- * @throws PropertyTypeMismatchException If the property ID is not mapped as a {char}
+ * @throws PropertyTypeMismatchException If the property ID is not mapped as a {@code char}
*/
void readChar(int id, char value);
@@ -65,7 +71,7 @@
*
* @param id Identifier of the property from a {@link PropertyMapper}
* @param value Value of the property
- * @throws PropertyTypeMismatchException If the property ID is not mapped as a {double}
+ * @throws PropertyTypeMismatchException If the property ID is not mapped as a {@code double}
*/
void readDouble(int id, double value);
@@ -74,7 +80,7 @@
*
* @param id Identifier of the property from a {@link PropertyMapper}
* @param value Value of the property
- * @throws PropertyTypeMismatchException If the property ID is not mapped as a {float}
+ * @throws PropertyTypeMismatchException If the property ID is not mapped as a {@code float}
*/
void readFloat(int id, float value);
@@ -83,7 +89,7 @@
*
* @param id Identifier of the property from a {@link PropertyMapper}
* @param value Value of the property
- * @throws PropertyTypeMismatchException If the property ID is not mapped as an {int}
+ * @throws PropertyTypeMismatchException If the property ID is not mapped as an {@code int}
*/
void readInt(int id, int value);
@@ -92,7 +98,7 @@
*
* @param id Identifier of the property from a {@link PropertyMapper}
* @param value Value of the property
- * @throws PropertyTypeMismatchException If the property ID is not mapped as a {long}
+ * @throws PropertyTypeMismatchException If the property ID is not mapped as a {@code long}
*/
void readLong(int id, long value);
@@ -101,7 +107,7 @@
*
* @param id Identifier of the property from a {@link PropertyMapper}
* @param value Value of the property
- * @throws PropertyTypeMismatchException If the property ID is not mapped as a {short}
+ * @throws PropertyTypeMismatchException If the property ID is not mapped as a {@code short}
*/
void readShort(int id, short value);
diff --git a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
index 2995a8f..7a00a51 100644
--- a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
+++ b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
@@ -58,6 +58,15 @@
return mContext.getResources().getBoolean(R.bool.config_dozePulsePickup);
}
+ public boolean tapGestureEnabled(int user) {
+ return boolSettingDefaultOn(Settings.Secure.DOZE_TAP_SCREEN_GESTURE, user)
+ && tapSensorAvailable();
+ }
+
+ public boolean tapSensorAvailable() {
+ return !TextUtils.isEmpty(tapSensorType());
+ }
+
public boolean doubleTapGestureEnabled(int user) {
return boolSettingDefaultOn(Settings.Secure.DOZE_DOUBLE_TAP_GESTURE, user)
&& doubleTapSensorAvailable();
@@ -86,6 +95,10 @@
return mContext.getResources().getString(R.string.config_dozeDoubleTapSensorType);
}
+ public String tapSensorType() {
+ return mContext.getResources().getString(R.string.config_dozeTapSensorType);
+ }
+
public String longPressSensorType() {
return mContext.getResources().getString(R.string.config_dozeLongPressSensorType);
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index cc8da5c..17cc6af 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -30,6 +30,7 @@
import android.database.ContentObserver;
import android.hardware.usb.UsbManager;
import android.net.ConnectivityManager;
+import android.net.INetworkStatsService;
import android.net.NetworkStats;
import android.net.Uri;
import android.net.wifi.WifiActivityEnergyInfo;
@@ -86,7 +87,6 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.location.gnssmetrics.GnssMetrics;
-import com.android.internal.net.NetworkStatsFactory;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FastXmlSerializer;
@@ -337,6 +337,25 @@
private final PlatformIdleStateCallback mPlatformIdleStateCallback;
+ private final Runnable mDeferSetCharging = new Runnable() {
+ @Override
+ public void run() {
+ synchronized (BatteryStatsImpl.this) {
+ if (mOnBattery) {
+ // if the device gets unplugged in the time between this runnable being
+ // executed and the lock being taken, we don't want to set charging state
+ return;
+ }
+ boolean changed = setChargingLocked(true);
+ if (changed) {
+ final long uptime = mClocks.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ addHistoryRecordLocked(elapsedRealtime, uptime);
+ }
+ }
+ }
+ };
+
/**
* This handler is running on {@link BackgroundThread}.
*/
@@ -11012,7 +11031,6 @@
}
}
- private final NetworkStatsFactory mNetworkStatsFactory = new NetworkStatsFactory();
private final Pools.Pool<NetworkStats> mNetworkStatsPool = new Pools.SynchronizedPool<>(6);
private final Object mWifiNetworkLock = new Object();
@@ -11034,11 +11052,16 @@
private NetworkStats readNetworkStatsLocked(String[] ifaces) {
try {
if (!ArrayUtils.isEmpty(ifaces)) {
- return mNetworkStatsFactory.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces,
- NetworkStats.TAG_NONE, mNetworkStatsPool.acquire());
+ INetworkStatsService statsService = INetworkStatsService.Stub.asInterface(
+ ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
+ if (statsService != null) {
+ return statsService.getDetailedUidStats(ifaces);
+ } else {
+ Slog.e(TAG, "Failed to get networkStatsService ");
+ }
}
- } catch (IOException e) {
- Slog.e(TAG, "failed to read network stats for ifaces: " + Arrays.toString(ifaces));
+ } catch (RemoteException e) {
+ Slog.e(TAG, "failed to read network stats for ifaces: " + Arrays.toString(ifaces) + e);
}
return null;
}
@@ -12336,6 +12359,14 @@
}
boolean setChargingLocked(boolean charging) {
+ // if the device is no longer charging, remove the callback
+ // if the device is now charging, it means that this is either called
+ // 1. directly when level >= 90
+ // 2. or from within the runnable that we deferred
+ // For 1. if we have an existing callback, remove it, since we will immediatelly send a
+ // ACTION_CHARGING
+ // For 2. we remove existing callback so we don't send multiple ACTION_CHARGING
+ mHandler.removeCallbacks(mDeferSetCharging);
if (mCharging != charging) {
mCharging = charging;
if (charging) {
@@ -12674,12 +12705,23 @@
// charging even if it happens to go down a level.
changed |= setChargingLocked(true);
mLastChargeStepLevel = level;
- } if (!mCharging) {
+ }
+ if (!mCharging) {
if (mLastChargeStepLevel < level) {
- // We have not reporting that we are charging, but the level has now
- // gone up, so consider the state to be charging.
- changed |= setChargingLocked(true);
+ // We have not reported that we are charging, but the level has gone up,
+ // but we would like to not have tons of activity from charging-constraint
+ // jobs, so instead of reporting ACTION_CHARGING immediately, we defer it.
mLastChargeStepLevel = level;
+ if (!mHandler.hasCallbacks(mDeferSetCharging)) {
+ mHandler.postDelayed(
+ mDeferSetCharging,
+ mConstants.BATTERY_CHARGED_DELAY_MS);
+ }
+ } else if (mLastChargeStepLevel > level) {
+ // if we had deferred a runnable due to charge level increasing, but then
+ // later the charge level drops (could be due to thermal issues), we don't
+ // want to trigger the deferred runnable, so remove it here
+ mHandler.removeCallbacks(mDeferSetCharging);
}
} else {
if (mLastChargeStepLevel > level) {
@@ -13296,6 +13338,8 @@
= "battery_level_collection_delay_ms";
public static final String KEY_MAX_HISTORY_FILES = "max_history_files";
public static final String KEY_MAX_HISTORY_BUFFER_KB = "max_history_buffer_kb";
+ public static final String KEY_BATTERY_CHARGED_DELAY_MS =
+ "battery_charged_delay_ms";
private static final boolean DEFAULT_TRACK_CPU_TIMES_BY_PROC_STATE = false;
private static final boolean DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME = true;
@@ -13308,6 +13352,7 @@
private static final int DEFAULT_MAX_HISTORY_BUFFER_KB = 128; /*Kilo Bytes*/
private static final int DEFAULT_MAX_HISTORY_FILES_LOW_RAM_DEVICE = 64;
private static final int DEFAULT_MAX_HISTORY_BUFFER_LOW_RAM_DEVICE_KB = 64; /*Kilo Bytes*/
+ private static final int DEFAULT_BATTERY_CHARGED_DELAY_MS = 900000; /* 15 min */
public boolean TRACK_CPU_TIMES_BY_PROC_STATE = DEFAULT_TRACK_CPU_TIMES_BY_PROC_STATE;
public boolean TRACK_CPU_ACTIVE_CLUSTER_TIME = DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME;
@@ -13320,6 +13365,7 @@
= DEFAULT_BATTERY_LEVEL_COLLECTION_DELAY_MS;
public int MAX_HISTORY_FILES;
public int MAX_HISTORY_BUFFER; /*Bytes*/
+ public int BATTERY_CHARGED_DELAY_MS = DEFAULT_BATTERY_CHARGED_DELAY_MS;
private ContentResolver mResolver;
private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -13388,6 +13434,9 @@
DEFAULT_MAX_HISTORY_BUFFER_LOW_RAM_DEVICE_KB
: DEFAULT_MAX_HISTORY_BUFFER_KB)
* 1024;
+ BATTERY_CHARGED_DELAY_MS = mParser.getInt(
+ KEY_BATTERY_CHARGED_DELAY_MS,
+ DEFAULT_BATTERY_CHARGED_DELAY_MS);
}
}
@@ -13445,6 +13494,8 @@
pw.println(MAX_HISTORY_FILES);
pw.print(KEY_MAX_HISTORY_BUFFER_KB); pw.print("=");
pw.println(MAX_HISTORY_BUFFER/1024);
+ pw.print(KEY_BATTERY_CHARGED_DELAY_MS); pw.print("=");
+ pw.println(BATTERY_CHARGED_DELAY_MS);
}
}
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 92aae27..876bd4f 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -566,11 +566,34 @@
return SkEncodeImage(strm.get(), skbitmap, fm, quality) ? JNI_TRUE : JNI_FALSE;
}
+static inline void bitmapErase(SkBitmap bitmap, const SkColor4f& color,
+ const sk_sp<SkColorSpace>& colorSpace) {
+ SkPaint p;
+ p.setColor4f(color, colorSpace.get());
+ p.setBlendMode(SkBlendMode::kSrc);
+ SkCanvas canvas(bitmap);
+ canvas.drawPaint(p);
+}
+
static void Bitmap_erase(JNIEnv* env, jobject, jlong bitmapHandle, jint color) {
LocalScopedBitmap bitmap(bitmapHandle);
SkBitmap skBitmap;
bitmap->getSkBitmap(&skBitmap);
- skBitmap.eraseColor(color);
+ bitmapErase(skBitmap, SkColor4f::FromColor(color), SkColorSpace::MakeSRGB());
+}
+
+static void Bitmap_eraseLong(JNIEnv* env, jobject, jlong bitmapHandle, jobject jColorSpace,
+ jfloat r, jfloat g, jfloat b, jfloat a) {
+ sk_sp<SkColorSpace> cs = GraphicsJNI::getNativeColorSpace(env, jColorSpace);
+ if (GraphicsJNI::hasException(env)) {
+ return;
+ }
+
+ LocalScopedBitmap bitmap(bitmapHandle);
+ SkBitmap skBitmap;
+ bitmap->getSkBitmap(&skBitmap);
+ SkColor4f color = SkColor4f{r, g, b, a};
+ bitmapErase(skBitmap, color, cs);
}
static jint Bitmap_rowBytes(JNIEnv* env, jobject, jlong bitmapHandle) {
@@ -1181,6 +1204,7 @@
{ "nativeCompress", "(JIILjava/io/OutputStream;[B)Z",
(void*)Bitmap_compress },
{ "nativeErase", "(JI)V", (void*)Bitmap_erase },
+ { "nativeErase", "(JLandroid/graphics/ColorSpace;FFFF)V", (void*)Bitmap_eraseLong },
{ "nativeRowBytes", "(J)I", (void*)Bitmap_rowBytes },
{ "nativeConfig", "(J)I", (void*)Bitmap_config },
{ "nativeHasAlpha", "(J)Z", (void*)Bitmap_hasAlpha },
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index ebeb5b2..9e74b88 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -456,12 +456,14 @@
if (colorSpace == nullptr) return nullptr;
if (!env->IsInstanceOf(colorSpace, gColorSpaceRGB_class)) {
doThrowIAE(env, "The color space must be an RGB color space");
+ return nullptr;
}
jobject transferParams = env->CallObjectMethod(colorSpace,
gColorSpaceRGB_getTransferParametersMethodID);
if (transferParams == nullptr) {
doThrowIAE(env, "The color space must use an ICC parametric transfer function");
+ return nullptr;
}
jfloatArray illuminantD50 = (jfloatArray) env->GetStaticObjectField(gColorSpace_class,
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index e97c9bc..bc49771 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -557,6 +557,38 @@
return result;
}
+ // FIXME: Should this be FastNative?
+ static void setColorLong(JNIEnv* env, jobject clazz, jlong paintHandle, jobject jColorSpace,
+ jfloat r, jfloat g, jfloat b, jfloat a) {
+ sk_sp<SkColorSpace> cs = GraphicsJNI::getNativeColorSpace(env, jColorSpace);
+ if (GraphicsJNI::hasException(env)) {
+ return;
+ }
+
+ SkColor4f color = SkColor4f{r, g, b, a};
+ reinterpret_cast<Paint*>(paintHandle)->setColor4f(color, cs.get());
+ }
+
+ static void setShadowLayerLong(JNIEnv* env, jobject clazz, jlong paintHandle, jfloat radius,
+ jfloat dx, jfloat dy, jobject jColorSpace,
+ jfloat r, jfloat g, jfloat b, jfloat a) {
+ sk_sp<SkColorSpace> cs = GraphicsJNI::getNativeColorSpace(env, jColorSpace);
+ if (GraphicsJNI::hasException(env)) {
+ return;
+ }
+
+ SkColor4f color = SkColor4f{r, g, b, a};
+
+ Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+ if (radius <= 0) {
+ paint->setLooper(nullptr);
+ }
+ else {
+ SkScalar sigma = android::uirenderer::Blur::convertRadiusToSigma(radius);
+ paint->setLooper(SkBlurDrawLooper::Make(color, cs.get(), sigma, dx, dy));
+ }
+ }
+
// ------------------ @FastNative ---------------------------
static jint setTextLocales(JNIEnv* env, jobject clazz, jlong objHandle, jstring locales) {
@@ -1075,6 +1107,9 @@
{"nGetRunAdvance", "(J[CIIIIZI)F", (void*) PaintGlue::getRunAdvance___CIIIIZI_F},
{"nGetOffsetForAdvance", "(J[CIIIIZF)I",
(void*) PaintGlue::getOffsetForAdvance___CIIIIZF_I},
+ {"nSetColor","(JLandroid/graphics/ColorSpace;FFFF)V", (void*) PaintGlue::setColorLong},
+ {"nSetShadowLayer", "(JFFFLandroid/graphics/ColorSpace;FFFF)V",
+ (void*)PaintGlue::setShadowLayerLong},
// --------------- @FastNative ----------------------
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index 49a24a3..b2d3651 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -281,15 +281,18 @@
std::unique_ptr<NativeCode> code;
bool needs_native_bridge = false;
+ char* nativeloader_error_msg = nullptr;
void* handle = OpenNativeLibrary(env,
sdkVersion,
pathStr.c_str(),
classLoader,
libraryPath,
&needs_native_bridge,
- &g_error_msg);
+ &nativeloader_error_msg);
if (handle == nullptr) {
+ g_error_msg = nativeloader_error_msg;
+ NativeLoaderFreeErrorMessage(nativeloader_error_msg);
ALOGW("NativeActivity LoadNativeLibrary(\"%s\") failed: %s",
pathStr.c_str(),
g_error_msg.c_str());
diff --git a/core/proto/Android.bp b/core/proto/Android.bp
new file mode 100644
index 0000000..80cc2d4
--- /dev/null
+++ b/core/proto/Android.bp
@@ -0,0 +1,27 @@
+// 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.
+
+// C++ library for Bluetooth platform wide protobuf definitions
+cc_library_static {
+ name: "libbt-platform-protos-lite",
+ host_supported: true,
+ proto: {
+ export_proto_headers: true,
+ type: "lite",
+ },
+ srcs: [
+ "android/bluetooth/enums.proto",
+ "android/bluetooth/hci/enums.proto",
+ ],
+}
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 2f2f623..2148273 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -91,4 +91,13 @@
// OPEN: Settings > Apps & Notifications -> Special app access -> Financial Apps Sms Access
SETTINGS_FINANCIAL_APPS_SMS_ACCESS = 1597;
+
+ // OPEN: Settings > System > Input & Gesture > Skip songs
+ SETTINGS_GESTURE_SKIP = 1624;
+
+ // OPEN: Settings > System > Input & Gesture > Silence alerts
+ SETTINGS_GESTURE_SILENCE = 1625;
+
+ // OPEN: Settings > System > Input & Gesture > Tap to check
+ SETTINGS_GESTURE_TAP_SCREEN = 1626;
}
diff --git a/core/proto/android/bluetooth/enums.proto b/core/proto/android/bluetooth/enums.proto
index d0c9226..76c240e 100644
--- a/core/proto/android/bluetooth/enums.proto
+++ b/core/proto/android/bluetooth/enums.proto
@@ -41,3 +41,18 @@
ENABLE_DISABLE_REASON_USER_SWITCH = 8;
ENABLE_DISABLE_REASON_RESTORE_USER_SETTING = 9;
}
+
+enum DirectionEnum {
+ DIRECTION_UNKNOWN = 0;
+ DIRECTION_OUTGOING = 1;
+ DIRECTION_INCOMING = 2;
+}
+
+// First item is the default value, other values follow Bluetooth spec definition
+enum LinkTypeEnum {
+ // Link type is at most 1 byte (0xFF), thus 0xFFF must not be a valid value
+ LINK_TYPE_UNKNOWN = 0xFFF;
+ LINK_TYPE_SCO = 0x00;
+ LINK_TYPE_ACL = 0x01;
+ LINK_TYPE_ESCO = 0x02;
+}
diff --git a/core/proto/android/bluetooth/hci/enums.proto b/core/proto/android/bluetooth/hci/enums.proto
new file mode 100644
index 0000000..e1d96bb
--- /dev/null
+++ b/core/proto/android/bluetooth/hci/enums.proto
@@ -0,0 +1,519 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+package android.bluetooth.hci;
+
+option java_outer_classname = "BluetoothHciProtoEnums";
+option java_multiple_files = true;
+
+// HCI command opcodes (OCF+OGF) from Bluetooth 5.0 specification Vol 2, Part E, Section 7
+// Original definition: system/bt/stack/include/hcidefs.h
+enum CommandEnum {
+ // Opcode is at most 2 bytes (0xFFFF), thus 0xFFFFF must not be a valid value
+ CMD_UNKNOWN = 0xFFFFF;
+ // Link control commands 0x0400
+ CMD_INQUIRY = 0x0401;
+ CMD_INQUIRY_CANCEL = 0x0402;
+ CMD_PERIODIC_INQUIRY_MODE = 0x0403;
+ CMD_EXIT_PERIODIC_INQUIRY_MODE = 0x0404;
+ CMD_CREATE_CONNECTION = 0x0405;
+ CMD_DISCONNECT = 0x0406;
+ CMD_ADD_SCO_CONNECTION = 0x0407; // Deprecated since Bluetooth 1.2
+ CMD_CREATE_CONNECTION_CANCEL = 0x0408;
+ CMD_ACCEPT_CONNECTION_REQUEST = 0x0409;
+ CMD_REJECT_CONNECTION_REQUEST = 0x040A;
+ CMD_LINK_KEY_REQUEST_REPLY = 0x040B;
+ CMD_LINK_KEY_REQUEST_NEG_REPLY = 0x040C;
+ CMD_PIN_CODE_REQUEST_REPLY = 0x040D;
+ CMD_PIN_CODE_REQUEST_NEG_REPLY = 0x040E;
+ CMD_CHANGE_CONN_PACKET_TYPE = 0x040F;
+ CMD_AUTHENTICATION_REQUESTED = 0x0411;
+ CMD_SET_CONN_ENCRYPTION = 0x0413;
+ CMD_CHANGE_CONN_LINK_KEY = 0x0415;
+ CMD_MASTER_LINK_KEY = 0x0417;
+ CMD_RMT_NAME_REQUEST = 0x0419;
+ CMD_RMT_NAME_REQUEST_CANCEL = 0x041A;
+ CMD_READ_RMT_FEATURES = 0x041B;
+ CMD_READ_RMT_EXT_FEATURES = 0x041C;
+ CMD_READ_RMT_VERSION_INFO = 0x041D;
+ CMD_READ_RMT_CLOCK_OFFSET = 0x041F;
+ CMD_READ_LMP_HANDLE = 0x0420;
+ CMD_SETUP_ESCO_CONNECTION = 0x0428;
+ CMD_ACCEPT_ESCO_CONNECTION = 0x0429;
+ CMD_REJECT_ESCO_CONNECTION = 0x042A;
+ CMD_IO_CAPABILITY_REQUEST_REPLY = 0x042B;
+ CMD_USER_CONF_REQUEST_REPLY = 0x042C;
+ CMD_USER_CONF_VALUE_NEG_REPLY = 0x042D;
+ CMD_USER_PASSKEY_REQ_REPLY = 0x042E;
+ CMD_USER_PASSKEY_REQ_NEG_REPLY = 0x042F;
+ CMD_REM_OOB_DATA_REQ_REPLY = 0x0430;
+ CMD_REM_OOB_DATA_REQ_NEG_REPLY = 0x0433;
+ CMD_IO_CAP_REQ_NEG_REPLY = 0x0434;
+ // BEGIN: AMP commands (not used in system/bt)
+ CMD_CREATE_PHYSICAL_LINK = 0x0435;
+ CMD_ACCEPT_PHYSICAL_LINK = 0x0436;
+ CMD_DISCONNECT_PHYSICAL_LINK = 0x0437;
+ CMD_CREATE_LOGICAL_LINK = 0x0438;
+ CMD_ACCEPT_LOGICAL_LINK = 0x0439;
+ CMD_DISCONNECT_LOGICAL_LINK = 0x043A;
+ CMD_LOGICAL_LINK_CANCEL = 0x043B;
+ CMD_FLOW_SPEC_MODIFY = 0x043C;
+ // END: AMP commands
+ CMD_ENH_SETUP_ESCO_CONNECTION = 0x043D;
+ CMD_ENH_ACCEPT_ESCO_CONNECTION = 0x043E;
+ CMD_TRUNCATED_PAGE = 0x043F;
+ CMD_TRUNCATED_PAGE_CANCEL = 0x0440;
+ CMD_SET_CLB = 0x0441;
+ CMD_RECEIVE_CLB = 0x0442;
+ CMD_START_SYNC_TRAIN = 0x0443;
+ CMD_RECEIVE_SYNC_TRAIN = 0x0444;
+ CMD_REM_OOB_EXTENDED_DATA_REQ_REPLY = 0x0445; // Not currently used in system/bt
+ // Link policy commands 0x0800
+ CMD_HOLD_MODE = 0x0801;
+ CMD_SNIFF_MODE = 0x0803;
+ CMD_EXIT_SNIFF_MODE = 0x0804;
+ CMD_PARK_MODE = 0x0805;
+ CMD_EXIT_PARK_MODE = 0x0806;
+ CMD_QOS_SETUP = 0x0807;
+ CMD_ROLE_DISCOVERY = 0x0809;
+ CMD_SWITCH_ROLE = 0x080B;
+ CMD_READ_POLICY_SETTINGS = 0x080C;
+ CMD_WRITE_POLICY_SETTINGS = 0x080D;
+ CMD_READ_DEF_POLICY_SETTINGS = 0x080E;
+ CMD_WRITE_DEF_POLICY_SETTINGS = 0x080F;
+ CMD_FLOW_SPECIFICATION = 0x0810;
+ CMD_SNIFF_SUB_RATE = 0x0811;
+ // Host controller baseband commands 0x0C00
+ CMD_SET_EVENT_MASK = 0x0C01;
+ CMD_RESET = 0x0C03;
+ CMD_SET_EVENT_FILTER = 0x0C05;
+ CMD_FLUSH = 0x0C08;
+ CMD_READ_PIN_TYPE = 0x0C09;
+ CMD_WRITE_PIN_TYPE = 0x0C0A;
+ CMD_CREATE_NEW_UNIT_KEY = 0x0C0B;
+ CMD_GET_MWS_TRANS_LAYER_CFG = 0x0C0C; // Deprecated (not used in spec)
+ CMD_READ_STORED_LINK_KEY = 0x0C0D;
+ CMD_WRITE_STORED_LINK_KEY = 0x0C11;
+ CMD_DELETE_STORED_LINK_KEY = 0x0C12;
+ CMD_CHANGE_LOCAL_NAME = 0x0C13;
+ CMD_READ_LOCAL_NAME = 0x0C14;
+ CMD_READ_CONN_ACCEPT_TOUT = 0x0C15;
+ CMD_WRITE_CONN_ACCEPT_TOUT = 0x0C16;
+ CMD_READ_PAGE_TOUT = 0x0C17;
+ CMD_WRITE_PAGE_TOUT = 0x0C18;
+ CMD_READ_SCAN_ENABLE = 0x0C19;
+ CMD_WRITE_SCAN_ENABLE = 0x0C1A;
+ CMD_READ_PAGESCAN_CFG = 0x0C1B;
+ CMD_WRITE_PAGESCAN_CFG = 0x0C1C;
+ CMD_READ_INQUIRYSCAN_CFG = 0x0C1D;
+ CMD_WRITE_INQUIRYSCAN_CFG = 0x0C1E;
+ CMD_READ_AUTHENTICATION_ENABLE = 0x0C1F;
+ CMD_WRITE_AUTHENTICATION_ENABLE = 0x0C20;
+ CMD_READ_ENCRYPTION_MODE = 0x0C21; // Deprecated
+ CMD_WRITE_ENCRYPTION_MODE = 0x0C22; // Deprecated
+ CMD_READ_CLASS_OF_DEVICE = 0x0C23;
+ CMD_WRITE_CLASS_OF_DEVICE = 0x0C24;
+ CMD_READ_VOICE_SETTINGS = 0x0C25;
+ CMD_WRITE_VOICE_SETTINGS = 0x0C26;
+ CMD_READ_AUTOMATIC_FLUSH_TIMEOUT = 0x0C27;
+ CMD_WRITE_AUTOMATIC_FLUSH_TIMEOUT = 0x0C28;
+ CMD_READ_NUM_BCAST_REXMITS = 0x0C29;
+ CMD_WRITE_NUM_BCAST_REXMITS = 0x0C2A;
+ CMD_READ_HOLD_MODE_ACTIVITY = 0x0C2B;
+ CMD_WRITE_HOLD_MODE_ACTIVITY = 0x0C2C;
+ CMD_READ_TRANSMIT_POWER_LEVEL = 0x0C2D;
+ CMD_READ_SCO_FLOW_CTRL_ENABLE = 0x0C2E;
+ CMD_WRITE_SCO_FLOW_CTRL_ENABLE = 0x0C2F;
+ CMD_SET_HC_TO_HOST_FLOW_CTRL = 0x0C31;
+ CMD_HOST_BUFFER_SIZE = 0x0C33;
+ CMD_HOST_NUM_PACKETS_DONE = 0x0C35;
+ CMD_READ_LINK_SUPER_TOUT = 0x0C36;
+ CMD_WRITE_LINK_SUPER_TOUT = 0x0C37;
+ CMD_READ_NUM_SUPPORTED_IAC = 0x0C38;
+ CMD_READ_CURRENT_IAC_LAP = 0x0C39;
+ CMD_WRITE_CURRENT_IAC_LAP = 0x0C3A;
+ CMD_READ_PAGESCAN_PERIOD_MODE = 0x0C3B; // Deprecated
+ CMD_WRITE_PAGESCAN_PERIOD_MODE = 0x0C3C; // Deprecated
+ CMD_READ_PAGESCAN_MODE = 0x0C3D; // Deprecated
+ CMD_WRITE_PAGESCAN_MODE = 0x0C3E; // Deprecated
+ CMD_SET_AFH_CHANNELS = 0x0C3F;
+ CMD_READ_INQSCAN_TYPE = 0x0C42;
+ CMD_WRITE_INQSCAN_TYPE = 0x0C43;
+ CMD_READ_INQUIRY_MODE = 0x0C44;
+ CMD_WRITE_INQUIRY_MODE = 0x0C45;
+ CMD_READ_PAGESCAN_TYPE = 0x0C46;
+ CMD_WRITE_PAGESCAN_TYPE = 0x0C47;
+ CMD_READ_AFH_ASSESSMENT_MODE = 0x0C48;
+ CMD_WRITE_AFH_ASSESSMENT_MODE = 0x0C49;
+ CMD_READ_EXT_INQ_RESPONSE = 0x0C51;
+ CMD_WRITE_EXT_INQ_RESPONSE = 0x0C52;
+ CMD_REFRESH_ENCRYPTION_KEY = 0x0C53;
+ CMD_READ_SIMPLE_PAIRING_MODE = 0x0C55;
+ CMD_WRITE_SIMPLE_PAIRING_MODE = 0x0C56;
+ CMD_READ_LOCAL_OOB_DATA = 0x0C57;
+ CMD_READ_INQ_TX_POWER_LEVEL = 0x0C58;
+ CMD_WRITE_INQ_TX_POWER_LEVEL = 0x0C59;
+ CMD_READ_ERRONEOUS_DATA_RPT = 0x0C5A;
+ CMD_WRITE_ERRONEOUS_DATA_RPT = 0x0C5B;
+ CMD_ENHANCED_FLUSH = 0x0C5F;
+ CMD_SEND_KEYPRESS_NOTIF = 0x0C60;
+ CMD_READ_LOGICAL_LINK_ACCEPT_TIMEOUT = 0x0C61;
+ CMD_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT = 0x0C62;
+ CMD_SET_EVENT_MASK_PAGE_2 = 0x0C63;
+ CMD_READ_LOCATION_DATA = 0x0C64;
+ CMD_WRITE_LOCATION_DATA = 0x0C65;
+ CMD_READ_FLOW_CONTROL_MODE = 0x0C66;
+ CMD_WRITE_FLOW_CONTROL_MODE = 0x0C67;
+ CMD_READ_ENHANCED_TX_PWR_LEVEL = 0x0C68; // Not currently used in system/bt
+ CMD_READ_BE_FLUSH_TOUT = 0x0C69;
+ CMD_WRITE_BE_FLUSH_TOUT = 0x0C6A;
+ CMD_SHORT_RANGE_MODE = 0x0C6B;
+ CMD_READ_BLE_HOST_SUPPORT = 0x0C6C;
+ CMD_WRITE_BLE_HOST_SUPPORT = 0x0C6D;
+ CMD_SET_MWS_CHANNEL_PARAMETERS = 0x0C6E;
+ CMD_SET_EXTERNAL_FRAME_CONFIGURATION = 0x0C6F;
+ CMD_SET_MWS_SIGNALING = 0x0C70;
+ CMD_SET_MWS_TRANSPORT_LAYER = 0x0C71;
+ CMD_SET_MWS_SCAN_FREQUENCY_TABLE = 0x0C72;
+ CMD_SET_MWS_PATTERN_CONFIGURATION = 0x0C73;
+ CMD_SET_RESERVED_LT_ADDR = 0x0C74;
+ CMD_DELETE_RESERVED_LT_ADDR = 0x0C75;
+ CMD_WRITE_CLB_DATA = 0x0C76;
+ CMD_READ_SYNC_TRAIN_PARAM = 0x0C77;
+ CMD_WRITE_SYNC_TRAIN_PARAM = 0x0C78;
+ CMD_READ_SECURE_CONNS_SUPPORT = 0x0C79;
+ CMD_WRITE_SECURE_CONNS_SUPPORT = 0x0C7A;
+ CMD_READ_AUTHED_PAYLOAD_TIMEOUT = 0x0C7B; // Not currently used in system/bt
+ CMD_WRITE_AUTHED_PAYLOAD_TIMEOUT = 0x0C7C; // Not currently used in system/bt
+ CMD_READ_LOCAL_OOB_EXTENDED_DATA = 0x0C7D; // Not currently used in system/bt
+ CMD_READ_EXTENDED_PAGE_TIMEOUT = 0x0C7E; // Not currently used in system/bt
+ CMD_WRITE_EXTENDED_PAGE_TIMEOUT = 0x0C7F; // Not currently used in system/bt
+ CMD_READ_EXTENDED_INQUIRY_LENGTH = 0x0C80; // Not currently used in system/bt
+ CMD_WRITE_EXTENDED_INQUIRY_LENGTH = 0x0C81; // Not currently used in system/bt
+ // Informational parameter commands 0x1000
+ CMD_READ_LOCAL_VERSION_INFO = 0x1001;
+ CMD_READ_LOCAL_SUPPORTED_CMDS = 0x1002;
+ CMD_READ_LOCAL_FEATURES = 0x1003;
+ CMD_READ_LOCAL_EXT_FEATURES = 0x1004;
+ CMD_READ_BUFFER_SIZE = 0x1005;
+ CMD_READ_COUNTRY_CODE = 0x1007; // Deprecated
+ CMD_READ_BD_ADDR = 0x1009;
+ CMD_READ_DATA_BLOCK_SIZE = 0x100A;
+ CMD_READ_LOCAL_SUPPORTED_CODECS = 0x100B;
+ // Status parameter commands 0x1400
+ CMD_READ_FAILED_CONTACT_COUNTER = 0x1401;
+ CMD_RESET_FAILED_CONTACT_COUNTER = 0x1402;
+ CMD_GET_LINK_QUALITY = 0x1403;
+ CMD_READ_RSSI = 0x1405;
+ CMD_READ_AFH_CH_MAP = 0x1406;
+ CMD_READ_CLOCK = 0x1407;
+ CMD_READ_ENCR_KEY_SIZE = 0x1408;
+ CMD_READ_LOCAL_AMP_INFO = 0x1409;
+ CMD_READ_LOCAL_AMP_ASSOC = 0x140A;
+ CMD_WRITE_REMOTE_AMP_ASSOC = 0x140B;
+ CMD_GET_MWS_TRANSPORT_CFG = 0x140C; // Not currently used in system/bt
+ CMD_SET_TRIGGERED_CLK_CAPTURE = 0x140D; // Not currently used in system/bt
+ // Testing commands 0x1800
+ CMD_READ_LOOPBACK_MODE = 0x1801;
+ CMD_WRITE_LOOPBACK_MODE = 0x1802;
+ CMD_ENABLE_DEV_UNDER_TEST_MODE = 0x1803;
+ CMD_WRITE_SIMP_PAIR_DEBUG_MODE = 0x1804;
+ CMD_ENABLE_AMP_RCVR_REPORTS = 0x1807;
+ CMD_AMP_TEST_END = 0x1808;
+ CMD_AMP_TEST = 0x1809;
+ CMD_WRITE_SECURE_CONN_TEST_MODE = 0x180A; // Not currently used in system/bt
+ // BLE commands 0x2000
+ CMD_BLE_SET_EVENT_MASK = 0x2001;
+ CMD_BLE_READ_BUFFER_SIZE = 0x2002;
+ CMD_BLE_READ_LOCAL_SPT_FEAT = 0x2003;
+ CMD_BLE_WRITE_LOCAL_SPT_FEAT = 0x2004;
+ CMD_BLE_WRITE_RANDOM_ADDR = 0x2005;
+ CMD_BLE_WRITE_ADV_PARAMS = 0x2006;
+ CMD_BLE_READ_ADV_CHNL_TX_POWER = 0x2007;
+ CMD_BLE_WRITE_ADV_DATA = 0x2008;
+ CMD_BLE_WRITE_SCAN_RSP_DATA = 0x2009;
+ CMD_BLE_WRITE_ADV_ENABLE = 0x200A;
+ CMD_BLE_WRITE_SCAN_PARAMS = 0x200B;
+ CMD_BLE_WRITE_SCAN_ENABLE = 0x200C;
+ CMD_BLE_CREATE_LL_CONN = 0x200D;
+ CMD_BLE_CREATE_CONN_CANCEL = 0x200E;
+ CMD_BLE_READ_WHITE_LIST_SIZE = 0x200F;
+ CMD_BLE_CLEAR_WHITE_LIST = 0x2010;
+ CMD_BLE_ADD_WHITE_LIST = 0x2011;
+ CMD_BLE_REMOVE_WHITE_LIST = 0x2012;
+ CMD_BLE_UPD_LL_CONN_PARAMS = 0x2013;
+ CMD_BLE_SET_HOST_CHNL_CLASS = 0x2014;
+ CMD_BLE_READ_CHNL_MAP = 0x2015;
+ CMD_BLE_READ_REMOTE_FEAT = 0x2016;
+ CMD_BLE_ENCRYPT = 0x2017;
+ CMD_BLE_RAND = 0x2018;
+ CMD_BLE_START_ENC = 0x2019;
+ CMD_BLE_LTK_REQ_REPLY = 0x201A;
+ CMD_BLE_LTK_REQ_NEG_REPLY = 0x201B;
+ CMD_BLE_READ_SUPPORTED_STATES = 0x201C;
+ CMD_BLE_RECEIVER_TEST = 0x201D;
+ CMD_BLE_TRANSMITTER_TEST = 0x201E;
+ CMD_BLE_TEST_END = 0x201F;
+ CMD_BLE_RC_PARAM_REQ_REPLY = 0x2020;
+ CMD_BLE_RC_PARAM_REQ_NEG_REPLY = 0x2021;
+ CMD_BLE_SET_DATA_LENGTH = 0x2022;
+ CMD_BLE_READ_DEFAULT_DATA_LENGTH = 0x2023;
+ CMD_BLE_WRITE_DEFAULT_DATA_LENGTH = 0x2024;
+ CMD_BLE_GENERATE_DHKEY = 0x2026; // Not currently used in system/bt
+ CMD_BLE_ADD_DEV_RESOLVING_LIST = 0x2027;
+ CMD_BLE_RM_DEV_RESOLVING_LIST = 0x2028;
+ CMD_BLE_CLEAR_RESOLVING_LIST = 0x2029;
+ CMD_BLE_READ_RESOLVING_LIST_SIZE = 0x202A;
+ CMD_BLE_READ_RESOLVABLE_ADDR_PEER = 0x202B;
+ CMD_BLE_READ_RESOLVABLE_ADDR_LOCAL = 0x202C;
+ CMD_BLE_SET_ADDR_RESOLUTION_ENABLE = 0x202D;
+ CMD_BLE_SET_RAND_PRIV_ADDR_TIMOUT = 0x202E;
+ CMD_BLE_READ_MAXIMUM_DATA_LENGTH = 0x202F;
+ CMD_BLE_READ_PHY = 0x2030;
+ CMD_BLE_SET_DEFAULT_PHY = 0x2031;
+ CMD_BLE_SET_PHY = 0x2032;
+ CMD_BLE_ENH_RECEIVER_TEST = 0x2033;
+ CMD_BLE_ENH_TRANSMITTER_TEST = 0x2034;
+ CMD_BLE_SET_EXT_ADVERTISING_RANDOM_ADDRESS = 0x2035;
+ CMD_BLE_SET_EXT_ADVERTISING_PARAM = 0x2036;
+ CMD_BLE_SET_EXT_ADVERTISING_DATA = 0x2037;
+ CMD_BLE_SET_EXT_ADVERTISING_SCAN_RESP = 0x2038;
+ CMD_BLE_SET_EXT_ADVERTISING_ENABLE = 0x2039;
+ CMD_BLE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH = 0x203A;
+ CMD_BLE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS = 0x203B;
+ CMD_BLE_REMOVE_ADVERTISING_SET = 0x203C;
+ CMD_BLE_CLEAR_ADVERTISING_SETS = 0x203D;
+ CMD_BLE_SET_PERIODIC_ADVERTISING_PARAM = 0x203E;
+ CMD_BLE_SET_PERIODIC_ADVERTISING_DATA = 0x203F;
+ CMD_BLE_SET_PERIODIC_ADVERTISING_ENABLE = 0x2040;
+ CMD_BLE_SET_EXTENDED_SCAN_PARAMETERS = 0x2041;
+ CMD_BLE_SET_EXTENDED_SCAN_ENABLE = 0x2042;
+ CMD_BLE_EXTENDED_CREATE_CONNECTION = 0x2043;
+ CMD_BLE_PERIODIC_ADVERTISING_CREATE_SYNC = 0x2044;
+ CMD_BLE_PERIODIC_ADVERTISING_CREATE_SYNC_CANCEL = 0x2045;
+ CMD_BLE_PERIODIC_ADVERTISING_TERMINATE_SYNC = 0x2046;
+ CMD_BLE_ADD_DEVICE_TO_PERIODIC_ADVERTISING_LIST = 0x2047;
+ CMD_BLE_RM_DEVICE_FROM_PERIODIC_ADVERTISING_LIST = 0x2048;
+ CMD_BLE_CLEAR_PERIODIC_ADVERTISING_LIST = 0x2049;
+ CMD_BLE_READ_PERIODIC_ADVERTISING_LIST_SIZE = 0x204A;
+ CMD_BLE_READ_TRANSMIT_POWER = 0x204B;
+ CMD_BLE_READ_RF_COMPENS_POWER = 0x204C;
+ CMD_BLE_WRITE_RF_COMPENS_POWER = 0x204D;
+ CMD_BLE_SET_PRIVACY_MODE = 0x204E;
+ // Vendor specific commands 0xFC00 and above
+ // Android vendor specific commands defined in
+ // https://source.android.com/devices/bluetooth/hci_requirements#vendor-specific-capabilities
+ CMD_BLE_VENDOR_CAP = 0xFD53;
+ CMD_BLE_MULTI_ADV = 0xFD54;
+ CMD_BLE_BATCH_SCAN = 0xFD56;
+ CMD_BLE_ADV_FILTER = 0xFD57;
+ CMD_BLE_TRACK_ADV = 0xFD58;
+ CMD_BLE_ENERGY_INFO = 0xFD59;
+ CMD_BLE_EXTENDED_SCAN_PARAMS = 0xFD5A;
+ CMD_CONTROLLER_DEBUG_INFO = 0xFD5B;
+ CMD_CONTROLLER_A2DP_OPCODE = 0xFD5D;
+ CMD_BRCM_SET_ACL_PRIORITY = 0xFC57;
+ // Other vendor specific commands below here
+}
+
+// HCI event codes from the Bluetooth 5.0 specification Vol 2, Part 7, Section 7
+// Original definition: system/bt/stack/include/hcidefs.h
+enum EventEnum {
+ // Event is at most 1 byte (0xFF), thus 0xFFF must not be a valid value
+ EVT_UNKNOWN = 0xFFF;
+ EVT_INQUIRY_COMP = 0x01;
+ EVT_INQUIRY_RESULT = 0x02;
+ EVT_CONNECTION_COMP = 0x03;
+ EVT_CONNECTION_REQUEST = 0x04;
+ EVT_DISCONNECTION_COMP = 0x05;
+ EVT_AUTHENTICATION_COMP = 0x06;
+ EVT_RMT_NAME_REQUEST_COMP = 0x07;
+ EVT_ENCRYPTION_CHANGE = 0x08;
+ EVT_CHANGE_CONN_LINK_KEY = 0x09;
+ EVT_MASTER_LINK_KEY_COMP = 0x0A;
+ EVT_READ_RMT_FEATURES_COMP = 0x0B;
+ EVT_READ_RMT_VERSION_COMP = 0x0C;
+ EVT_QOS_SETUP_COMP = 0x0D;
+ EVT_COMMAND_COMPLETE = 0x0E;
+ EVT_COMMAND_STATUS = 0x0F;
+ EVT_HARDWARE_ERROR = 0x10;
+ EVT_FLUSH_OCCURED = 0x11;
+ EVT_ROLE_CHANGE = 0x12;
+ EVT_NUM_COMPL_DATA_PKTS = 0x13;
+ EVT_MODE_CHANGE = 0x14;
+ EVT_RETURN_LINK_KEYS = 0x15;
+ EVT_PIN_CODE_REQUEST = 0x16;
+ EVT_LINK_KEY_REQUEST = 0x17;
+ EVT_LINK_KEY_NOTIFICATION = 0x18;
+ EVT_LOOPBACK_COMMAND = 0x19;
+ EVT_DATA_BUF_OVERFLOW = 0x1A;
+ EVT_MAX_SLOTS_CHANGED = 0x1B;
+ EVT_READ_CLOCK_OFF_COMP = 0x1C;
+ EVT_CONN_PKT_TYPE_CHANGE = 0x1D;
+ EVT_QOS_VIOLATION = 0x1E;
+ EVT_PAGE_SCAN_MODE_CHANGE = 0x1F; // Deprecated
+ EVT_PAGE_SCAN_REP_MODE_CHNG = 0x20;
+ EVT_FLOW_SPECIFICATION_COMP = 0x21;
+ EVT_INQUIRY_RSSI_RESULT = 0x22;
+ EVT_READ_RMT_EXT_FEATURES_COMP = 0x23;
+ EVT_ESCO_CONNECTION_COMP = 0x2C;
+ EVT_ESCO_CONNECTION_CHANGED = 0x2D;
+ EVT_SNIFF_SUB_RATE = 0x2E;
+ EVT_EXTENDED_INQUIRY_RESULT = 0x2F;
+ EVT_ENCRYPTION_KEY_REFRESH_COMP = 0x30;
+ EVT_IO_CAPABILITY_REQUEST = 0x31;
+ EVT_IO_CAPABILITY_RESPONSE = 0x32;
+ EVT_USER_CONFIRMATION_REQUEST = 0x33;
+ EVT_USER_PASSKEY_REQUEST = 0x34;
+ EVT_REMOTE_OOB_DATA_REQUEST = 0x35;
+ EVT_SIMPLE_PAIRING_COMPLETE = 0x36;
+ EVT_LINK_SUPER_TOUT_CHANGED = 0x38;
+ EVT_ENHANCED_FLUSH_COMPLETE = 0x39;
+ EVT_USER_PASSKEY_NOTIFY = 0x3B;
+ EVT_KEYPRESS_NOTIFY = 0x3C;
+ EVT_RMT_HOST_SUP_FEAT_NOTIFY = 0x3D;
+ EVT_BLE_META = 0x3E;
+ EVT_PHYSICAL_LINK_COMP = 0x40;
+ EVT_CHANNEL_SELECTED = 0x41;
+ EVT_DISC_PHYSICAL_LINK_COMP = 0x42;
+ EVT_PHY_LINK_LOSS_EARLY_WARNING = 0x43;
+ EVT_PHY_LINK_RECOVERY = 0x44;
+ EVT_LOGICAL_LINK_COMP = 0x45;
+ EVT_DISC_LOGICAL_LINK_COMP = 0x46;
+ EVT_FLOW_SPEC_MODIFY_COMP = 0x47;
+ EVT_NUM_COMPL_DATA_BLOCKS = 0x48;
+ EVT_AMP_TEST_START = 0x49; // Not currently used in system/bt
+ EVT_AMP_TEST_END = 0x4A; // Not currently used in system/bt
+ EVT_AMP_RECEIVER_RPT = 0x4B; // Not currently used in system/bt
+ EVT_SHORT_RANGE_MODE_COMPLETE = 0x4C;
+ EVT_AMP_STATUS_CHANGE = 0x4D;
+ EVT_SET_TRIGGERED_CLOCK_CAPTURE = 0x4E;
+ EVT_SYNC_TRAIN_CMPL = 0x4F; // Not currently used in system/bt
+ EVT_SYNC_TRAIN_RCVD = 0x50; // Not currently used in system/bt
+ EVT_CONNLESS_SLAVE_BROADCAST_RCVD = 0x51; // Not currently used in system/bt
+ EVT_CONNLESS_SLAVE_BROADCAST_TIMEOUT = 0x52; // Not currently used in system/bt
+ EVT_TRUNCATED_PAGE_CMPL = 0x53; // Not currently used in system/bt
+ EVT_SLAVE_PAGE_RES_TIMEOUT = 0x54; // Not currently used in system/bt
+ EVT_CONNLESS_SLAVE_BROADCAST_CHNL_MAP_CHANGE = 0x55; // Not currently used in system/bt
+ EVT_INQUIRY_RES_NOTIFICATION = 0x56; // Not currently used in system/bt
+ EVT_AUTHED_PAYLOAD_TIMEOUT = 0x57; // Not currently used in system/bt
+ EVT_SAM_STATUS_CHANGE = 0x58; // Not currently used in system/bt
+}
+
+// Bluetooth low energy related meta event codes
+// from the Bluetooth 5.0 specification Vol 2, Part E, Section 7.7.65
+// Original definition: system/bt/stack/include/hcidefs.h
+enum BleMetaEventEnum {
+ // BLE meta event code is at most 1 byte (0xFF), thus 0xFFF must not be a valid value
+ BLE_EVT_UNKNOWN = 0xFFF;
+ BLE_EVT_CONN_COMPLETE_EVT = 0x01;
+ BLE_EVT_ADV_PKT_RPT_EVT = 0x02;
+ BLE_EVT_LL_CONN_PARAM_UPD_EVT = 0x03;
+ BLE_EVT_READ_REMOTE_FEAT_CMPL_EVT = 0x04;
+ BLE_EVT_LTK_REQ_EVT = 0x05;
+ BLE_EVT_RC_PARAM_REQ_EVT = 0x06;
+ BLE_EVT_DATA_LENGTH_CHANGE_EVT = 0x07;
+ BLE_EVT_READ_LOCAL_P256_PUB_KEY = 0x08; // Not currently used in system/bt
+ BLE_EVT_GEN_DHKEY_CMPL = 0x09; // Not currently used in system/bt
+ BLE_EVT_ENHANCED_CONN_COMPLETE_EVT = 0x0a;
+ BLE_EVT_DIRECT_ADV_EVT = 0x0b;
+ BLE_EVT_PHY_UPDATE_COMPLETE_EVT = 0x0c;
+ BLE_EVT_EXTENDED_ADVERTISING_REPORT_EVT = 0x0D;
+ BLE_EVT_PERIODIC_ADV_SYNC_EST_EVT = 0x0E;
+ BLE_EVT_PERIODIC_ADV_REPORT_EVT = 0x0F;
+ BLE_EVT_PERIODIC_ADV_SYNC_LOST_EVT = 0x10;
+ BLE_EVT_SCAN_TIMEOUT_EVT = 0x11;
+ BLE_EVT_ADVERTISING_SET_TERMINATED_EVT = 0x12;
+ BLE_EVT_SCAN_REQ_RX_EVT = 0x13;
+ BLE_EVT_CHNL_SELECTION_ALGORITHM = 0x14; // Not currently used in system/bt
+}
+
+// HCI status code from the Bluetooth 5.0 specification Vol 2, Part D.
+// Original definition: system/bt/stack/include/hcidefs.h
+enum StatusEnum {
+ // Status is at most 1 byte (0xFF), thus 0xFFF must not be a valid value
+ STATUS_UNKNOWN = 0xFFF;
+ STATUS_SUCCESS = 0x00;
+ STATUS_ILLEGAL_COMMAND = 0x01;
+ STATUS_NO_CONNECTION = 0x02;
+ STATUS_HW_FAILURE = 0x03;
+ STATUS_PAGE_TIMEOUT = 0x04;
+ STATUS_AUTH_FAILURE = 0x05;
+ STATUS_KEY_MISSING = 0x06;
+ STATUS_MEMORY_FULL = 0x07;
+ STATUS_CONNECTION_TOUT = 0x08;
+ STATUS_MAX_NUM_OF_CONNECTIONS = 0x09;
+ STATUS_MAX_NUM_OF_SCOS = 0x0A;
+ STATUS_CONNECTION_EXISTS = 0x0B;
+ STATUS_COMMAND_DISALLOWED = 0x0C;
+ STATUS_HOST_REJECT_RESOURCES = 0x0D;
+ STATUS_HOST_REJECT_SECURITY = 0x0E;
+ STATUS_HOST_REJECT_DEVICE = 0x0F;
+ STATUS_HOST_TIMEOUT = 0x10;
+ STATUS_UNSUPPORTED_VALUE = 0x11;
+ STATUS_ILLEGAL_PARAMETER_FMT = 0x12;
+ STATUS_PEER_USER = 0x13;
+ STATUS_PEER_LOW_RESOURCES = 0x14;
+ STATUS_PEER_POWER_OFF = 0x15;
+ STATUS_CONN_CAUSE_LOCAL_HOST = 0x16;
+ STATUS_REPEATED_ATTEMPTS = 0x17;
+ STATUS_PAIRING_NOT_ALLOWED = 0x18;
+ STATUS_UNKNOWN_LMP_PDU = 0x19;
+ STATUS_UNSUPPORTED_REM_FEATURE = 0x1A;
+ STATUS_SCO_OFFSET_REJECTED = 0x1B;
+ STATUS_SCO_INTERVAL_REJECTED = 0x1C;
+ STATUS_SCO_AIR_MODE = 0x1D;
+ STATUS_INVALID_LMP_PARAM = 0x1E;
+ STATUS_UNSPECIFIED = 0x1F;
+ STATUS_UNSUPPORTED_LMP_FEATURE = 0x20;
+ STATUS_ROLE_CHANGE_NOT_ALLOWED = 0x21;
+ STATUS_LMP_RESPONSE_TIMEOUT = 0x22;
+ STATUS_LMP_STATUS_TRANS_COLLISION = 0x23;
+ STATUS_LMP_PDU_NOT_ALLOWED = 0x24;
+ STATUS_ENCRY_MODE_NOT_ACCEPTABLE = 0x25;
+ STATUS_UNIT_KEY_USED = 0x26;
+ STATUS_QOS_NOT_SUPPORTED = 0x27;
+ STATUS_INSTANT_PASSED = 0x28;
+ STATUS_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED = 0x29;
+ STATUS_DIFF_TRANSACTION_COLLISION = 0x2A;
+ STATUS_UNDEFINED_0x2B = 0x2B; // Not used
+ STATUS_QOS_UNACCEPTABLE_PARAM = 0x2C;
+ STATUS_QOS_REJECTED = 0x2D;
+ STATUS_CHAN_CLASSIF_NOT_SUPPORTED = 0x2E;
+ STATUS_INSUFFCIENT_SECURITY = 0x2F;
+ STATUS_PARAM_OUT_OF_RANGE = 0x30;
+ STATUS_UNDEFINED_0x31 = 0x31; // Not used
+ STATUS_ROLE_SWITCH_PENDING = 0x32;
+ STATUS_UNDEFINED_0x33 = 0x33;
+ STATUS_RESERVED_SLOT_VIOLATION = 0x34;
+ STATUS_ROLE_SWITCH_FAILED = 0x35;
+ STATUS_INQ_RSP_DATA_TOO_LARGE = 0x36;
+ STATUS_SIMPLE_PAIRING_NOT_SUPPORTED = 0x37;
+ STATUS_HOST_BUSY_PAIRING = 0x38;
+ STATUS_REJ_NO_SUITABLE_CHANNEL = 0x39;
+ STATUS_CONTROLLER_BUSY = 0x3A;
+ STATUS_UNACCEPT_CONN_INTERVAL = 0x3B;
+ STATUS_ADVERTISING_TIMEOUT = 0x3C;
+ STATUS_CONN_TOUT_DUE_TO_MIC_FAILURE = 0x3D;
+ STATUS_CONN_FAILED_ESTABLISHMENT = 0x3E;
+ STATUS_MAC_CONNECTION_FAILED = 0x3F;
+ STATUS_LT_ADDR_ALREADY_IN_USE = 0x40;
+ STATUS_LT_ADDR_NOT_ALLOCATED = 0x41;
+ STATUS_CLB_NOT_ENABLED = 0x42;
+ STATUS_CLB_DATA_TOO_BIG = 0x43;
+ STATUS_OPERATION_CANCELED_BY_HOST = 0x44; // Not currently used in system/bt
+}
diff --git a/core/proto/android/bluetooth/hfp/enums.proto b/core/proto/android/bluetooth/hfp/enums.proto
new file mode 100644
index 0000000..d286e4b
--- /dev/null
+++ b/core/proto/android/bluetooth/hfp/enums.proto
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+package android.bluetooth.hfp;
+
+option java_outer_classname = "BluetoothHfpProtoEnums";
+option java_multiple_files = true;
+
+enum ScoCodec {
+ SCO_CODEC_UNKNOWN = 0;
+ SCO_CODEC_CVSD = 1;
+ // Default codec behind Wide Band Speech
+ SCO_CODEC_MSBC = 2;
+}
\ No newline at end of file
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index cc5aa20..4158577 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -436,12 +436,19 @@
// Ordered GPU debug layer list for GLES
// i.e. <layer1>:<layer2>:...:<layerN>
optional SettingProto debug_layers_gles = 7;
- // GUP - List of Apps selected to use Game Update Packages
- optional SettingProto gup_dev_opt_in_apps = 8;
- // GUP - List of Apps selected not to use Game Update Packages
- optional SettingProto gup_dev_opt_out_apps = 9;
- // GUP - List of Apps that are forbidden to use Game Update Packages
- optional SettingProto gup_black_list = 10;
+ // GUP - Game Update Package global preference for all Apps
+ // 0 = Default
+ // 1 = All Apps use Game Update Package
+ // 2 = All Apps use system graphics driver
+ optional SettingProto gup_dev_all_apps = 8;
+ // GUP - List of Apps selected to use Game Update Package
+ // i.e. <pkg1>,<pkg2>,...,<pkgN>
+ optional SettingProto gup_dev_opt_in_apps = 9;
+ // GUP - List of Apps selected not to use Game Update Package
+ // i.e. <pkg1>,<pkg2>,...,<pkgN>
+ optional SettingProto gup_dev_opt_out_apps = 10;
+ // GUP - List of Apps that are forbidden to use Game Update Package
+ optional SettingProto gup_blacklist = 11;
}
optional Gpu gpu = 59;
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index 0e052fe..4bfd4d2 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -182,6 +182,7 @@
optional SettingProto pulse_on_pick_up = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto pulse_on_long_press = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto pulse_on_double_tap = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto pulse_on_tap = 6 [ (android.privacy).dest = DEST_AUTOMATIC ];
}
optional Doze doze = 21;
@@ -525,7 +526,10 @@
}
optional Zen zen = 71;
+ optional SettingProto skip_gesture_enabled = 74 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto silence_gesture_enabled = 75 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
// Please insert fields in alphabetical order and group them into messages
// if possible (to avoid reaching the method limit).
- // Next tag = 74;
+ // Next tag = 76;
}
diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto
index 0ec8c1a..7f3ea7a 100644
--- a/core/proto/android/server/jobscheduler.proto
+++ b/core/proto/android/server/jobscheduler.proto
@@ -403,18 +403,23 @@
optional bool is_charging = 1;
optional bool is_in_parole = 2;
+ // List of UIDs currently in the foreground.
+ repeated int32 foreground_uids = 3;
+
message TrackedJob {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
optional JobStatusShortInfoProto info = 1;
optional int32 source_uid = 2;
optional JobStatusDumpProto.Bucket effective_standby_bucket = 3;
- optional bool has_quota = 4;
+ // If the job started while the app was in the TOP state.
+ optional bool is_top_started_job = 4;
+ optional bool has_quota = 5;
// The amount of time that this job has remaining in its quota. This
// can be negative if the job is out of quota.
- optional int64 remaining_quota_ms = 5;
+ optional int64 remaining_quota_ms = 6;
}
- repeated TrackedJob tracked_jobs = 3;
+ repeated TrackedJob tracked_jobs = 4;
message Package {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
@@ -456,7 +461,7 @@
repeated TimingSession saved_sessions = 3;
}
- repeated PackageStats package_stats = 4;
+ repeated PackageStats package_stats = 5;
}
message StorageController {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 2f3a491..7813128 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3196,9 +3196,10 @@
<!-- @SystemApi Required to add or remove another application as a device admin.
<p>Not for use by third-party applications.
- @hide -->
+ @hide
+ @removed -->
<permission android:name="android.permission.MANAGE_DEVICE_ADMINS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows an app to reset the device password.
<p>Not for use by third-party applications.
@@ -3520,19 +3521,25 @@
<permission android:name="android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS"
android:protectionLevel="signature|privileged" />
+ <!-- @SystemApi Allows an application to provide remote displays.
+ <p>Not for use by third-party applications.</p>
+ @hide -->
+ <permission android:name="android.permission.REMOTE_DISPLAY_PROVIDER"
+ android:protectionLevel="signature|privileged" />
+
<!-- Allows an application to capture video output.
<p>Not for use by third-party applications.</p>
@hide
@removed -->
<permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature" />
<!-- Allows an application to capture secure video output.
<p>Not for use by third-party applications.</p>
@hide
@removed -->
<permission android:name="android.permission.CAPTURE_SECURE_VIDEO_OUTPUT"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature" />
<!-- Allows an application to know what content is playing and control its playback.
<p>Not for use by third-party applications due to privacy of media consumption</p> -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 1feb59a..9a1360b 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -929,9 +929,6 @@
in hardware. -->
<bool name="config_setColorTransformAccelerated">false</bool>
- <!-- Boolean indicating whether display white balance is supported. -->
- <bool name="config_displayWhiteBalanceAvailable">false</bool>
-
<!-- Control whether Night display is available. This should only be enabled on devices
that have a HWC implementation that can apply the matrix passed to setColorTransform
without impacting power, performance, and app compatibility (e.g. protected content). -->
@@ -987,6 +984,44 @@
<!-- B y-intercept --> <item>-0.198650895</item>
</string-array>
+ <!-- Boolean indicating whether display white balance is supported. -->
+ <bool name="config_displayWhiteBalanceAvailable">false</bool>
+
+ <!-- Minimum color temperature, in Kelvin, supported by display white balance. -->
+ <integer name="config_displayWhiteBalanceColorTemperatureMin">4000</integer>
+
+ <!-- Maximum color temperature, in Kelvin, supported by display white balance. -->
+ <integer name="config_displayWhiteBalanceColorTemperatureMax">8000</integer>
+
+ <!-- Default color temperature, in Kelvin, used by display white balance. -->
+ <integer name="config_displayWhiteBalanceColorTemperatureDefault">6500</integer>
+
+ <!-- The display primaries, in CIE1931 XYZ color space, for display
+ white balance to use in its calculations. -->
+ <string-array name="config_displayWhiteBalanceDisplayPrimaries">
+ <!-- Red X --> <item>0.412315</item>
+ <!-- Red Y --> <item>0.212600</item>
+ <!-- Red Z --> <item>0.019327</item>
+ <!-- Green X --> <item>0.357600</item>
+ <!-- Green Y --> <item>0.715200</item>
+ <!-- Green Z --> <item>0.119200</item>
+ <!-- Blue X --> <item>0.180500</item>
+ <!-- Blue Y --> <item>0.072200</item>
+ <!-- Blue Z --> <item>0.950633</item>
+ <!-- White X --> <item>0.950456</item>
+ <!-- White Y --> <item>1.000000</item>
+ <!-- White Z --> <item>1.089058</item>
+ </string-array>
+
+ <!-- The nominal white coordinates, in CIE1931 XYZ color space, for Display White Balance to
+ use in its calculations. AWB will adapt this white point to the target ambient white
+ point. -->
+ <string-array name="config_displayWhiteBalanceDisplayNominalWhite">
+ <!-- Nominal White X --> <item>0.950456</item>
+ <!-- Nominal White Y --> <item>1.000000</item>
+ <!-- Nominal White Z --> <item>1.089058</item>
+ </string-array>
+
<!-- Indicate available ColorDisplayController.COLOR_MODE_xxx. -->
<integer-array name="config_availableColorModes">
@@ -1654,6 +1689,8 @@
config_enableFusedLocationOverlay is false. -->
<string name="config_fusedLocationProviderPackageName" translatable="false">com.android.location.fused</string>
+ <string-array name="config_locationExtraPackageNames" translatable="false"></string-array>
+
<!-- The package name of the default network recommendation app.
A network recommendation provider must:
* Be granted the SCORE_NETWORKS permission.
@@ -2168,6 +2205,9 @@
<!-- Type of the double tap sensor. Empty if double tap is not supported. -->
<string name="config_dozeDoubleTapSensorType" translatable="false"></string>
+ <!-- Type of the tap sensor. Empty if tap is not supported. -->
+ <string name="config_dozeTapSensorType" translatable="false"></string>
+
<!-- Type of the long press sensor. Empty if long press is not supported. -->
<string name="config_dozeLongPressSensorType" translatable="false"></string>
@@ -3661,7 +3701,7 @@
<string name="config_inputEventCompatProcessorOverrideClassName" translatable="false"></string>
<!-- Component name for the default module metadata provider on this device -->
- <string name="config_defaultModuleMetadataProvider">com.android.modulemetadata</string>
+ <string name="config_defaultModuleMetadataProvider" translatable="false">com.android.modulemetadata</string>
<!-- This is the default launcher component to use on secondary displays that support system
decorations.
@@ -3673,4 +3713,10 @@
<!-- If device supports corner radius on windows.
This should be turned off on low-end devices to improve animation performance. -->
<bool name="config_supportsRoundedCornersOnWindows">true</bool>
+
+ <!-- If the sensor that skips media is available or not. -->
+ <bool name="config_skipSensorAvailable">false</bool>
+
+ <!-- If the sensor that silences alerts is available or not. -->
+ <bool name="config_silenceSensorAvailable">false</bool>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 010accf..cd1ee2b 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1840,6 +1840,7 @@
<java-symbol type="array" name="radioAttributes" />
<java-symbol type="array" name="config_oemUsbModeOverride" />
<java-symbol type="array" name="config_locationProviderPackageNames" />
+ <java-symbol type="array" name="config_locationExtraPackageNames" />
<java-symbol type="array" name="config_testLocationProviders" />
<java-symbol type="array" name="config_defaultNotificationVibePattern" />
<java-symbol type="array" name="config_notificationFallbackVibePattern" />
@@ -3001,6 +3002,7 @@
<java-symbol type="array" name="config_emergency_mcc_codes" />
<java-symbol type="string" name="config_dozeDoubleTapSensorType" />
+ <java-symbol type="string" name="config_dozeTapSensorType" />
<java-symbol type="bool" name="config_dozePulsePickup" />
<!-- Used for MimeIconUtils. -->
@@ -3042,6 +3044,13 @@
<java-symbol type="array" name="config_nightDisplayColorTemperatureCoefficientsNative" />
<java-symbol type="array" name="config_availableColorModes" />
+ <java-symbol type="bool" name="config_displayWhiteBalanceAvailable" />
+ <java-symbol type="integer" name="config_displayWhiteBalanceColorTemperatureMin" />
+ <java-symbol type="integer" name="config_displayWhiteBalanceColorTemperatureMax" />
+ <java-symbol type="integer" name="config_displayWhiteBalanceColorTemperatureDefault" />
+ <java-symbol type="array" name="config_displayWhiteBalanceDisplayPrimaries" />
+ <java-symbol type="array" name="config_displayWhiteBalanceDisplayNominalWhite" />
+
<!-- Default first user restrictions -->
<java-symbol type="array" name="config_defaultFirstUserRestrictions" />
@@ -3529,4 +3538,7 @@
<java-symbol type="string" name="dynamic_mode_notification_title" />
<java-symbol type="string" name="dynamic_mode_notification_summary" />
<java-symbol type="drawable" name="ic_battery" />
+
+ <java-symbol type="bool" name="config_skipSensorAvailable" />
+ <java-symbol type="bool" name="config_silenceSensorAvailable" />
</resources>
diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk
index 74943c7..0fc3bd2 100644
--- a/core/tests/coretests/Android.mk
+++ b/core/tests/coretests/Android.mk
@@ -36,12 +36,12 @@
frameworks-core-util-lib \
mockwebserver \
guava \
- android-support-test \
+ androidx.test.runner \
+ androidx.test.rules \
mockito-target-minus-junit4 \
espresso-core \
ub-uiautomator \
platform-test-annotations \
- compatibility-device-util \
truth-prebuilt \
print-test-util-lib \
testng # TODO: remove once Android migrates to JUnit 4.12, which provide assertThrows
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 46d4a47..e80cb6d 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -1425,7 +1425,7 @@
</application>
- <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.frameworks.coretests"
android:label="Frameworks Core Tests" />
<key-sets>
diff --git a/core/tests/coretests/AndroidTest.xml b/core/tests/coretests/AndroidTest.xml
index 68ef34b..b40aa87 100644
--- a/core/tests/coretests/AndroidTest.xml
+++ b/core/tests/coretests/AndroidTest.xml
@@ -25,6 +25,7 @@
<option name="test-tag" value="FrameworksCoreTests" />
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.frameworks.coretests" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
<option name="hidden-api-checks" value="false"/>
</test>
</configuration>
diff --git a/core/tests/coretests/src/android/animation/AnimatorInflaterTest.java b/core/tests/coretests/src/android/animation/AnimatorInflaterTest.java
index e26bdf5..be1d44c 100644
--- a/core/tests/coretests/src/android/animation/AnimatorInflaterTest.java
+++ b/core/tests/coretests/src/android/animation/AnimatorInflaterTest.java
@@ -13,17 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.animation;
-import android.support.test.filters.LargeTest;
import android.test.ActivityInstrumentationTestCase2;
+import androidx.test.filters.LargeTest;
+
+import com.android.frameworks.coretests.R;
+
import java.util.HashSet;
import java.util.Set;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-import com.android.frameworks.coretests.R;
@LargeTest
public class AnimatorInflaterTest extends ActivityInstrumentationTestCase2<BasicAnimatorActivity> {
diff --git a/core/tests/coretests/src/android/animation/AnimatorSetActivity.java b/core/tests/coretests/src/android/animation/AnimatorSetActivity.java
index 501ea48..af265af 100644
--- a/core/tests/coretests/src/android/animation/AnimatorSetActivity.java
+++ b/core/tests/coretests/src/android/animation/AnimatorSetActivity.java
@@ -1,10 +1,26 @@
-package android.animation;
+/*
+ * Copyright (C) 2015 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.
+ */
-import com.android.frameworks.coretests.R;
+package android.animation;
import android.app.Activity;
import android.os.Bundle;
+import com.android.frameworks.coretests.R;
+
public class AnimatorSetActivity extends Activity {
@Override
public void onCreate(Bundle savedBundleInstance) {
diff --git a/core/tests/coretests/src/android/animation/AnimatorSetActivityTest.java b/core/tests/coretests/src/android/animation/AnimatorSetActivityTest.java
index 922bc59..55837ba 100644
--- a/core/tests/coretests/src/android/animation/AnimatorSetActivityTest.java
+++ b/core/tests/coretests/src/android/animation/AnimatorSetActivityTest.java
@@ -1,12 +1,29 @@
+/*
+ * Copyright (C) 2015 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.animation;
-import com.android.frameworks.coretests.R;
-
import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.test.suitebuilder.annotation.SmallTest;
import android.view.View;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.SmallTest;
+
+import com.android.frameworks.coretests.R;
+
import java.util.ArrayList;
public class AnimatorSetActivityTest extends ActivityInstrumentationTestCase2<AnimatorSetActivity> {
diff --git a/core/tests/coretests/src/android/animation/AnimatorSetEventsTest.java b/core/tests/coretests/src/android/animation/AnimatorSetEventsTest.java
index 7eb32ee..4e90d1a 100644
--- a/core/tests/coretests/src/android/animation/AnimatorSetEventsTest.java
+++ b/core/tests/coretests/src/android/animation/AnimatorSetEventsTest.java
@@ -13,12 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.animation;
import android.os.Handler;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
import android.widget.Button;
+
+import androidx.test.filters.MediumTest;
+
import com.android.frameworks.coretests.R;
import java.util.concurrent.TimeUnit;
diff --git a/core/tests/coretests/src/android/animation/AutoCancelTest.java b/core/tests/coretests/src/android/animation/AutoCancelTest.java
index b1f88db..b3ec92c 100644
--- a/core/tests/coretests/src/android/animation/AutoCancelTest.java
+++ b/core/tests/coretests/src/android/animation/AutoCancelTest.java
@@ -13,11 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.animation;
import android.os.Handler;
import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;
diff --git a/core/tests/coretests/src/android/animation/BasicAnimatorActivity.java b/core/tests/coretests/src/android/animation/BasicAnimatorActivity.java
index 0e1e6ac..2b9866d 100644
--- a/core/tests/coretests/src/android/animation/BasicAnimatorActivity.java
+++ b/core/tests/coretests/src/android/animation/BasicAnimatorActivity.java
@@ -13,14 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.animation;
-import com.android.frameworks.coretests.R;
+package android.animation;
import android.app.Activity;
import android.os.Bundle;
import android.widget.Button;
+import com.android.frameworks.coretests.R;
+
public class BasicAnimatorActivity extends Activity {
public Button mAnimatingButton;
@Override
diff --git a/core/tests/coretests/src/android/animation/EventsTest.java b/core/tests/coretests/src/android/animation/EventsTest.java
index 28cfe3d..ba7413a 100644
--- a/core/tests/coretests/src/android/animation/EventsTest.java
+++ b/core/tests/coretests/src/android/animation/EventsTest.java
@@ -13,13 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.animation;
import android.os.Handler;
import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
diff --git a/core/tests/coretests/src/android/animation/FutureWaiter.java b/core/tests/coretests/src/android/animation/FutureWaiter.java
index 0c65e20..0c09a4a 100644
--- a/core/tests/coretests/src/android/animation/FutureWaiter.java
+++ b/core/tests/coretests/src/android/animation/FutureWaiter.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.animation;
import com.google.common.util.concurrent.AbstractFuture;
diff --git a/core/tests/coretests/src/android/animation/ObjectAnimatorEventsTest.java b/core/tests/coretests/src/android/animation/ObjectAnimatorEventsTest.java
index 606a939..53f9472 100644
--- a/core/tests/coretests/src/android/animation/ObjectAnimatorEventsTest.java
+++ b/core/tests/coretests/src/android/animation/ObjectAnimatorEventsTest.java
@@ -13,9 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.animation;
import android.widget.Button;
+
import com.android.frameworks.coretests.R;
/**
diff --git a/core/tests/coretests/src/android/animation/StateListAnimatorTest.java b/core/tests/coretests/src/android/animation/StateListAnimatorTest.java
index a9961e1..e755b89 100644
--- a/core/tests/coretests/src/android/animation/StateListAnimatorTest.java
+++ b/core/tests/coretests/src/android/animation/StateListAnimatorTest.java
@@ -14,16 +14,16 @@
* limitations under the License.
*/
-
package android.animation;
-import android.support.test.filters.LargeTest;
import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
import android.util.StateSet;
import android.view.View;
import android.view.ViewGroup;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.LargeTest;
+
import com.android.frameworks.coretests.R;
import java.util.concurrent.atomic.AtomicInteger;
diff --git a/core/tests/coretests/src/android/animation/ValueAnimatorEventsTest.java b/core/tests/coretests/src/android/animation/ValueAnimatorEventsTest.java
index c25d050..f6d71b8 100644
--- a/core/tests/coretests/src/android/animation/ValueAnimatorEventsTest.java
+++ b/core/tests/coretests/src/android/animation/ValueAnimatorEventsTest.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.animation;
/**
diff --git a/core/tests/coretests/src/android/animation/ValueAnimatorTests.java b/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
index 4facf77..dee0a3e 100644
--- a/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
+++ b/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
@@ -13,8 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.animation;
+import static android.test.MoreAsserts.assertNotEqual;
+
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull;
@@ -24,23 +27,20 @@
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
-import android.support.test.annotation.UiThreadTest;
-import android.support.test.filters.MediumTest;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
import android.view.Choreographer;
import android.view.animation.LinearInterpolator;
+import androidx.test.filters.MediumTest;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.After;
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.ArrayList;
-import static android.test.MoreAsserts.assertNotEqual;
-
@RunWith(AndroidJUnit4.class)
@MediumTest
public class ValueAnimatorTests {
diff --git a/core/tests/coretests/src/android/animation/ViewPropertyAnimatorTest.java b/core/tests/coretests/src/android/animation/ViewPropertyAnimatorTest.java
index 30ec182..997af00 100644
--- a/core/tests/coretests/src/android/animation/ViewPropertyAnimatorTest.java
+++ b/core/tests/coretests/src/android/animation/ViewPropertyAnimatorTest.java
@@ -13,15 +13,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.animation;
import android.os.Handler;
import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
import android.view.ViewPropertyAnimator;
import android.widget.Button;
+
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
+
import com.android.frameworks.coretests.R;
import java.util.concurrent.TimeUnit;
diff --git a/core/tests/coretests/src/android/app/ApplicationErrorReportTest.java b/core/tests/coretests/src/android/app/ApplicationErrorReportTest.java
index 19a390a..8dc5ad6 100644
--- a/core/tests/coretests/src/android/app/ApplicationErrorReportTest.java
+++ b/core/tests/coretests/src/android/app/ApplicationErrorReportTest.java
@@ -16,16 +16,17 @@
package android.app;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import android.app.ApplicationErrorReport.CrashInfo;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import android.app.ApplicationErrorReport.CrashInfo;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(AndroidJUnit4.class)
@SmallTest
public class ApplicationErrorReportTest {
diff --git a/core/tests/coretests/src/android/app/ApplicationPackageManagerTest.java b/core/tests/coretests/src/android/app/ApplicationPackageManagerTest.java
index 063bef7..4b0ed65 100644
--- a/core/tests/coretests/src/android/app/ApplicationPackageManagerTest.java
+++ b/core/tests/coretests/src/android/app/ApplicationPackageManagerTest.java
@@ -16,13 +16,17 @@
package android.app;
+import static android.os.storage.VolumeInfo.STATE_MOUNTED;
+import static android.os.storage.VolumeInfo.STATE_UNMOUNTED;
+
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
import junit.framework.TestCase;
@@ -32,9 +36,6 @@
import java.util.Arrays;
import java.util.List;
-import static android.os.storage.VolumeInfo.STATE_MOUNTED;
-import static android.os.storage.VolumeInfo.STATE_UNMOUNTED;
-
@LargeTest
public class ApplicationPackageManagerTest extends TestCase {
private static final String sInternalVolPath = "/data";
diff --git a/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java b/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java
index c1d4be0..33e0402 100644
--- a/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java
+++ b/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java
@@ -22,7 +22,8 @@
import android.net.Uri;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
import com.google.mockwebserver.MockResponse;
diff --git a/core/tests/coretests/src/android/app/DownloadManagerStressTest.java b/core/tests/coretests/src/android/app/DownloadManagerStressTest.java
index 39d9a8e..adfe76f 100644
--- a/core/tests/coretests/src/android/app/DownloadManagerStressTest.java
+++ b/core/tests/coretests/src/android/app/DownloadManagerStressTest.java
@@ -23,10 +23,11 @@
import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.os.StatFs;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.Suppress;
import android.util.Log;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.Suppress;
+
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
diff --git a/core/tests/coretests/src/android/app/InstrumentationTest.java b/core/tests/coretests/src/android/app/InstrumentationTest.java
index 9b59da4..93b5aec 100644
--- a/core/tests/coretests/src/android/app/InstrumentationTest.java
+++ b/core/tests/coretests/src/android/app/InstrumentationTest.java
@@ -17,9 +17,10 @@
package android.app;
import android.os.Bundle;
-import android.support.test.filters.LargeTest;
import android.test.InstrumentationTestCase;
+import androidx.test.filters.LargeTest;
+
@LargeTest
public class InstrumentationTest extends InstrumentationTestCase {
diff --git a/core/tests/coretests/src/android/app/LoaderLifecycleTest.java b/core/tests/coretests/src/android/app/LoaderLifecycleTest.java
index c83e798..e343383 100644
--- a/core/tests/coretests/src/android/app/LoaderLifecycleTest.java
+++ b/core/tests/coretests/src/android/app/LoaderLifecycleTest.java
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
package android.app;
import static junit.framework.TestCase.assertNotNull;
@@ -27,11 +26,12 @@
import android.content.Context;
import android.os.Handler;
import android.os.Parcelable;
-import android.support.test.filters.MediumTest;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
import android.util.ArrayMap;
+import androidx.test.filters.MediumTest;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java
index e89a4d3..c17aa92 100644
--- a/core/tests/coretests/src/android/app/NotificationTest.java
+++ b/core/tests/coretests/src/android/app/NotificationTest.java
@@ -33,11 +33,12 @@
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.widget.RemoteViews;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/app/SearchManagerTest.java b/core/tests/coretests/src/android/app/SearchManagerTest.java
index 08b7f60..14370c8 100644
--- a/core/tests/coretests/src/android/app/SearchManagerTest.java
+++ b/core/tests/coretests/src/android/app/SearchManagerTest.java
@@ -17,17 +17,13 @@
package android.app;
import android.app.activity.LocalActivity;
-
-import android.app.Activity;
-import android.app.ISearchManager;
-import android.app.SearchManager;
-import android.app.SearchableInfo;
import android.content.ComponentName;
import android.content.Context;
import android.os.ServiceManager;
import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
/**
* To launch this test from the command line:
diff --git a/core/tests/coretests/src/android/app/activity/ActivityManagerTest.java b/core/tests/coretests/src/android/app/activity/ActivityManagerTest.java
index 61d73bc..bbd442d 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityManagerTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityManagerTest.java
@@ -21,8 +21,9 @@
import android.content.pm.ConfigurationInfo;
import android.content.res.Configuration;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.Suppress;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.filters.Suppress;
import java.util.Iterator;
import java.util.List;
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index 0f83a29..9cb3489 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -36,13 +36,14 @@
import android.content.Intent;
import android.content.res.Configuration;
import android.os.IBinder;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.MediumTest;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
import android.util.MergedConfiguration;
import android.view.Display;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.MediumTest;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/app/activity/BroadcastTest.java b/core/tests/coretests/src/android/app/activity/BroadcastTest.java
index 13e70eb..0f81896 100644
--- a/core/tests/coretests/src/android/app/activity/BroadcastTest.java
+++ b/core/tests/coretests/src/android/app/activity/BroadcastTest.java
@@ -27,11 +27,10 @@
import android.os.IBinder;
import android.os.Parcel;
import android.os.UserHandle;
-import android.support.test.filters.LargeTest;
-import android.test.FlakyTest;
import android.util.Log;
-import java.util.Arrays;
+import androidx.test.filters.FlakyTest;
+import androidx.test.filters.LargeTest;
@LargeTest
public class BroadcastTest extends ActivityTestsBase {
@@ -231,7 +230,7 @@
};
// Mark flaky until http://b/issue?id=1191607 is resolved.
- @FlakyTest(tolerance=2)
+ @FlakyTest
public void testRegistered() throws Exception {
runLaunchpad(LaunchpadActivity.BROADCAST_REGISTERED);
}
@@ -248,12 +247,12 @@
runLaunchpad(LaunchpadActivity.BROADCAST_ABORT);
}
- @FlakyTest(tolerance=2)
+ @FlakyTest
public void testAll() throws Exception {
runLaunchpad(LaunchpadActivity.BROADCAST_ALL);
}
- @FlakyTest(tolerance=2)
+ @FlakyTest
public void testMulti() throws Exception {
runLaunchpad(LaunchpadActivity.BROADCAST_MULTI);
}
@@ -348,7 +347,7 @@
}
// Marking flaky until http://b/issue?id=1191337 is resolved
- @FlakyTest(tolerance=2)
+ @FlakyTest
public void testReceiveSticky() throws Exception {
Intent intent = new Intent(LaunchpadActivity.BROADCAST_STICKY1, null);
intent.putExtra("test", LaunchpadActivity.DATA_1);
@@ -358,7 +357,7 @@
}
// Marking flaky until http://b/issue?id=1191337 is resolved
- @FlakyTest(tolerance=2)
+ @FlakyTest
public void testReceive2Sticky() throws Exception {
Intent intent = new Intent(LaunchpadActivity.BROADCAST_STICKY1, null);
intent.putExtra("test", LaunchpadActivity.DATA_1);
diff --git a/core/tests/coretests/src/android/app/activity/IntentSenderTest.java b/core/tests/coretests/src/android/app/activity/IntentSenderTest.java
index 8c1d79b..19ddb52 100644
--- a/core/tests/coretests/src/android/app/activity/IntentSenderTest.java
+++ b/core/tests/coretests/src/android/app/activity/IntentSenderTest.java
@@ -21,7 +21,8 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
@LargeTest
public class IntentSenderTest extends BroadcastTest {
diff --git a/core/tests/coretests/src/android/app/activity/LaunchTest.java b/core/tests/coretests/src/android/app/activity/LaunchTest.java
index 5b86dce..6846ea7 100644
--- a/core/tests/coretests/src/android/app/activity/LaunchTest.java
+++ b/core/tests/coretests/src/android/app/activity/LaunchTest.java
@@ -17,8 +17,9 @@
package android.app.activity;
import android.content.ComponentName;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.Suppress;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.Suppress;
@Suppress // Flaky.
public class LaunchTest extends ActivityTestsBase {
diff --git a/core/tests/coretests/src/android/app/activity/LifecycleTest.java b/core/tests/coretests/src/android/app/activity/LifecycleTest.java
index ed01fac5..5aa0380 100644
--- a/core/tests/coretests/src/android/app/activity/LifecycleTest.java
+++ b/core/tests/coretests/src/android/app/activity/LifecycleTest.java
@@ -18,8 +18,9 @@
import android.content.ComponentName;
import android.content.Intent;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
public class LifecycleTest extends ActivityTestsBase {
private Intent mTopIntent;
diff --git a/core/tests/coretests/src/android/app/activity/MetaDataTest.java b/core/tests/coretests/src/android/app/activity/MetaDataTest.java
index 5b9c0e9..cf27878 100644
--- a/core/tests/coretests/src/android/app/activity/MetaDataTest.java
+++ b/core/tests/coretests/src/android/app/activity/MetaDataTest.java
@@ -27,8 +27,11 @@
import android.content.res.XmlResourceParser;
import android.os.Bundle;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
+
import com.android.frameworks.coretests.R;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/core/tests/coretests/src/android/app/activity/RemoteSubActivityScreen.java b/core/tests/coretests/src/android/app/activity/RemoteSubActivityScreen.java
index 9f402a5..8184627 100644
--- a/core/tests/coretests/src/android/app/activity/RemoteSubActivityScreen.java
+++ b/core/tests/coretests/src/android/app/activity/RemoteSubActivityScreen.java
@@ -1,19 +1,18 @@
-/* //device/apps/AndroidTests/src/com.android.unit_tests/activity/TestedScreen.java
-**
-** Copyright 2006, 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.
-*/
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package android.app.activity;
@@ -21,7 +20,8 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.Process;
-import android.util.Log;
+
+//device/apps/AndroidTests/src/com.android.unit_tests/activity/TestedScreen.java
public class RemoteSubActivityScreen extends SubActivityScreen {
Handler mHandler = new Handler();
diff --git a/core/tests/coretests/src/android/app/activity/ServiceTest.java b/core/tests/coretests/src/android/app/activity/ServiceTest.java
index d3ae415..9d2aebd 100644
--- a/core/tests/coretests/src/android/app/activity/ServiceTest.java
+++ b/core/tests/coretests/src/android/app/activity/ServiceTest.java
@@ -22,13 +22,12 @@
import android.content.ServiceConnection;
import android.os.Binder;
import android.os.Bundle;
-import android.os.RemoteException;
import android.os.IBinder;
import android.os.Parcel;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.Suppress;
-import android.util.Log;
+import android.os.RemoteException;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
// These test binders purport to support an interface whose canonical
// interface name is ServiceTest.SERVICE_LOCAL
diff --git a/core/tests/coretests/src/android/app/activity/SetTimeZonePermissionsTest.java b/core/tests/coretests/src/android/app/activity/SetTimeZonePermissionsTest.java
index 41b9547..8e17295 100644
--- a/core/tests/coretests/src/android/app/activity/SetTimeZonePermissionsTest.java
+++ b/core/tests/coretests/src/android/app/activity/SetTimeZonePermissionsTest.java
@@ -19,7 +19,8 @@
import android.app.AlarmManager;
import android.content.Context;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
import java.util.TimeZone;
diff --git a/core/tests/coretests/src/android/app/activity/SubActivityTest.java b/core/tests/coretests/src/android/app/activity/SubActivityTest.java
index 35dde8a..53f89fe 100644
--- a/core/tests/coretests/src/android/app/activity/SubActivityTest.java
+++ b/core/tests/coretests/src/android/app/activity/SubActivityTest.java
@@ -16,9 +16,10 @@
package android.app.activity;
-import android.test.suitebuilder.annotation.Suppress;
import android.content.ComponentName;
+import androidx.test.filters.Suppress;
+
@Suppress
public class SubActivityTest extends ActivityTestsBase {
diff --git a/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java b/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java
index 9b5b725..8d42c74 100644
--- a/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java
+++ b/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java
@@ -27,8 +27,9 @@
import android.app.admin.PasswordMetrics.PasswordComplexityBucket;
import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/app/assist/AssistStructureTest.java b/core/tests/coretests/src/android/app/assist/AssistStructureTest.java
index 689e683..1f4e5df 100644
--- a/core/tests/coretests/src/android/app/assist/AssistStructureTest.java
+++ b/core/tests/coretests/src/android/app/assist/AssistStructureTest.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.app.assist;
import static android.view.View.AUTOFILL_TYPE_TEXT;
@@ -22,13 +23,9 @@
import static com.google.common.truth.Truth.assertThat;
import android.app.assist.AssistStructure.ViewNode;
-import android.content.ComponentName;
import android.content.Context;
import android.os.Parcel;
import android.os.SystemClock;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
import android.text.InputFilter;
import android.util.Log;
import android.view.autofill.AutofillId;
@@ -37,6 +34,10 @@
import android.widget.LinearLayout;
import android.widget.TextView;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/app/assist/EmptyLayoutActivity.java b/core/tests/coretests/src/android/app/assist/EmptyLayoutActivity.java
index f4b6bed..defec43 100644
--- a/core/tests/coretests/src/android/app/assist/EmptyLayoutActivity.java
+++ b/core/tests/coretests/src/android/app/assist/EmptyLayoutActivity.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.app.assist;
import android.app.Activity;
diff --git a/core/tests/coretests/src/android/app/backup/BackupDataTest.java b/core/tests/coretests/src/android/app/backup/BackupDataTest.java
index 5b8e481..18ff54f 100644
--- a/core/tests/coretests/src/android/app/backup/BackupDataTest.java
+++ b/core/tests/coretests/src/android/app/backup/BackupDataTest.java
@@ -16,31 +16,22 @@
package android.app.backup;
-import android.app.backup.BackupDataInput;
-import android.app.backup.BackupDataOutput;
-import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.os.Bundle;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
-import android.support.test.filters.LargeTest;
import android.test.AndroidTestCase;
-import android.test.InstrumentationTestCase;
import android.util.Base64;
-import android.util.Log;
-import org.json.JSONObject;
+
+import androidx.test.filters.LargeTest;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
-import java.io.FileReader;
import java.io.IOException;
-import java.io.InputStream;
import java.io.InputStreamReader;
-import java.lang.Exception;
-import java.nio.ByteBuffer;
@LargeTest
public class BackupDataTest extends AndroidTestCase {
diff --git a/core/tests/coretests/src/android/app/backup/FullBackupTest.java b/core/tests/coretests/src/android/app/backup/FullBackupTest.java
index 5db416b..08edb4e 100644
--- a/core/tests/coretests/src/android/app/backup/FullBackupTest.java
+++ b/core/tests/coretests/src/android/app/backup/FullBackupTest.java
@@ -18,11 +18,12 @@
import android.app.backup.FullBackup.BackupScheme.PathWithRequiredFlags;
import android.content.Context;
-import android.support.test.filters.LargeTest;
import android.test.AndroidTestCase;
import android.util.ArrayMap;
import android.util.ArraySet;
+import androidx.test.filters.LargeTest;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
diff --git a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionTests.java b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionTests.java
index b1f8552..52b2658 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionTests.java
@@ -23,8 +23,9 @@
import android.app.ClientTransactionHandler;
import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
index fb0f534..ad28d13 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
@@ -35,8 +35,9 @@
import android.os.Bundle;
import android.os.PersistableBundle;
import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java
index a788a93..f730a24 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java
@@ -45,10 +45,11 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.util.ArrayMap;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index 2801f324..8604b0c 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -50,8 +50,9 @@
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import com.android.internal.app.IVoiceInteractor;
diff --git a/core/tests/coretests/src/android/app/timezone/DistroFormatVersionTest.java b/core/tests/coretests/src/android/app/timezone/DistroFormatVersionTest.java
index e20645c..0efc0ab 100644
--- a/core/tests/coretests/src/android/app/timezone/DistroFormatVersionTest.java
+++ b/core/tests/coretests/src/android/app/timezone/DistroFormatVersionTest.java
@@ -21,7 +21,8 @@
import static org.junit.Assert.assertTrue;
import android.os.Parcel;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/app/timezone/DistroRulesVersionTest.java b/core/tests/coretests/src/android/app/timezone/DistroRulesVersionTest.java
index b69054c..b519bf8 100644
--- a/core/tests/coretests/src/android/app/timezone/DistroRulesVersionTest.java
+++ b/core/tests/coretests/src/android/app/timezone/DistroRulesVersionTest.java
@@ -21,7 +21,8 @@
import static org.junit.Assert.assertTrue;
import android.os.Parcel;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/app/timezone/RulesStateTest.java b/core/tests/coretests/src/android/app/timezone/RulesStateTest.java
index dd46240..bb535b6 100644
--- a/core/tests/coretests/src/android/app/timezone/RulesStateTest.java
+++ b/core/tests/coretests/src/android/app/timezone/RulesStateTest.java
@@ -16,14 +16,13 @@
package android.app.timezone;
-import static junit.framework.Assert.fail;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import android.os.Parcel;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/app/timezone/RulesUpdaterContractTest.java b/core/tests/coretests/src/android/app/timezone/RulesUpdaterContractTest.java
index 4004086..df9ddea 100644
--- a/core/tests/coretests/src/android/app/timezone/RulesUpdaterContractTest.java
+++ b/core/tests/coretests/src/android/app/timezone/RulesUpdaterContractTest.java
@@ -25,7 +25,8 @@
import android.content.Context;
import android.content.Intent;
import android.os.UserHandle;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
diff --git a/core/tests/coretests/src/android/app/usage/EventListTest.java b/core/tests/coretests/src/android/app/usage/EventListTest.java
index 9dc0d43..685fcae 100644
--- a/core/tests/coretests/src/android/app/usage/EventListTest.java
+++ b/core/tests/coretests/src/android/app/usage/EventListTest.java
@@ -20,10 +20,11 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.util.Log;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/app/usage/UsageStatsTest.java b/core/tests/coretests/src/android/app/usage/UsageStatsTest.java
index 28aaf1e..1633e1a 100644
--- a/core/tests/coretests/src/android/app/usage/UsageStatsTest.java
+++ b/core/tests/coretests/src/android/app/usage/UsageStatsTest.java
@@ -21,6 +21,7 @@
import static android.app.usage.UsageEvents.Event.ACTIVITY_RESUMED;
import static android.app.usage.UsageEvents.Event.ACTIVITY_STOPPED;
import static android.app.usage.UsageEvents.Event.CONTINUING_FOREGROUND_SERVICE;
+import static android.app.usage.UsageEvents.Event.DEVICE_SHUTDOWN;
import static android.app.usage.UsageEvents.Event.END_OF_DAY;
import static android.app.usage.UsageEvents.Event.FLUSH_TO_DISK;
import static android.app.usage.UsageEvents.Event.FOREGROUND_SERVICE_START;
@@ -33,8 +34,9 @@
import android.app.usage.UsageEvents.Event;
import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
@@ -528,6 +530,11 @@
}
@Test
+ public void testEvent_DEVICE_SHUTDOWN() {
+ testClosingEvent(DEVICE_SHUTDOWN);
+ }
+
+ @Test
public void testEvent_FLUSH_TO_DISK() {
testClosingEvent(FLUSH_TO_DISK);
}
@@ -535,8 +542,9 @@
private void testClosingEvent(int eventType) {
// When these three closing events are received, all open activities/services need to be
// closed and usage stats are updated.
- if (eventType != FLUSH_TO_DISK) {
- fail("Closing eventType must be one of FLUSH_TO_DISK");
+ if (eventType != DEVICE_SHUTDOWN
+ && eventType != FLUSH_TO_DISK) {
+ fail("Closing eventType must be one of DEVICE_SHUTDOWN, FLUSH_TO_DISK");
}
left.mPackageName = "com.test";
diff --git a/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java b/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java
index 978ea7a..c307e64 100644
--- a/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java
+++ b/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java
@@ -16,7 +16,6 @@
package android.content;
-
import static org.junit.Assert.fail;
import android.app.ActivityManager;
@@ -30,9 +29,10 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Before;
diff --git a/core/tests/coretests/src/android/content/AssetTest.java b/core/tests/coretests/src/android/content/AssetTest.java
index b66574c..8e55e8a 100644
--- a/core/tests/coretests/src/android/content/AssetTest.java
+++ b/core/tests/coretests/src/android/content/AssetTest.java
@@ -18,7 +18,8 @@
import android.content.res.AssetManager;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
import java.io.IOException;
import java.io.InputStream;
diff --git a/core/tests/coretests/src/android/content/BrickDeniedTest.java b/core/tests/coretests/src/android/content/BrickDeniedTest.java
index 3d246b4..d8c9baa 100644
--- a/core/tests/coretests/src/android/content/BrickDeniedTest.java
+++ b/core/tests/coretests/src/android/content/BrickDeniedTest.java
@@ -17,7 +17,8 @@
package android.content;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
/** Test to make sure brick intents <b>don't</b> work without permission. */
public class BrickDeniedTest extends AndroidTestCase {
diff --git a/core/tests/coretests/src/android/content/BroadcastReceiverTests.java b/core/tests/coretests/src/android/content/BroadcastReceiverTests.java
index 8deccb7..1509ff9 100644
--- a/core/tests/coretests/src/android/content/BroadcastReceiverTests.java
+++ b/core/tests/coretests/src/android/content/BroadcastReceiverTests.java
@@ -18,9 +18,9 @@
import static org.junit.Assert.fail;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/content/ContentProviderOperationTest.java b/core/tests/coretests/src/android/content/ContentProviderOperationTest.java
index aea124b..b142761 100644
--- a/core/tests/coretests/src/android/content/ContentProviderOperationTest.java
+++ b/core/tests/coretests/src/android/content/ContentProviderOperationTest.java
@@ -16,22 +16,23 @@
package android.content;
-import android.content.ContentValues;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
import android.os.Parcel;
-import android.test.suitebuilder.annotation.SmallTest;
import android.text.TextUtils;
+
+import androidx.test.filters.SmallTest;
+
import junit.framework.TestCase;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
-import java.util.Set;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.Set;
@SmallTest
public class ContentProviderOperationTest extends TestCase {
diff --git a/core/tests/coretests/src/android/content/ContentProviderTest.java b/core/tests/coretests/src/android/content/ContentProviderTest.java
index 2142f27..8895f9b 100644
--- a/core/tests/coretests/src/android/content/ContentProviderTest.java
+++ b/core/tests/coretests/src/android/content/ContentProviderTest.java
@@ -23,7 +23,8 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.ProviderInfo;
import android.net.Uri;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/content/ContentQueryMapTest.java b/core/tests/coretests/src/android/content/ContentQueryMapTest.java
index f47bfdb..7106234 100644
--- a/core/tests/coretests/src/android/content/ContentQueryMapTest.java
+++ b/core/tests/coretests/src/android/content/ContentQueryMapTest.java
@@ -16,16 +16,14 @@
package android.content;
-import android.content.ContentQueryMap;
-import android.content.ContentResolver;
-import android.content.ContentValues;
import android.database.Cursor;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
import java.util.Observable;
import java.util.Observer;
diff --git a/core/tests/coretests/src/android/content/ContentResolverTest.java b/core/tests/coretests/src/android/content/ContentResolverTest.java
index 9940bf7..f14f289 100644
--- a/core/tests/coretests/src/android/content/ContentResolverTest.java
+++ b/core/tests/coretests/src/android/content/ContentResolverTest.java
@@ -31,10 +31,11 @@
import android.net.Uri;
import android.os.MemoryFile;
import android.os.ParcelFileDescriptor;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
import android.util.Size;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/content/ContentValuesTest.java b/core/tests/coretests/src/android/content/ContentValuesTest.java
index 7b39939..0ab79e7 100644
--- a/core/tests/coretests/src/android/content/ContentValuesTest.java
+++ b/core/tests/coretests/src/android/content/ContentValuesTest.java
@@ -17,8 +17,8 @@
package android.content;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.SmallTest;
/*
runtest -c android.content.ContentValuesTest frameworks-core
@@ -29,7 +29,7 @@
adb shell pm uninstall -k com.android.frameworks.coretests && \
adb install out/target/product/bullhead/testcases/FrameworksCoreTests/FrameworksCoreTests.apk && \
adb shell am instrument -w -e package android.content \
- com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
+ com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner
*/
public class ContentValuesTest extends AndroidTestCase {
diff --git a/core/tests/coretests/src/android/content/ContextTest.java b/core/tests/coretests/src/android/content/ContextTest.java
index c8a3098..2f442c3 100644
--- a/core/tests/coretests/src/android/content/ContextTest.java
+++ b/core/tests/coretests/src/android/content/ContextTest.java
@@ -19,11 +19,12 @@
import static org.junit.Assert.assertEquals;
import android.app.ActivityThread;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.view.WindowManager;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/content/ManagedUserContentResolverTest.java b/core/tests/coretests/src/android/content/ManagedUserContentResolverTest.java
index 4362ec3..22b2314 100644
--- a/core/tests/coretests/src/android/content/ManagedUserContentResolverTest.java
+++ b/core/tests/coretests/src/android/content/ManagedUserContentResolverTest.java
@@ -19,7 +19,8 @@
import android.content.pm.UserInfo;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
/**
* To run the tests, use
@@ -32,7 +33,7 @@
* Install: adb install -r \
* ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
* Run: adb shell am instrument -e class android.content.ManagedUserContentResolverTest -w \
- * com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
+ * com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner
*/
@LargeTest
public class ManagedUserContentResolverTest extends AbstractCrossUserContentResolverTest {
diff --git a/core/tests/coretests/src/android/content/MemoryFileProviderTest.java b/core/tests/coretests/src/android/content/MemoryFileProviderTest.java
index bbe7c10..7cd4862 100644
--- a/core/tests/coretests/src/android/content/MemoryFileProviderTest.java
+++ b/core/tests/coretests/src/android/content/MemoryFileProviderTest.java
@@ -18,9 +18,10 @@
import android.net.Uri;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
import java.io.InputStream;
import java.util.Arrays;
diff --git a/core/tests/coretests/src/android/content/RestrictionsManagerTest.java b/core/tests/coretests/src/android/content/RestrictionsManagerTest.java
index 10d74f7..fd5de32 100644
--- a/core/tests/coretests/src/android/content/RestrictionsManagerTest.java
+++ b/core/tests/coretests/src/android/content/RestrictionsManagerTest.java
@@ -13,13 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License
*/
+
package android.content;
import android.os.Bundle;
import android.os.Parcelable;
-import android.support.test.filters.LargeTest;
import android.test.AndroidTestCase;
+import androidx.test.filters.LargeTest;
+
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
diff --git a/core/tests/coretests/src/android/content/SecondaryUserContentResolverTest.java b/core/tests/coretests/src/android/content/SecondaryUserContentResolverTest.java
index f8b13f0..dbe0278 100644
--- a/core/tests/coretests/src/android/content/SecondaryUserContentResolverTest.java
+++ b/core/tests/coretests/src/android/content/SecondaryUserContentResolverTest.java
@@ -18,7 +18,8 @@
import android.content.pm.UserInfo;
import android.os.RemoteException;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
/**
* To run the tests, use
@@ -31,7 +32,7 @@
* Install: adb install -r \
* ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
* Run: adb shell am instrument -e class android.content.SecondaryUserContentResolverTest -w \
- * com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
+ * com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner
*/
@LargeTest
public class SecondaryUserContentResolverTest extends AbstractCrossUserContentResolverTest {
diff --git a/core/tests/coretests/src/android/content/UriMatcherTest.java b/core/tests/coretests/src/android/content/UriMatcherTest.java
index f3b9e76..6cef46b 100644
--- a/core/tests/coretests/src/android/content/UriMatcherTest.java
+++ b/core/tests/coretests/src/android/content/UriMatcherTest.java
@@ -17,14 +17,14 @@
package android.content;
import android.net.Uri;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
import junit.framework.TestCase;
import java.lang.reflect.Field;
import java.util.ArrayList;
-
public class UriMatcherTest extends TestCase {
static final int ROOT = 0;
diff --git a/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java b/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java
index 2acb08d..9b360db 100644
--- a/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java
+++ b/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.content.pm;
import static android.content.pm.PackageBuilder.builder;
@@ -20,7 +21,8 @@
import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_MANAGER;
import android.os.Build;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/content/pm/AndroidTestBaseUpdaterTest.java b/core/tests/coretests/src/android/content/pm/AndroidTestBaseUpdaterTest.java
index dce22ce..0ed76dc 100644
--- a/core/tests/coretests/src/android/content/pm/AndroidTestBaseUpdaterTest.java
+++ b/core/tests/coretests/src/android/content/pm/AndroidTestBaseUpdaterTest.java
@@ -13,13 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.content.pm;
import static android.content.pm.PackageBuilder.builder;
import static android.content.pm.SharedLibraryNames.ANDROID_TEST_BASE;
import android.os.Build;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/content/pm/AndroidTestRunnerSplitUpdaterTest.java b/core/tests/coretests/src/android/content/pm/AndroidTestRunnerSplitUpdaterTest.java
index 866de93..7f817d6 100644
--- a/core/tests/coretests/src/android/content/pm/AndroidTestRunnerSplitUpdaterTest.java
+++ b/core/tests/coretests/src/android/content/pm/AndroidTestRunnerSplitUpdaterTest.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.content.pm;
import static android.content.pm.PackageBuilder.builder;
@@ -20,7 +21,8 @@
import static android.content.pm.SharedLibraryNames.ANDROID_TEST_RUNNER;
import android.content.pm.PackageBackwardCompatibility.AndroidTestRunnerSplitUpdater;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/content/pm/ComponentTest.java b/core/tests/coretests/src/android/content/pm/ComponentTest.java
index cc75641..f31f0b5 100644
--- a/core/tests/coretests/src/android/content/pm/ComponentTest.java
+++ b/core/tests/coretests/src/android/content/pm/ComponentTest.java
@@ -21,7 +21,14 @@
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
import static android.content.pm.PackageManager.GET_DISABLED_COMPONENTS;
-import android.test.suitebuilder.annotation.Suppress;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.test.AndroidTestCase;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.filters.Suppress;
+
import com.android.frameworks.coretests.enabled_app.DisabledActivity;
import com.android.frameworks.coretests.enabled_app.DisabledProvider;
import com.android.frameworks.coretests.enabled_app.DisabledReceiver;
@@ -31,12 +38,6 @@
import com.android.frameworks.coretests.enabled_app.EnabledReceiver;
import com.android.frameworks.coretests.enabled_app.EnabledService;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
-
import java.util.List;
/**
diff --git a/core/tests/coretests/src/android/content/pm/LimitedLengthInputStreamTest.java b/core/tests/coretests/src/android/content/pm/LimitedLengthInputStreamTest.java
index 1f762fd..1c703ab 100644
--- a/core/tests/coretests/src/android/content/pm/LimitedLengthInputStreamTest.java
+++ b/core/tests/coretests/src/android/content/pm/LimitedLengthInputStreamTest.java
@@ -17,7 +17,8 @@
package android.content.pm;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
+
+import androidx.test.filters.MediumTest;
import java.io.ByteArrayInputStream;
import java.io.IOException;
diff --git a/core/tests/coretests/src/android/content/pm/MacAuthenticatedInputStreamTest.java b/core/tests/coretests/src/android/content/pm/MacAuthenticatedInputStreamTest.java
index 659f9ea..1ddd753 100644
--- a/core/tests/coretests/src/android/content/pm/MacAuthenticatedInputStreamTest.java
+++ b/core/tests/coretests/src/android/content/pm/MacAuthenticatedInputStreamTest.java
@@ -16,9 +16,12 @@
package android.content.pm;
-import android.support.test.filters.LargeTest;
import android.test.AndroidTestCase;
+import androidx.test.filters.LargeTest;
+
+import libcore.io.Streams;
+
import java.io.ByteArrayInputStream;
import java.util.Arrays;
@@ -26,8 +29,6 @@
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
-import libcore.io.Streams;
-
@LargeTest
public class MacAuthenticatedInputStreamTest extends AndroidTestCase {
diff --git a/core/tests/coretests/src/android/content/pm/OptionalClassRunner.java b/core/tests/coretests/src/android/content/pm/OptionalClassRunner.java
index 91697c0..05db8ee 100644
--- a/core/tests/coretests/src/android/content/pm/OptionalClassRunner.java
+++ b/core/tests/coretests/src/android/content/pm/OptionalClassRunner.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.content.pm;
import org.junit.Assume;
diff --git a/core/tests/coretests/src/android/content/pm/OrgApacheHttpLegacyUpdaterTest.java b/core/tests/coretests/src/android/content/pm/OrgApacheHttpLegacyUpdaterTest.java
index dcd2707..834a0bb 100644
--- a/core/tests/coretests/src/android/content/pm/OrgApacheHttpLegacyUpdaterTest.java
+++ b/core/tests/coretests/src/android/content/pm/OrgApacheHttpLegacyUpdaterTest.java
@@ -13,13 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.content.pm;
import static android.content.pm.PackageBuilder.builder;
import static android.content.pm.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
import android.os.Build;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/content/pm/PackageBackwardCompatibilityTest.java b/core/tests/coretests/src/android/content/pm/PackageBackwardCompatibilityTest.java
index c64d520..3d7aab0 100644
--- a/core/tests/coretests/src/android/content/pm/PackageBackwardCompatibilityTest.java
+++ b/core/tests/coretests/src/android/content/pm/PackageBackwardCompatibilityTest.java
@@ -24,7 +24,8 @@
import android.content.pm.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary;
import android.os.Build;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
import org.junit.Assume;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/content/pm/PackageBuilder.java b/core/tests/coretests/src/android/content/pm/PackageBuilder.java
index 4ceed83..c5db962 100644
--- a/core/tests/coretests/src/android/content/pm/PackageBuilder.java
+++ b/core/tests/coretests/src/android/content/pm/PackageBuilder.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.content.pm;
import static org.junit.Assert.assertEquals;
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index 8ac9451d..0ab5367 100644
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -54,11 +54,12 @@
import android.system.Os;
import android.system.StructStat;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.Suppress;
import android.util.Log;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.filters.Suppress;
+
import com.android.frameworks.coretests.R;
import com.android.internal.content.PackageHelper;
diff --git a/core/tests/coretests/src/android/content/pm/PackageParserCacheHelperTest.java b/core/tests/coretests/src/android/content/pm/PackageParserCacheHelperTest.java
index 00be822..e852f98 100644
--- a/core/tests/coretests/src/android/content/pm/PackageParserCacheHelperTest.java
+++ b/core/tests/coretests/src/android/content/pm/PackageParserCacheHelperTest.java
@@ -22,8 +22,9 @@
import android.content.pm.PackageParserCacheHelper.WriteHelper;
import android.os.Bundle;
import android.os.Parcel;
-import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/content/pm/PackageParserTest.java b/core/tests/coretests/src/android/content/pm/PackageParserTest.java
index 267267e..be1b1ce 100644
--- a/core/tests/coretests/src/android/content/pm/PackageParserTest.java
+++ b/core/tests/coretests/src/android/content/pm/PackageParserTest.java
@@ -29,9 +29,10 @@
import android.os.Bundle;
import android.os.FileUtils;
import android.os.SystemProperties;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import com.android.frameworks.coretests.R;
@@ -51,6 +52,12 @@
private static final String PRE_RELEASE = "B";
private static final String NEWER_PRE_RELEASE = "C";
+ // Codenames with a fingerprint attached to them. These may only be present in the apps
+ // declared min SDK and not as platform codenames.
+ private static final String OLDER_PRE_RELEASE_WITH_FINGERPRINT = "A.fingerprint";
+ private static final String PRE_RELEASE_WITH_FINGERPRINT = "B.fingerprint";
+ private static final String NEWER_PRE_RELEASE_WITH_FINGERPRINT = "C.fingerprint";
+
private static final String[] CODENAMES_RELEASED = { /* empty */ };
private static final String[] CODENAMES_PRE_RELEASE = { PRE_RELEASE };
@@ -68,7 +75,7 @@
isPlatformReleased ? CODENAMES_RELEASED : CODENAMES_PRE_RELEASE,
outError);
- assertEquals(result, expectedMinSdk);
+ assertEquals("Error msg: " + outError[0], expectedMinSdk, result);
if (expectedMinSdk == -1) {
assertNotNull(outError[0]);
@@ -98,6 +105,7 @@
// APP: Pre-release API 10
// DEV: Pre-release API 20
verifyComputeMinSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, false, -1);
+ verifyComputeMinSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE_WITH_FINGERPRINT, false, -1);
// Do allow same pre-release minSdkVersion on pre-release platform,
// but overwrite the specified version with CUR_DEVELOPMENT.
@@ -105,11 +113,15 @@
// DEV: Pre-release API 20
verifyComputeMinSdkVersion(PLATFORM_VERSION, PRE_RELEASE, false,
Build.VERSION_CODES.CUR_DEVELOPMENT);
+ verifyComputeMinSdkVersion(PLATFORM_VERSION, PRE_RELEASE_WITH_FINGERPRINT, false,
+ Build.VERSION_CODES.CUR_DEVELOPMENT);
+
// Don't allow newer pre-release minSdkVersion on pre-release platform.
// APP: Pre-release API 30
// DEV: Pre-release API 20
verifyComputeMinSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, false, -1);
+ verifyComputeMinSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, false, -1);
}
@Test
@@ -133,16 +145,20 @@
// APP: Pre-release API 10
// DEV: Released API 20
verifyComputeMinSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, true, -1);
+ verifyComputeMinSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE_WITH_FINGERPRINT, true, -1);
// Don't allow same pre-release minSdkVersion on released platform.
// APP: Pre-release API 20
// DEV: Released API 20
verifyComputeMinSdkVersion(PLATFORM_VERSION, PRE_RELEASE, true, -1);
+ verifyComputeMinSdkVersion(PLATFORM_VERSION, PRE_RELEASE_WITH_FINGERPRINT, true, -1);
+
// Don't allow newer pre-release minSdkVersion on released platform.
// APP: Pre-release API 30
// DEV: Released API 20
verifyComputeMinSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, true, -1);
+ verifyComputeMinSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, true, -1);
}
private void verifyComputeTargetSdkVersion(int targetSdkVersion, String targetSdkCodename,
@@ -189,6 +205,9 @@
// DEV: Pre-release API 20
verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, false, -1,
false /* forceCurrentDev */);
+ verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE_WITH_FINGERPRINT, false, -1,
+ false /* forceCurrentDev */);
+
// Do allow same pre-release targetSdkVersion on pre-release platform,
// but overwrite the specified version with CUR_DEVELOPMENT.
@@ -196,18 +215,26 @@
// DEV: Pre-release API 20
verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE, false,
Build.VERSION_CODES.CUR_DEVELOPMENT, false /* forceCurrentDev */);
+ verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE_WITH_FINGERPRINT, false,
+ Build.VERSION_CODES.CUR_DEVELOPMENT, false /* forceCurrentDev */);
+
// Don't allow newer pre-release targetSdkVersion on pre-release platform.
// APP: Pre-release API 30
// DEV: Pre-release API 20
verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, false, -1,
false /* forceCurrentDev */);
+ verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, false, -1,
+ false /* forceCurrentDev */);
+
// Force newer pre-release targetSdkVersion to current pre-release platform.
// APP: Pre-release API 30
// DEV: Pre-release API 20
verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, false,
Build.VERSION_CODES.CUR_DEVELOPMENT, true /* forceCurrentDev */);
+ verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, false,
+ Build.VERSION_CODES.CUR_DEVELOPMENT, true /* forceCurrentDev */);
}
@Test
@@ -235,18 +262,25 @@
// DEV: Released API 20
verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, true, -1,
false /* forceCurrentDev */);
+ verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE_WITH_FINGERPRINT, true, -1,
+ false /* forceCurrentDev */);
// Don't allow same pre-release targetSdkVersion on released platform.
// APP: Pre-release API 20
// DEV: Released API 20
verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE, true, -1,
false /* forceCurrentDev */);
+ verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE_WITH_FINGERPRINT, true, -1,
+ false /* forceCurrentDev */);
+
// Don't allow newer pre-release targetSdkVersion on released platform.
// APP: Pre-release API 30
// DEV: Released API 20
verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, true, -1,
false /* forceCurrentDev */);
+ verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, true, -1,
+ false /* forceCurrentDev */);
}
/**
diff --git a/core/tests/coretests/src/android/content/pm/PackageSharedLibraryUpdaterTest.java b/core/tests/coretests/src/android/content/pm/PackageSharedLibraryUpdaterTest.java
index d5d3d7a..71a0e5e 100644
--- a/core/tests/coretests/src/android/content/pm/PackageSharedLibraryUpdaterTest.java
+++ b/core/tests/coretests/src/android/content/pm/PackageSharedLibraryUpdaterTest.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.content.pm;
import java.util.function.Supplier;
diff --git a/core/tests/coretests/src/android/content/pm/ParceledListSliceTest.java b/core/tests/coretests/src/android/content/pm/ParceledListSliceTest.java
index 952bb55..8874525 100644
--- a/core/tests/coretests/src/android/content/pm/ParceledListSliceTest.java
+++ b/core/tests/coretests/src/android/content/pm/ParceledListSliceTest.java
@@ -1,8 +1,25 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package android.content.pm;
import android.os.Parcel;
import android.os.Parcelable;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
import junit.framework.TestCase;
diff --git a/core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java b/core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java
index d3d1f22a..365e97d 100644
--- a/core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java
+++ b/core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java
@@ -21,11 +21,12 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.os.UserHandle;
-import android.support.test.filters.LargeTest;
import android.test.AndroidTestCase;
import android.util.AttributeSet;
import android.util.SparseArray;
+import androidx.test.filters.LargeTest;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
diff --git a/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryAndroidTestBaseLibraryTest.java b/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
index 3dba440..216b0c8 100644
--- a/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
+++ b/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.content.pm;
import static android.content.pm.PackageBuilder.builder;
@@ -20,7 +21,8 @@
import android.content.pm.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary;
import android.os.Build;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java b/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
index 15b27d7..fc60980 100644
--- a/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
+++ b/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.content.pm;
import static android.content.pm.PackageBuilder.builder;
@@ -20,7 +21,8 @@
import android.content.pm.PackageBackwardCompatibility.RemoveUnnecessaryOrgApacheHttpLegacyLibrary;
import android.os.Build;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/content/pm/SignatureTest.java b/core/tests/coretests/src/android/content/pm/SignatureTest.java
index a3fa1a9..f0b4af6 100644
--- a/core/tests/coretests/src/android/content/pm/SignatureTest.java
+++ b/core/tests/coretests/src/android/content/pm/SignatureTest.java
@@ -16,7 +16,7 @@
package android.content.pm;
-import android.support.test.filters.LargeTest;
+import androidx.test.filters.LargeTest;
import junit.framework.TestCase;
diff --git a/core/tests/coretests/src/android/content/pm/VerificationParamsTest.java b/core/tests/coretests/src/android/content/pm/VerificationParamsTest.java
index 68942cb..f6527da 100644
--- a/core/tests/coretests/src/android/content/pm/VerificationParamsTest.java
+++ b/core/tests/coretests/src/android/content/pm/VerificationParamsTest.java
@@ -16,12 +16,12 @@
package android.content.pm;
-import android.content.pm.VerificationParams;
import android.net.Uri;
import android.os.Parcel;
-import android.support.test.filters.LargeTest;
import android.test.AndroidTestCase;
+import androidx.test.filters.LargeTest;
+
/**
* Tests the android.content.pm.VerificationParams class
*
diff --git a/core/tests/coretests/src/android/content/pm/VerifierDeviceIdentityTest.java b/core/tests/coretests/src/android/content/pm/VerifierDeviceIdentityTest.java
index 88d7a59..e7cd02d 100644
--- a/core/tests/coretests/src/android/content/pm/VerifierDeviceIdentityTest.java
+++ b/core/tests/coretests/src/android/content/pm/VerifierDeviceIdentityTest.java
@@ -17,7 +17,8 @@
package android.content.pm;
import android.os.Parcel;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
import java.util.Random;
diff --git a/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java b/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java
index e248a77..1ca879c 100644
--- a/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java
+++ b/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java
@@ -29,12 +29,21 @@
import android.content.pm.PackageParser.PackageLite;
import android.content.pm.PackageParser.PackageParserException;
import android.os.FileUtils;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import com.android.frameworks.coretests.R;
+import libcore.testing.io.TestIoUtils;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@@ -45,14 +54,6 @@
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
-import libcore.testing.io.TestIoUtils;
-
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
@SmallTest
@RunWith(AndroidJUnit4.class)
public class DexMetadataHelperTest {
diff --git a/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java b/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java
index 47554a6..47b14bb 100644
--- a/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java
+++ b/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java
@@ -17,9 +17,10 @@
package android.content.res;
import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.SmallTest;
import android.util.TypedValue;
+import androidx.test.filters.SmallTest;
+
import com.android.frameworks.coretests.R;
import java.lang.reflect.InvocationTargetException;
diff --git a/core/tests/coretests/src/android/content/res/ConfigurationTest.java b/core/tests/coretests/src/android/content/res/ConfigurationTest.java
index 72b9197..2fc3e36 100644
--- a/core/tests/coretests/src/android/content/res/ConfigurationTest.java
+++ b/core/tests/coretests/src/android/content/res/ConfigurationTest.java
@@ -13,19 +13,18 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
+
package android.content.res;
-import org.junit.runner.RunWith;
-import org.junit.Test;
-import org.junit.runners.JUnit4;
-
-import android.content.res.Configuration;
-import android.support.test.filters.SmallTest;
import android.platform.test.annotations.Presubmit;
+import androidx.test.filters.SmallTest;
+
import junit.framework.TestCase;
-import static org.junit.Assert.assertEquals;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
/**
* Build/install/run: bit FrameworksCoreTests:android.content.res.ConfigurationTest
diff --git a/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java b/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java
index 42ff2e9..7ab9d7f 100644
--- a/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java
+++ b/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.content.res;
import static android.content.res.FontResourcesParser.FamilyResourceEntry;
@@ -26,9 +27,10 @@
import static org.junit.Assert.assertNotNull;
import android.app.Instrumentation;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import com.android.frameworks.coretests.R;
diff --git a/core/tests/coretests/src/android/content/res/ResourcesLocaleTest.java b/core/tests/coretests/src/android/content/res/ResourcesLocaleTest.java
index e85666e..aa1a534 100644
--- a/core/tests/coretests/src/android/content/res/ResourcesLocaleTest.java
+++ b/core/tests/coretests/src/android/content/res/ResourcesLocaleTest.java
@@ -13,14 +13,15 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
+
package android.content.res;
import android.os.FileUtils;
import android.os.LocaleList;
-import android.support.test.filters.SmallTest;
import android.test.AndroidTestCase;
import android.util.DisplayMetrics;
-import android.view.Display;
+
+import androidx.test.filters.SmallTest;
import com.android.frameworks.coretests.R;
diff --git a/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
index b2ff927..a2dab99 100644
--- a/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
+++ b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
@@ -13,18 +13,20 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
+
package android.content.res;
import android.annotation.NonNull;
import android.app.ResourcesManager;
import android.os.Binder;
import android.os.LocaleList;
-import android.support.test.filters.SmallTest;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.Display;
import android.view.DisplayAdjustments;
+import androidx.test.filters.SmallTest;
+
import junit.framework.TestCase;
public class ResourcesManagerTest extends TestCase {
diff --git a/core/tests/coretests/src/android/database/CursorWindowTest.java b/core/tests/coretests/src/android/database/CursorWindowTest.java
index 075f5b7..123da3e 100644
--- a/core/tests/coretests/src/android/database/CursorWindowTest.java
+++ b/core/tests/coretests/src/android/database/CursorWindowTest.java
@@ -16,14 +16,14 @@
package android.database;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.database.CursorWindow;
import android.test.PerformanceTestCase;
-import java.util.Arrays;
+import androidx.test.filters.SmallTest;
import junit.framework.TestCase;
+import java.util.Arrays;
+
public class CursorWindowTest extends TestCase implements PerformanceTestCase {
public boolean isPerformanceOnly() {
return false;
diff --git a/core/tests/coretests/src/android/database/DatabaseCursorTest.java b/core/tests/coretests/src/android/database/DatabaseCursorTest.java
index 3507223..eb4fd70 100644
--- a/core/tests/coretests/src/android/database/DatabaseCursorTest.java
+++ b/core/tests/coretests/src/android/database/DatabaseCursorTest.java
@@ -18,10 +18,6 @@
import android.content.ContentValues;
import android.content.Context;
-import android.database.Cursor;
-import android.database.CursorIndexOutOfBoundsException;
-import android.database.DataSetObserver;
-import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteCursor;
import android.database.sqlite.SQLiteCursorDriver;
import android.database.sqlite.SQLiteDatabase;
@@ -29,11 +25,12 @@
import android.os.Looper;
import android.test.AndroidTestCase;
import android.test.PerformanceTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
import android.util.Log;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
diff --git a/core/tests/coretests/src/android/database/DatabaseGeneralTest.java b/core/tests/coretests/src/android/database/DatabaseGeneralTest.java
index 9d75c78..49fb75b 100644
--- a/core/tests/coretests/src/android/database/DatabaseGeneralTest.java
+++ b/core/tests/coretests/src/android/database/DatabaseGeneralTest.java
@@ -25,16 +25,17 @@
import android.database.sqlite.SQLiteDebug;
import android.database.sqlite.SQLiteException;
import android.os.Parcel;
-import android.support.test.InstrumentationRegistry;
import android.support.test.uiautomator.UiDevice;
import android.test.AndroidTestCase;
import android.test.PerformanceTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
import android.util.Pair;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
+
import junit.framework.Assert;
import java.io.File;
diff --git a/core/tests/coretests/src/android/database/DatabaseLocaleTest.java b/core/tests/coretests/src/android/database/DatabaseLocaleTest.java
index b3282941..ee7936f 100644
--- a/core/tests/coretests/src/android/database/DatabaseLocaleTest.java
+++ b/core/tests/coretests/src/android/database/DatabaseLocaleTest.java
@@ -17,17 +17,17 @@
package android.database;
import android.database.sqlite.SQLiteDatabase;
-import android.database.Cursor;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
import android.test.MoreAsserts;
+import android.util.Log;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
+
+import junit.framework.TestCase;
import java.util.ArrayList;
import java.util.Locale;
-import junit.framework.TestCase;
-
public class DatabaseLocaleTest extends TestCase {
private SQLiteDatabase mDatabase;
diff --git a/core/tests/coretests/src/android/database/DatabaseLockTest.java b/core/tests/coretests/src/android/database/DatabaseLockTest.java
index 8d3cf5a..e8936c9 100644
--- a/core/tests/coretests/src/android/database/DatabaseLockTest.java
+++ b/core/tests/coretests/src/android/database/DatabaseLockTest.java
@@ -17,11 +17,13 @@
package android.database;
import android.database.sqlite.SQLiteDatabase;
-import android.test.suitebuilder.annotation.Suppress;
+import android.test.AndroidTestCase;
import android.util.Log;
+
+import androidx.test.filters.Suppress;
+
import java.io.File;
import java.util.concurrent.atomic.AtomicInteger;
-import android.test.AndroidTestCase;
/*
* This is a series of unit tests for database locks.
diff --git a/core/tests/coretests/src/android/database/DatabaseStatementTest.java b/core/tests/coretests/src/android/database/DatabaseStatementTest.java
index 895d715..4b34650 100644
--- a/core/tests/coretests/src/android/database/DatabaseStatementTest.java
+++ b/core/tests/coretests/src/android/database/DatabaseStatementTest.java
@@ -17,14 +17,14 @@
package android.database;
import android.content.Context;
-import android.database.Cursor;
import android.database.sqlite.SQLiteConstraintException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDoneException;
import android.database.sqlite.SQLiteStatement;
import android.test.AndroidTestCase;
import android.test.PerformanceTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
+
+import androidx.test.filters.MediumTest;
import java.io.File;
diff --git a/core/tests/coretests/src/android/database/DatabaseStressTest.java b/core/tests/coretests/src/android/database/DatabaseStressTest.java
index 30e46e7..bfea1fc 100644
--- a/core/tests/coretests/src/android/database/DatabaseStressTest.java
+++ b/core/tests/coretests/src/android/database/DatabaseStressTest.java
@@ -17,11 +17,11 @@
package android.database;
import android.content.Context;
-import android.database.sqlite.*;
+import android.database.sqlite.SQLiteDatabase;
+import android.test.AndroidTestCase;
import android.util.Log;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.Suppress;
+import androidx.test.filters.Suppress;
import java.io.File;
diff --git a/core/tests/coretests/src/android/database/DatabaseUtilsTest.java b/core/tests/coretests/src/android/database/DatabaseUtilsTest.java
index 7c206d7..be156c8 100644
--- a/core/tests/coretests/src/android/database/DatabaseUtilsTest.java
+++ b/core/tests/coretests/src/android/database/DatabaseUtilsTest.java
@@ -20,7 +20,7 @@
import static org.junit.Assert.assertEquals;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/database/RedactingCursorTest.java b/core/tests/coretests/src/android/database/RedactingCursorTest.java
index 93998f3..e2d2bae 100644
--- a/core/tests/coretests/src/android/database/RedactingCursorTest.java
+++ b/core/tests/coretests/src/android/database/RedactingCursorTest.java
@@ -22,8 +22,9 @@
import android.content.Context;
import android.net.Uri;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/database/SQLiteOpenHelperTest.java b/core/tests/coretests/src/android/database/SQLiteOpenHelperTest.java
index 9ed3f11b..730a3cb 100644
--- a/core/tests/coretests/src/android/database/SQLiteOpenHelperTest.java
+++ b/core/tests/coretests/src/android/database/SQLiteOpenHelperTest.java
@@ -26,11 +26,12 @@
import android.database.sqlite.SQLiteDatabaseConfiguration;
import android.database.sqlite.SQLiteDebug;
import android.database.sqlite.SQLiteOpenHelper;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.util.Log;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/database/run_newdb_perf_test.sh b/core/tests/coretests/src/android/database/run_newdb_perf_test.sh
index c5b2c97..95f1f83 100755
--- a/core/tests/coretests/src/android/database/run_newdb_perf_test.sh
+++ b/core/tests/coretests/src/android/database/run_newdb_perf_test.sh
@@ -23,7 +23,7 @@
for (( i=0; i<$RUN_N; i++ ))
do
- adb shell am instrument -e class 'android.database.NewDatabasePerformanceTestSuite' -w 'com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner'
+ adb shell am instrument -e class 'android.database.NewDatabasePerformanceTestSuite' -w 'com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner'
done
adb logcat -d > /tmp/testlogcat.txt
diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteCompatibilityWalFlagsTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteCompatibilityWalFlagsTest.java
index 551a58e..5dbcb3c 100644
--- a/core/tests/coretests/src/android/database/sqlite/SQLiteCompatibilityWalFlagsTest.java
+++ b/core/tests/coretests/src/android/database/sqlite/SQLiteCompatibilityWalFlagsTest.java
@@ -22,9 +22,10 @@
import android.content.Context;
import android.database.DatabaseUtils;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteConnectionPoolTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteConnectionPoolTest.java
index ed14a53..f1d27d4 100644
--- a/core/tests/coretests/src/android/database/sqlite/SQLiteConnectionPoolTest.java
+++ b/core/tests/coretests/src/android/database/sqlite/SQLiteConnectionPoolTest.java
@@ -21,11 +21,12 @@
import android.content.Context;
import android.os.HandlerThread;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.util.Log;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteCursorTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteCursorTest.java
index c52cf6e..78d3c41 100644
--- a/core/tests/coretests/src/android/database/sqlite/SQLiteCursorTest.java
+++ b/core/tests/coretests/src/android/database/sqlite/SQLiteCursorTest.java
@@ -23,7 +23,8 @@
import android.database.CursorWindow;
import android.platform.test.annotations.Presubmit;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
import java.io.File;
import java.util.Arrays;
diff --git a/core/tests/coretests/src/android/graphics/BitmapFactoryTest.java b/core/tests/coretests/src/android/graphics/BitmapFactoryTest.java
index e9e2a4d..564460e 100644
--- a/core/tests/coretests/src/android/graphics/BitmapFactoryTest.java
+++ b/core/tests/coretests/src/android/graphics/BitmapFactoryTest.java
@@ -17,14 +17,14 @@
package android.graphics;
import android.os.ParcelFileDescriptor;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
import junit.framework.TestCase;
import java.io.ByteArrayOutputStream;
import java.io.FileDescriptor;
-
public class BitmapFactoryTest extends TestCase {
// tests that we can decode bitmaps from MemoryFiles
diff --git a/core/tests/coretests/src/android/graphics/BitmapTest.java b/core/tests/coretests/src/android/graphics/BitmapTest.java
index 3666ddd..e79d2ae 100644
--- a/core/tests/coretests/src/android/graphics/BitmapTest.java
+++ b/core/tests/coretests/src/android/graphics/BitmapTest.java
@@ -16,11 +16,10 @@
package android.graphics;
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.SmallTest;
import junit.framework.TestCase;
-
public class BitmapTest extends TestCase {
@SmallTest
diff --git a/core/tests/coretests/src/android/graphics/ColorSpaceRendererTest.java b/core/tests/coretests/src/android/graphics/ColorSpaceRendererTest.java
index 6e38fb6..8e9b38c 100644
--- a/core/tests/coretests/src/android/graphics/ColorSpaceRendererTest.java
+++ b/core/tests/coretests/src/android/graphics/ColorSpaceRendererTest.java
@@ -19,8 +19,8 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/graphics/ColorStateListTest.java b/core/tests/coretests/src/android/graphics/ColorStateListTest.java
index 374d142..1d34f938 100644
--- a/core/tests/coretests/src/android/graphics/ColorStateListTest.java
+++ b/core/tests/coretests/src/android/graphics/ColorStateListTest.java
@@ -19,7 +19,8 @@
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
import com.android.frameworks.coretests.R;
diff --git a/core/tests/coretests/src/android/graphics/FontFileUtilTest.java b/core/tests/coretests/src/android/graphics/FontFileUtilTest.java
index 76267b2..1771671 100644
--- a/core/tests/coretests/src/android/graphics/FontFileUtilTest.java
+++ b/core/tests/coretests/src/android/graphics/FontFileUtilTest.java
@@ -22,11 +22,12 @@
import android.content.res.AssetManager;
import android.graphics.fonts.FontFileUtil;
import android.graphics.fonts.FontVariationAxis;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
import android.util.Log;
import android.util.Pair;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+
import org.junit.Test;
import java.io.File;
diff --git a/core/tests/coretests/src/android/graphics/GraphicsPerformanceTests.java b/core/tests/coretests/src/android/graphics/GraphicsPerformanceTests.java
index 164c1aa..3cfeb25 100644
--- a/core/tests/coretests/src/android/graphics/GraphicsPerformanceTests.java
+++ b/core/tests/coretests/src/android/graphics/GraphicsPerformanceTests.java
@@ -20,7 +20,8 @@
import android.content.res.Resources;
import android.test.AndroidTestCase;
import android.test.PerformanceTestCase;
-import android.test.suitebuilder.annotation.Suppress;
+
+import androidx.test.filters.Suppress;
import com.android.frameworks.coretests.R;
diff --git a/core/tests/coretests/src/android/graphics/PaintTest.java b/core/tests/coretests/src/android/graphics/PaintTest.java
index b5ed01f..bf56df1 100644
--- a/core/tests/coretests/src/android/graphics/PaintTest.java
+++ b/core/tests/coretests/src/android/graphics/PaintTest.java
@@ -18,9 +18,9 @@
import static org.junit.Assert.assertNotEquals;
-import android.graphics.Paint;
import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
import java.util.Arrays;
import java.util.HashSet;
diff --git a/core/tests/coretests/src/android/graphics/PathOffsetTest.java b/core/tests/coretests/src/android/graphics/PathOffsetTest.java
index 950f873..6cc42f6 100644
--- a/core/tests/coretests/src/android/graphics/PathOffsetTest.java
+++ b/core/tests/coretests/src/android/graphics/PathOffsetTest.java
@@ -16,13 +16,13 @@
package android.graphics;
+import static org.junit.Assert.assertTrue;
import android.graphics.Bitmap.Config;
import android.graphics.Path.Direction;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import static org.junit.Assert.assertTrue;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/graphics/PathTest.java b/core/tests/coretests/src/android/graphics/PathTest.java
index 78e4959..c6d6d1f 100644
--- a/core/tests/coretests/src/android/graphics/PathTest.java
+++ b/core/tests/coretests/src/android/graphics/PathTest.java
@@ -16,11 +16,10 @@
package android.graphics;
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.SmallTest;
import junit.framework.TestCase;
-
public class PathTest extends TestCase {
@SmallTest
diff --git a/core/tests/coretests/src/android/graphics/RectTest.java b/core/tests/coretests/src/android/graphics/RectTest.java
index d31d7d5..2918f44 100644
--- a/core/tests/coretests/src/android/graphics/RectTest.java
+++ b/core/tests/coretests/src/android/graphics/RectTest.java
@@ -23,8 +23,9 @@
import static org.junit.Assert.assertNull;
import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/graphics/ThreadBitmapTest.java b/core/tests/coretests/src/android/graphics/ThreadBitmapTest.java
index 909a8d9..e1ca7df 100644
--- a/core/tests/coretests/src/android/graphics/ThreadBitmapTest.java
+++ b/core/tests/coretests/src/android/graphics/ThreadBitmapTest.java
@@ -16,7 +16,7 @@
package android.graphics;
-import android.test.suitebuilder.annotation.LargeTest;
+import androidx.test.filters.LargeTest;
import junit.framework.TestCase;
diff --git a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java b/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
index 6fdb71f..c66bac6 100644
--- a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
+++ b/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
@@ -27,12 +27,13 @@
import android.graphics.fonts.FontCustomizationParser;
import android.graphics.fonts.FontFamily;
import android.graphics.fonts.SystemFonts;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.text.FontConfig;
import android.util.ArrayMap;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/graphics/TypefaceTest.java b/core/tests/coretests/src/android/graphics/TypefaceTest.java
index b0c7976..2d16f82 100644
--- a/core/tests/coretests/src/android/graphics/TypefaceTest.java
+++ b/core/tests/coretests/src/android/graphics/TypefaceTest.java
@@ -22,13 +22,12 @@
import android.content.Context;
import android.content.res.AssetManager;
import android.content.res.Resources;
-import android.graphics.Paint;
-import android.graphics.Typeface;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import com.android.frameworks.coretests.R;
diff --git a/core/tests/coretests/src/android/graphics/drawable/AdaptiveIconDrawableTest.java b/core/tests/coretests/src/android/graphics/drawable/AdaptiveIconDrawableTest.java
index 781e343..3dc9987 100644
--- a/core/tests/coretests/src/android/graphics/drawable/AdaptiveIconDrawableTest.java
+++ b/core/tests/coretests/src/android/graphics/drawable/AdaptiveIconDrawableTest.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2017 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.graphics.drawable;
import android.content.res.Resources;
@@ -11,11 +27,12 @@
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
-import android.support.test.filters.LargeTest;
import android.test.AndroidTestCase;
import android.util.Log;
import android.util.PathParser;
+import androidx.test.filters.LargeTest;
+
import org.junit.Test;
import java.io.File;
diff --git a/core/tests/coretests/src/android/graphics/drawable/DrawableWrapperTest.java b/core/tests/coretests/src/android/graphics/drawable/DrawableWrapperTest.java
index 655efb5..d0a6ff9 100644
--- a/core/tests/coretests/src/android/graphics/drawable/DrawableWrapperTest.java
+++ b/core/tests/coretests/src/android/graphics/drawable/DrawableWrapperTest.java
@@ -24,8 +24,9 @@
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Xfermode;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/graphics/drawable/IconTest.java b/core/tests/coretests/src/android/graphics/drawable/IconTest.java
index 64fadc0..2bdcc28 100644
--- a/core/tests/coretests/src/android/graphics/drawable/IconTest.java
+++ b/core/tests/coretests/src/android/graphics/drawable/IconTest.java
@@ -25,9 +25,10 @@
import android.os.HandlerThread;
import android.os.Parcel;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
+import androidx.test.filters.SmallTest;
+
import com.android.frameworks.coretests.R;
import java.io.ByteArrayOutputStream;
diff --git a/core/tests/coretests/src/android/hardware/display/AmbientBrightnessDayStatsTest.java b/core/tests/coretests/src/android/hardware/display/AmbientBrightnessDayStatsTest.java
index f90ae34..0a25bd7 100644
--- a/core/tests/coretests/src/android/hardware/display/AmbientBrightnessDayStatsTest.java
+++ b/core/tests/coretests/src/android/hardware/display/AmbientBrightnessDayStatsTest.java
@@ -23,8 +23,9 @@
import static org.junit.Assert.fail;
import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java b/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java
index dcc51e1..823fca5 100644
--- a/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java
+++ b/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java
@@ -22,10 +22,11 @@
import static org.junit.Assert.fail;
import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.util.Pair;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java b/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java
index f30b1a2..daf6139 100644
--- a/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java
+++ b/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java
@@ -22,15 +22,12 @@
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.drawable.ColorDrawable;
-import android.hardware.display.DisplayManager;
-import android.hardware.display.VirtualDisplay;
import android.media.Image;
import android.media.ImageReader;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
-import android.support.test.filters.LargeTest;
import android.test.AndroidTestCase;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -40,6 +37,8 @@
import android.view.WindowManager;
import android.widget.ImageView;
+import androidx.test.filters.LargeTest;
+
import java.nio.ByteBuffer;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
diff --git a/core/tests/coretests/src/android/hardware/hdmi/HdmiUtilsTest.java b/core/tests/coretests/src/android/hardware/hdmi/HdmiUtilsTest.java
new file mode 100644
index 0000000..16be0b0
--- /dev/null
+++ b/core/tests/coretests/src/android/hardware/hdmi/HdmiUtilsTest.java
@@ -0,0 +1,82 @@
+/*
+ * 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.hardware.hdmi;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.support.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@SmallTest
+@RunWith(JUnit4.class)
+/** Tests for {@link HdmiUtils} class. */
+public class HdmiUtilsTest {
+
+ @Test
+ public void pathToPort_isMe() {
+ int targetPhysicalAddress = 0x1000;
+ int myPhysicalAddress = 0x1000;
+ assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+ targetPhysicalAddress, myPhysicalAddress)).isEqualTo(
+ HdmiUtils.TARGET_SAME_PHYSICAL_ADDRESS);
+ }
+
+ @Test
+ public void pathToPort_isDirectlyBelow() {
+ int targetPhysicalAddress = 0x1100;
+ int myPhysicalAddress = 0x1000;
+ assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+ targetPhysicalAddress, myPhysicalAddress)).isEqualTo(1);
+ }
+
+ @Test
+ public void pathToPort_isBelow() {
+ int targetPhysicalAddress = 0x1110;
+ int myPhysicalAddress = 0x1000;
+ assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+ targetPhysicalAddress, myPhysicalAddress)).isEqualTo(1);
+ }
+
+ @Test
+ public void pathToPort_neitherMeNorBelow() {
+ int targetPhysicalAddress = 0x3000;
+ int myPhysicalAddress = 0x2000;
+ assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+ targetPhysicalAddress, myPhysicalAddress)).isEqualTo(
+ HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE);
+
+ targetPhysicalAddress = 0x2200;
+ myPhysicalAddress = 0x3300;
+ assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+ targetPhysicalAddress, myPhysicalAddress)).isEqualTo(
+ HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE);
+
+ targetPhysicalAddress = 0x2213;
+ myPhysicalAddress = 0x2212;
+ assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+ targetPhysicalAddress, myPhysicalAddress)).isEqualTo(
+ HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE);
+
+ targetPhysicalAddress = 0x2340;
+ myPhysicalAddress = 0x2310;
+ assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+ targetPhysicalAddress, myPhysicalAddress)).isEqualTo(
+ HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE);
+ }
+}
diff --git a/core/tests/coretests/src/android/metrics/LogMakerTest.java b/core/tests/coretests/src/android/metrics/LogMakerTest.java
index 3be776d..aabfc28 100644
--- a/core/tests/coretests/src/android/metrics/LogMakerTest.java
+++ b/core/tests/coretests/src/android/metrics/LogMakerTest.java
@@ -13,9 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.metrics;
-import android.support.test.filters.LargeTest;
+import androidx.test.filters.LargeTest;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
diff --git a/core/tests/coretests/src/android/metrics/MetricsReaderTest.java b/core/tests/coretests/src/android/metrics/MetricsReaderTest.java
index 784a12f..96dac64 100644
--- a/core/tests/coretests/src/android/metrics/MetricsReaderTest.java
+++ b/core/tests/coretests/src/android/metrics/MetricsReaderTest.java
@@ -13,10 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.metrics;
import android.metrics.MetricsReader.Event;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
diff --git a/core/tests/coretests/src/android/net/LocalSocketTest.java b/core/tests/coretests/src/android/net/LocalSocketTest.java
index 1286b13..9172237 100644
--- a/core/tests/coretests/src/android/net/LocalSocketTest.java
+++ b/core/tests/coretests/src/android/net/LocalSocketTest.java
@@ -16,12 +16,9 @@
package android.net;
-import android.net.Credentials;
-import android.net.LocalServerSocket;
-import android.net.LocalSocket;
-import android.net.LocalSocketAddress;
import android.test.MoreAsserts;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
import junit.framework.TestCase;
diff --git a/core/tests/coretests/src/android/net/NetworkKeyTest.java b/core/tests/coretests/src/android/net/NetworkKeyTest.java
index fff23a0..0f1c71d 100644
--- a/core/tests/coretests/src/android/net/NetworkKeyTest.java
+++ b/core/tests/coretests/src/android/net/NetworkKeyTest.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package android.net;
import static org.junit.Assert.assertEquals;
@@ -7,7 +23,8 @@
import android.net.wifi.ScanResult;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiSsid;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/net/NetworkPolicyManagerTest.java b/core/tests/coretests/src/android/net/NetworkPolicyManagerTest.java
index c6758ce..29e212f 100644
--- a/core/tests/coretests/src/android/net/NetworkPolicyManagerTest.java
+++ b/core/tests/coretests/src/android/net/NetworkPolicyManagerTest.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.net;
import static android.net.NetworkPolicyManager.MASK_ALL_NETWORKS;
diff --git a/core/tests/coretests/src/android/net/NetworkRecommendationProviderTest.java b/core/tests/coretests/src/android/net/NetworkRecommendationProviderTest.java
index ff9816a..3e45a79 100644
--- a/core/tests/coretests/src/android/net/NetworkRecommendationProviderTest.java
+++ b/core/tests/coretests/src/android/net/NetworkRecommendationProviderTest.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package android.net;
import static junit.framework.Assert.assertFalse;
@@ -9,7 +25,8 @@
import android.Manifest.permission;
import android.content.Context;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/net/SSLCertificateSocketFactoryTest.java b/core/tests/coretests/src/android/net/SSLCertificateSocketFactoryTest.java
index 5cbf02a..bc12e72 100644
--- a/core/tests/coretests/src/android/net/SSLCertificateSocketFactoryTest.java
+++ b/core/tests/coretests/src/android/net/SSLCertificateSocketFactoryTest.java
@@ -19,7 +19,7 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/net/SSLSessionCacheTest.java b/core/tests/coretests/src/android/net/SSLSessionCacheTest.java
index 11d066b..eec09e6 100644
--- a/core/tests/coretests/src/android/net/SSLSessionCacheTest.java
+++ b/core/tests/coretests/src/android/net/SSLSessionCacheTest.java
@@ -19,10 +19,10 @@
import com.android.org.conscrypt.ClientSessionContext;
import com.android.org.conscrypt.SSLClientSessionCache;
-import org.mockito.Mockito;
-
import junit.framework.TestCase;
+import org.mockito.Mockito;
+
import java.security.KeyManagementException;
import java.security.SecureRandom;
diff --git a/core/tests/coretests/src/android/net/ScoredNetworkTest.java b/core/tests/coretests/src/android/net/ScoredNetworkTest.java
index 109f32e..d984d86 100644
--- a/core/tests/coretests/src/android/net/ScoredNetworkTest.java
+++ b/core/tests/coretests/src/android/net/ScoredNetworkTest.java
@@ -16,11 +16,17 @@
package android.net;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import android.os.Bundle;
import android.os.Parcel;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/net/SntpClientTest.java b/core/tests/coretests/src/android/net/SntpClientTest.java
index d72738c..87edb6e 100644
--- a/core/tests/coretests/src/android/net/SntpClientTest.java
+++ b/core/tests/coretests/src/android/net/SntpClientTest.java
@@ -20,9 +20,10 @@
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
-import android.support.test.runner.AndroidJUnit4;
import android.util.Log;
+import androidx.test.runner.AndroidJUnit4;
+
import libcore.util.HexEncoding;
import org.junit.Before;
diff --git a/core/tests/coretests/src/android/net/UriTest.java b/core/tests/coretests/src/android/net/UriTest.java
index ea0347d..a33de7b 100644
--- a/core/tests/coretests/src/android/net/UriTest.java
+++ b/core/tests/coretests/src/android/net/UriTest.java
@@ -18,7 +18,8 @@
import android.content.ContentUris;
import android.os.Parcel;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
import junit.framework.TestCase;
diff --git a/core/tests/coretests/src/android/net/WebAddressTest.java b/core/tests/coretests/src/android/net/WebAddressTest.java
index 6fcb97e..70a6253 100644
--- a/core/tests/coretests/src/android/net/WebAddressTest.java
+++ b/core/tests/coretests/src/android/net/WebAddressTest.java
@@ -16,8 +16,8 @@
package android.net;
-import android.net.WebAddress;
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.SmallTest;
+
import junit.framework.TestCase;
public class WebAddressTest extends TestCase {
diff --git a/core/tests/coretests/src/android/net/http/SslCertificateTest.java b/core/tests/coretests/src/android/net/http/SslCertificateTest.java
index 6a30c6c..1beb1de 100644
--- a/core/tests/coretests/src/android/net/http/SslCertificateTest.java
+++ b/core/tests/coretests/src/android/net/http/SslCertificateTest.java
@@ -17,12 +17,13 @@
package android.net.http;
-import android.net.http.SslCertificate;
-import android.test.suitebuilder.annotation.LargeTest;
+import androidx.test.filters.LargeTest;
+
+import junit.framework.TestCase;
+
import java.io.ByteArrayInputStream;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
-import junit.framework.TestCase;
public class SslCertificateTest extends TestCase {
diff --git a/core/tests/coretests/src/android/os/AidlTest.java b/core/tests/coretests/src/android/os/AidlTest.java
index bf11d56..4c51415 100644
--- a/core/tests/coretests/src/android/os/AidlTest.java
+++ b/core/tests/coretests/src/android/os/AidlTest.java
@@ -16,11 +16,10 @@
package android.os;
-import android.os.IInterface;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.SmallTest;
+
import com.google.android.collect.Lists;
+
import junit.framework.TestCase;
import java.util.List;
diff --git a/core/tests/coretests/src/android/os/BinderProxyCountingTest.java b/core/tests/coretests/src/android/os/BinderProxyCountingTest.java
index 6cdb35ab..ce6ad87 100644
--- a/core/tests/coretests/src/android/os/BinderProxyCountingTest.java
+++ b/core/tests/coretests/src/android/os/BinderProxyCountingTest.java
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
package android.os;
import static org.junit.Assert.assertEquals;
@@ -25,12 +24,13 @@
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
import android.support.test.uiautomator.UiDevice;
import android.util.Log;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
import com.android.frameworks.coretests.aidl.IBpcCallbackObserver;
import com.android.frameworks.coretests.aidl.IBpcTestAppCmdService;
import com.android.frameworks.coretests.aidl.IBpcTestServiceCmdService;
@@ -63,7 +63,7 @@
* Install: adb install -r \
* ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
* Run: adb shell am instrument -e class android.os.BinderProxyCountingTest -w \
- * com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
+ * com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner
*
* or
*
diff --git a/core/tests/coretests/src/android/os/BinderProxyTest.java b/core/tests/coretests/src/android/os/BinderProxyTest.java
index 4c36b5c..aceda2d 100644
--- a/core/tests/coretests/src/android/os/BinderProxyTest.java
+++ b/core/tests/coretests/src/android/os/BinderProxyTest.java
@@ -19,7 +19,8 @@
import android.annotation.Nullable;
import android.content.Context;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
+
+import androidx.test.filters.MediumTest;
public class BinderProxyTest extends AndroidTestCase {
private static class CountingListener implements Binder.ProxyTransactListener {
diff --git a/core/tests/coretests/src/android/os/BinderTest.java b/core/tests/coretests/src/android/os/BinderTest.java
index 6c9c3c1..a354195 100644
--- a/core/tests/coretests/src/android/os/BinderTest.java
+++ b/core/tests/coretests/src/android/os/BinderTest.java
@@ -16,7 +16,7 @@
package android.os;
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.SmallTest;
import junit.framework.TestCase;
diff --git a/core/tests/coretests/src/android/os/BinderThreadPriorityService.java b/core/tests/coretests/src/android/os/BinderThreadPriorityService.java
index 47a4483..ed42058 100644
--- a/core/tests/coretests/src/android/os/BinderThreadPriorityService.java
+++ b/core/tests/coretests/src/android/os/BinderThreadPriorityService.java
@@ -18,7 +18,6 @@
import android.app.Service;
import android.content.Intent;
-import android.text.TextUtils;
import android.util.Log;
/**
diff --git a/core/tests/coretests/src/android/os/BinderThreadPriorityTest.java b/core/tests/coretests/src/android/os/BinderThreadPriorityTest.java
index 56e977c..48c9df6 100644
--- a/core/tests/coretests/src/android/os/BinderThreadPriorityTest.java
+++ b/core/tests/coretests/src/android/os/BinderThreadPriorityTest.java
@@ -21,7 +21,6 @@
import android.content.Intent;
import android.content.ServiceConnection;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
import android.util.Log;
import java.io.File;
diff --git a/core/tests/coretests/src/android/os/BinderWorkSourceTest.java b/core/tests/coretests/src/android/os/BinderWorkSourceTest.java
index 5664df6..e16a3db 100644
--- a/core/tests/coretests/src/android/os/BinderWorkSourceTest.java
+++ b/core/tests/coretests/src/android/os/BinderWorkSourceTest.java
@@ -24,9 +24,10 @@
import android.content.Intent;
import android.content.ServiceConnection;
import android.platform.test.annotations.Presubmit;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Before;
diff --git a/core/tests/coretests/src/android/os/BrightnessLimit.java b/core/tests/coretests/src/android/os/BrightnessLimit.java
index fabcf3d..5a3724f 100644
--- a/core/tests/coretests/src/android/os/BrightnessLimit.java
+++ b/core/tests/coretests/src/android/os/BrightnessLimit.java
@@ -18,7 +18,6 @@
import android.app.Activity;
import android.hardware.display.DisplayManager;
-import android.os.Bundle;
import android.provider.Settings;
import android.view.View;
import android.view.View.OnClickListener;
diff --git a/core/tests/coretests/src/android/os/BroadcasterTest.java b/core/tests/coretests/src/android/os/BroadcasterTest.java
index 551ea8d..b4c47af9 100644
--- a/core/tests/coretests/src/android/os/BroadcasterTest.java
+++ b/core/tests/coretests/src/android/os/BroadcasterTest.java
@@ -16,11 +16,8 @@
package android.os;
-import android.os.Broadcaster;
-import android.os.Handler;
-import android.os.Message;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.MediumTest;
+
import junit.framework.TestCase;
public class BroadcasterTest extends TestCase {
diff --git a/core/tests/coretests/src/android/os/BuildTest.java b/core/tests/coretests/src/android/os/BuildTest.java
index 3758627..decc768 100644
--- a/core/tests/coretests/src/android/os/BuildTest.java
+++ b/core/tests/coretests/src/android/os/BuildTest.java
@@ -16,9 +16,8 @@
package android.os;
-import android.os.Build;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
+import androidx.test.filters.SmallTest;
+
import junit.framework.Assert;
import junit.framework.TestCase;
diff --git a/core/tests/coretests/src/android/os/BundleTest.java b/core/tests/coretests/src/android/os/BundleTest.java
index 9fcf96d..e4dc993 100644
--- a/core/tests/coretests/src/android/os/BundleTest.java
+++ b/core/tests/coretests/src/android/os/BundleTest.java
@@ -20,8 +20,8 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/os/EnvironmentTest.java b/core/tests/coretests/src/android/os/EnvironmentTest.java
index 5189df5..d98ceaf 100644
--- a/core/tests/coretests/src/android/os/EnvironmentTest.java
+++ b/core/tests/coretests/src/android/os/EnvironmentTest.java
@@ -25,8 +25,9 @@
import static org.junit.Assert.assertEquals;
import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Before;
diff --git a/core/tests/coretests/src/android/os/FileObserverTest.java b/core/tests/coretests/src/android/os/FileObserverTest.java
index 93e27af..ece7645 100644
--- a/core/tests/coretests/src/android/os/FileObserverTest.java
+++ b/core/tests/coretests/src/android/os/FileObserverTest.java
@@ -16,13 +16,14 @@
package android.os;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import androidx.test.filters.MediumTest;
+
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.util.Log;
-
import java.io.File;
import java.io.FileOutputStream;
import java.util.Iterator;
diff --git a/core/tests/coretests/src/android/os/FileUtilsTest.java b/core/tests/coretests/src/android/os/FileUtilsTest.java
index 514ea0c..5bce227c 100644
--- a/core/tests/coretests/src/android/os/FileUtilsTest.java
+++ b/core/tests/coretests/src/android/os/FileUtilsTest.java
@@ -51,8 +51,9 @@
import android.content.Context;
import android.os.FileUtils.MemoryPipe;
import android.provider.DocumentsContract.Document;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
import libcore.io.Streams;
diff --git a/core/tests/coretests/src/android/os/HandlerTester.java b/core/tests/coretests/src/android/os/HandlerTester.java
index a216a0b..fa442f4 100644
--- a/core/tests/coretests/src/android/os/HandlerTester.java
+++ b/core/tests/coretests/src/android/os/HandlerTester.java
@@ -16,10 +16,6 @@
package android.os;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-
public abstract class HandlerTester extends Thread {
public abstract void go();
public abstract void handleMessage(Message msg);
diff --git a/core/tests/coretests/src/android/os/HandlerThreadTest.java b/core/tests/coretests/src/android/os/HandlerThreadTest.java
index 9772aa4..93cfc40 100644
--- a/core/tests/coretests/src/android/os/HandlerThreadTest.java
+++ b/core/tests/coretests/src/android/os/HandlerThreadTest.java
@@ -16,13 +16,9 @@
package android.os;
+import androidx.test.filters.MediumTest;
+
import junit.framework.TestCase;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Message;
-import android.os.Process;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
public class HandlerThreadTest extends TestCase {
private static final int TEST_WHAT = 1;
diff --git a/core/tests/coretests/src/android/os/IdleHandlerTest.java b/core/tests/coretests/src/android/os/IdleHandlerTest.java
index 6c0a862..d8886c9 100644
--- a/core/tests/coretests/src/android/os/IdleHandlerTest.java
+++ b/core/tests/coretests/src/android/os/IdleHandlerTest.java
@@ -16,11 +16,10 @@
package android.os;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
import android.os.MessageQueue.IdleHandler;
-import android.test.suitebuilder.annotation.MediumTest;
+
+import androidx.test.filters.MediumTest;
+
import junit.framework.TestCase;
public class IdleHandlerTest extends TestCase {
diff --git a/core/tests/coretests/src/android/os/LocaleListTest.java b/core/tests/coretests/src/android/os/LocaleListTest.java
index 17ef773..1f00a7a 100644
--- a/core/tests/coretests/src/android/os/LocaleListTest.java
+++ b/core/tests/coretests/src/android/os/LocaleListTest.java
@@ -13,14 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.os;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import java.util.Locale;
+import androidx.test.filters.SmallTest;
import junit.framework.TestCase;
+import java.util.Locale;
+
public class LocaleListTest extends TestCase {
@SmallTest
public void testConstructor() throws Exception {
diff --git a/core/tests/coretests/src/android/os/MemoryFileTest.java b/core/tests/coretests/src/android/os/MemoryFileTest.java
index 20b298d..05c2995 100644
--- a/core/tests/coretests/src/android/os/MemoryFileTest.java
+++ b/core/tests/coretests/src/android/os/MemoryFileTest.java
@@ -17,8 +17,9 @@
package android.os;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.SmallTest;
import java.io.IOException;
import java.io.InputStream;
diff --git a/core/tests/coretests/src/android/os/MessageQueueTest.java b/core/tests/coretests/src/android/os/MessageQueueTest.java
index 1cd1020..2c5588e 100644
--- a/core/tests/coretests/src/android/os/MessageQueueTest.java
+++ b/core/tests/coretests/src/android/os/MessageQueueTest.java
@@ -16,11 +16,9 @@
package android.os;
-import android.os.Handler;
-import android.os.Message;
-import android.os.SystemClock;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
import junit.framework.TestCase;
@Suppress // Failing.
diff --git a/core/tests/coretests/src/android/os/MessengerService.java b/core/tests/coretests/src/android/os/MessengerService.java
index f15e134..db33471 100644
--- a/core/tests/coretests/src/android/os/MessengerService.java
+++ b/core/tests/coretests/src/android/os/MessengerService.java
@@ -18,11 +18,6 @@
import android.app.Service;
import android.content.Intent;
-import android.os.RemoteException;
-import android.os.IBinder;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Messenger;
public class MessengerService extends Service {
private final Handler mHandler = new Handler() {
diff --git a/core/tests/coretests/src/android/os/MessengerTest.java b/core/tests/coretests/src/android/os/MessengerTest.java
index 473ffe2..9143ff1 100644
--- a/core/tests/coretests/src/android/os/MessengerTest.java
+++ b/core/tests/coretests/src/android/os/MessengerTest.java
@@ -20,13 +20,9 @@
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
-import android.os.RemoteException;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.Messenger;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
+
+import androidx.test.filters.MediumTest;
public class MessengerTest extends AndroidTestCase {
private Messenger mServiceMessenger;
diff --git a/core/tests/coretests/src/android/os/OsTests.java b/core/tests/coretests/src/android/os/OsTests.java
index 2b84126..08fb945 100644
--- a/core/tests/coretests/src/android/os/OsTests.java
+++ b/core/tests/coretests/src/android/os/OsTests.java
@@ -16,12 +16,8 @@
package android.os;
-import com.google.android.collect.Lists;
import junit.framework.TestSuite;
-import java.util.Enumeration;
-import java.util.List;
-
public class OsTests {
public static TestSuite suite() {
TestSuite suite = new TestSuite(OsTests.class.getName());
diff --git a/core/tests/coretests/src/android/os/ParcelNullabilityTest.java b/core/tests/coretests/src/android/os/ParcelNullabilityTest.java
index 516dc0a..a6b296d 100644
--- a/core/tests/coretests/src/android/os/ParcelNullabilityTest.java
+++ b/core/tests/coretests/src/android/os/ParcelNullabilityTest.java
@@ -20,10 +20,11 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.SmallTest;
import android.util.ArrayMap;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/os/PatternMatcherTest.java b/core/tests/coretests/src/android/os/PatternMatcherTest.java
index 9645ccc..82350cd 100644
--- a/core/tests/coretests/src/android/os/PatternMatcherTest.java
+++ b/core/tests/coretests/src/android/os/PatternMatcherTest.java
@@ -1,9 +1,27 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package android.os;
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.SmallTest;
+
import junit.framework.TestCase;
-import org.junit.runner.RunWith;
+
import org.junit.Test;
+import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
diff --git a/core/tests/coretests/src/android/os/PerformanceCollectorTest.java b/core/tests/coretests/src/android/os/PerformanceCollectorTest.java
index 7533c84..38ad90f 100644
--- a/core/tests/coretests/src/android/os/PerformanceCollectorTest.java
+++ b/core/tests/coretests/src/android/os/PerformanceCollectorTest.java
@@ -17,15 +17,16 @@
package android.os;
import android.os.PerformanceCollector.PerformanceResultsWriter;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
+
+import junit.framework.TestCase;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Random;
-import junit.framework.TestCase;
-
public class PerformanceCollectorTest extends TestCase {
private PerformanceCollector mPerfCollector;
diff --git a/core/tests/coretests/src/android/os/PowerManagerTest.java b/core/tests/coretests/src/android/os/PowerManagerTest.java
index a828f44..1b587dd 100644
--- a/core/tests/coretests/src/android/os/PowerManagerTest.java
+++ b/core/tests/coretests/src/android/os/PowerManagerTest.java
@@ -21,10 +21,11 @@
import static org.mockito.Mockito.verify;
import android.content.Context;
-import android.support.test.InstrumentationRegistry;
import android.support.test.uiautomator.UiDevice;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
import org.junit.After;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/os/PowerManagerVrTest.java b/core/tests/coretests/src/android/os/PowerManagerVrTest.java
index e01e5fa..5d2c65b 100644
--- a/core/tests/coretests/src/android/os/PowerManagerVrTest.java
+++ b/core/tests/coretests/src/android/os/PowerManagerVrTest.java
@@ -19,16 +19,14 @@
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
-import android.os.PowerManager;
-import android.os.RemoteException;
-import android.os.ServiceManager;
import android.provider.Settings;
-import android.service.dreams.IDreamManager;
import android.service.dreams.DreamService;
-import android.support.test.filters.MediumTest;
-import android.support.test.filters.SmallTest;
+import android.service.dreams.IDreamManager;
import android.test.ActivityInstrumentationTestCase2;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
+
/**
* Tests dream aspects of PowerManager.
*/
diff --git a/core/tests/coretests/src/android/os/ProcessTest.java b/core/tests/coretests/src/android/os/ProcessTest.java
index 1f5b7c8..b749e71 100644
--- a/core/tests/coretests/src/android/os/ProcessTest.java
+++ b/core/tests/coretests/src/android/os/ProcessTest.java
@@ -17,14 +17,10 @@
package android.os;
-import android.os.Process;
-import android.os.UserHandle;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.MediumTest;
import junit.framework.TestCase;
-
public class ProcessTest extends TestCase {
@MediumTest
diff --git a/core/tests/coretests/src/android/os/RedactingFileDescriptorTest.java b/core/tests/coretests/src/android/os/RedactingFileDescriptorTest.java
index 9e15231..d5163e1 100644
--- a/core/tests/coretests/src/android/os/RedactingFileDescriptorTest.java
+++ b/core/tests/coretests/src/android/os/RedactingFileDescriptorTest.java
@@ -24,10 +24,11 @@
import static org.junit.Assert.assertEquals;
import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
import android.system.Os;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/os/SetPersistentVrThreadTest.java b/core/tests/coretests/src/android/os/SetPersistentVrThreadTest.java
index 9e44554..8085993 100644
--- a/core/tests/coretests/src/android/os/SetPersistentVrThreadTest.java
+++ b/core/tests/coretests/src/android/os/SetPersistentVrThreadTest.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.os;
import android.app.ActivityManager;
@@ -20,10 +21,10 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
-import android.os.Process;
import android.provider.Settings;
import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
/**
* Tests ActivityManager#setPersistentVrThread and ActivityManager#setVrThread's
diff --git a/core/tests/coretests/src/android/os/TestHandlerThread.java b/core/tests/coretests/src/android/os/TestHandlerThread.java
index 7e84af3..8c0330b 100644
--- a/core/tests/coretests/src/android/os/TestHandlerThread.java
+++ b/core/tests/coretests/src/android/os/TestHandlerThread.java
@@ -16,11 +16,6 @@
package android.os;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.MessageQueue.IdleHandler;
-
abstract class TestHandlerThread {
private boolean mDone = false;
private boolean mSuccess = false;
diff --git a/core/tests/coretests/src/android/os/TestVrActivity.java b/core/tests/coretests/src/android/os/TestVrActivity.java
index 33ff164..75df7c2 100644
--- a/core/tests/coretests/src/android/os/TestVrActivity.java
+++ b/core/tests/coretests/src/android/os/TestVrActivity.java
@@ -17,7 +17,6 @@
package android.os;
import android.app.Activity;
-import android.os.Bundle;
import android.service.vr.VrListenerService;
import java.util.concurrent.CountDownLatch;
diff --git a/core/tests/coretests/src/android/os/TraceTest.java b/core/tests/coretests/src/android/os/TraceTest.java
index 1541553..5cad549 100644
--- a/core/tests/coretests/src/android/os/TraceTest.java
+++ b/core/tests/coretests/src/android/os/TraceTest.java
@@ -16,13 +16,13 @@
package android.os;
-import android.os.Debug;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.Suppress;
import android.util.Log;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.filters.Suppress;
+
/**
* This class is used to test the native tracing support. Run this test
* while tracing on the emulator and then run traceview to view the trace.
diff --git a/core/tests/coretests/src/android/os/UserHandleTest.java b/core/tests/coretests/src/android/os/UserHandleTest.java
index af559fd..4a1cdbf 100644
--- a/core/tests/coretests/src/android/os/UserHandleTest.java
+++ b/core/tests/coretests/src/android/os/UserHandleTest.java
@@ -25,7 +25,7 @@
import static org.junit.Assert.assertEquals;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/os/VintfObjectTest.java b/core/tests/coretests/src/android/os/VintfObjectTest.java
index 44510c2..af3660a 100644
--- a/core/tests/coretests/src/android/os/VintfObjectTest.java
+++ b/core/tests/coretests/src/android/os/VintfObjectTest.java
@@ -16,7 +16,6 @@
package android.os;
-import junit.framework.Assert;
import junit.framework.TestCase;
public class VintfObjectTest extends TestCase {
diff --git a/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java b/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java
index 3ec297c..62f2ac2 100644
--- a/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java
+++ b/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java
@@ -19,7 +19,8 @@
import android.os.ParcelFileDescriptor;
import android.os.ProxyFileDescriptorCallback;
import android.system.ErrnoException;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
import com.android.frameworks.coretests.R;
diff --git a/core/tests/coretests/src/android/preference/ListPreferenceTest.java b/core/tests/coretests/src/android/preference/ListPreferenceTest.java
index 72f62f1..51dbb64 100644
--- a/core/tests/coretests/src/android/preference/ListPreferenceTest.java
+++ b/core/tests/coretests/src/android/preference/ListPreferenceTest.java
@@ -16,10 +16,10 @@
package android.preference;
-import android.preference.ListPreference;
-import android.support.test.filters.LargeTest;
import android.test.AndroidTestCase;
+import androidx.test.filters.LargeTest;
+
@LargeTest
public class ListPreferenceTest extends AndroidTestCase {
public void testListPreferenceSummaryFromEntries() {
diff --git a/core/tests/coretests/src/android/preference/PreferenceIconSpaceTest.java b/core/tests/coretests/src/android/preference/PreferenceIconSpaceTest.java
index 654474c..0deb77e 100644
--- a/core/tests/coretests/src/android/preference/PreferenceIconSpaceTest.java
+++ b/core/tests/coretests/src/android/preference/PreferenceIconSpaceTest.java
@@ -16,20 +16,20 @@
package android.preference;
-
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java b/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java
index 5d12f7e..94d85e6 100644
--- a/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java
+++ b/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java
@@ -41,9 +41,10 @@
import android.print.test.services.PrinterDiscoverySessionCallbacks;
import android.print.test.services.StubbablePrinterDiscoverySession;
import android.printservice.recommendation.IRecommendationsChangeListener;
-import android.support.test.filters.LargeTest;
-import android.support.test.filters.MediumTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/provider/DeviceConfigTest.java b/core/tests/coretests/src/android/provider/DeviceConfigTest.java
index 800b864..17e9654 100644
--- a/core/tests/coretests/src/android/provider/DeviceConfigTest.java
+++ b/core/tests/coretests/src/android/provider/DeviceConfigTest.java
@@ -28,9 +28,10 @@
import android.os.Bundle;
import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/provider/DocumentsProviderTest.java b/core/tests/coretests/src/android/provider/DocumentsProviderTest.java
index 1465d0a9..02a9adf 100644
--- a/core/tests/coretests/src/android/provider/DocumentsProviderTest.java
+++ b/core/tests/coretests/src/android/provider/DocumentsProviderTest.java
@@ -20,9 +20,10 @@
import android.content.ContentResolver;
import android.net.Uri;
import android.provider.DocumentsContract.Path;
-import android.support.test.filters.SmallTest;
import android.test.ProviderTestCase2;
+import androidx.test.filters.SmallTest;
+
import java.util.Arrays;
/**
diff --git a/core/tests/coretests/src/android/provider/FontsContractE2ETest.java b/core/tests/coretests/src/android/provider/FontsContractE2ETest.java
index 2955869..7e02be8 100644
--- a/core/tests/coretests/src/android/provider/FontsContractE2ETest.java
+++ b/core/tests/coretests/src/android/provider/FontsContractE2ETest.java
@@ -25,25 +25,25 @@
import android.app.Instrumentation;
import android.content.Context;
import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.Signature;
import android.graphics.Typeface;
import android.os.Handler;
-import android.provider.FontsContract.Columns;
import android.provider.FontsContract.FontFamilyResult;
-import android.provider.FontsContract.FontInfo;
-import android.provider.FontsContract;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import java.util.ArrayList;
-import java.util.List;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.ArrayList;
+import java.util.List;
+
@SmallTest
@RunWith(AndroidJUnit4.class)
public class FontsContractE2ETest {
diff --git a/core/tests/coretests/src/android/provider/FontsContractTest.java b/core/tests/coretests/src/android/provider/FontsContractTest.java
index d42d79e..c5d6f7f 100644
--- a/core/tests/coretests/src/android/provider/FontsContractTest.java
+++ b/core/tests/coretests/src/android/provider/FontsContractTest.java
@@ -13,31 +13,33 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.provider;
+import static android.provider.FontsContract.Columns.RESULT_CODE_FONT_NOT_FOUND;
+import static android.provider.FontsContract.Columns.RESULT_CODE_FONT_UNAVAILABLE;
+import static android.provider.FontsContract.Columns.RESULT_CODE_MALFORMED_QUERY;
+import static android.provider.FontsContract.Columns.RESULT_CODE_OK;
+
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-import static android.provider.FontsContract.Columns.RESULT_CODE_OK;
-import static android.provider.FontsContract.Columns.RESULT_CODE_FONT_NOT_FOUND;
-import static android.provider.FontsContract.Columns.RESULT_CODE_FONT_UNAVAILABLE;
-import static android.provider.FontsContract.Columns.RESULT_CODE_MALFORMED_QUERY;
-
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ProviderInfo;
import android.content.pm.Signature;
import android.database.MatrixCursor;
import android.graphics.fonts.FontVariationAxis;
import android.provider.FontsContract.FontInfo;
-import android.support.test.filters.SmallTest;
import android.test.ProviderTestCase2;
import android.util.Base64;
+import androidx.test.filters.SmallTest;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
diff --git a/core/tests/coretests/src/android/provider/MockFontProvider.java b/core/tests/coretests/src/android/provider/MockFontProvider.java
index ad5b130..e527dec 100644
--- a/core/tests/coretests/src/android/provider/MockFontProvider.java
+++ b/core/tests/coretests/src/android/provider/MockFontProvider.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.provider;
import static android.provider.FontsContract.Columns;
@@ -21,16 +22,13 @@
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
-import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.database.Cursor;
import android.database.MatrixCursor;
-import android.graphics.fonts.FontVariationAxis;
import android.net.Uri;
-import android.os.CancellationSignal;
import android.os.ParcelFileDescriptor;
-import android.util.ArraySet;
-import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
import java.io.File;
import java.io.FileNotFoundException;
@@ -46,8 +44,6 @@
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
-import com.android.internal.annotations.GuardedBy;
-
public class MockFontProvider extends ContentProvider {
final static String AUTHORITY = "android.provider.fonts.font";
diff --git a/core/tests/coretests/src/android/provider/SearchRecentSuggestionsProviderTest.java b/core/tests/coretests/src/android/provider/SearchRecentSuggestionsProviderTest.java
index 7458de5..f84355f 100644
--- a/core/tests/coretests/src/android/provider/SearchRecentSuggestionsProviderTest.java
+++ b/core/tests/coretests/src/android/provider/SearchRecentSuggestionsProviderTest.java
@@ -21,9 +21,9 @@
import android.database.Cursor;
import android.net.Uri;
import android.test.ProviderTestCase2;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
/**
* ProviderTestCase that performs unit tests of SearchRecentSuggestionsProvider.
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 1ed5ce4..93af013 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -27,9 +27,9 @@
import static java.lang.reflect.Modifier.isStatic;
import android.platform.test.annotations.Presubmit;
-import android.provider.Settings.Global;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -270,6 +270,7 @@
Settings.Global.GNSS_HAL_LOCATION_REQUEST_DURATION_MILLIS,
Settings.Global.GNSS_SATELLITE_BLACKLIST,
Settings.Global.GPRS_REGISTER_CHECK_PERIOD_MS,
+ Settings.Global.HDMI_CEC_SWITCH_ENABLED,
Settings.Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED,
Settings.Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED,
Settings.Global.HDMI_CONTROL_ENABLED,
@@ -477,9 +478,10 @@
Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE,
Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS,
Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES,
+ Settings.Global.GUP_DEV_ALL_APPS,
Settings.Global.GUP_DEV_OPT_IN_APPS,
Settings.Global.GUP_DEV_OPT_OUT_APPS,
- Settings.Global.GUP_BLACK_LIST,
+ Settings.Global.GUP_BLACKLIST,
Settings.Global.GPU_DEBUG_LAYER_APP,
Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING,
Settings.Global.INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT,
@@ -554,8 +556,10 @@
Settings.Global.APPOP_HISTORY_PARAMETERS,
Settings.Global.APPOP_HISTORY_MODE,
Settings.Global.APPOP_HISTORY_INTERVAL_MULTIPLIER,
- Settings.Global.APPOP_HISTORY_BASE_INTERVAL_MILLIS);
-
+ Settings.Global.APPOP_HISTORY_BASE_INTERVAL_MILLIS,
+ Settings.Global.ENABLE_RADIO_BUG_DETECTION,
+ Settings.Global.RADIO_BUG_WAKELOCK_TIMEOUT_COUNT_THRESHOLD,
+ Settings.Global.RADIO_BUG_SYSTEM_ERROR_COUNT_THRESHOLD);
private static final Set<String> BACKUP_BLACKLISTED_SECURE_SETTINGS =
newHashSet(
Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
@@ -664,6 +668,7 @@
Settings.Secure.SMS_DEFAULT_APPLICATION,
Settings.Secure.SPELL_CHECKER_ENABLED, // Intentionally removed in Q
Settings.Secure.TRUST_AGENTS_INITIALIZED,
+ Settings.Secure.TV_APP_USES_NON_SYSTEM_INPUTS,
Settings.Secure.TV_INPUT_CUSTOM_LABELS,
Settings.Secure.TV_INPUT_HIDDEN_INPUTS,
Settings.Secure.TV_USER_SETUP_COMPLETE,
diff --git a/core/tests/coretests/src/android/provider/SettingsProviderTest.java b/core/tests/coretests/src/android/provider/SettingsProviderTest.java
index cb6f0e6..a5f5f67 100644
--- a/core/tests/coretests/src/android/provider/SettingsProviderTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsProviderTest.java
@@ -34,9 +34,10 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.Suppress;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.filters.Suppress;
import java.util.HashMap;
import java.util.List;
diff --git a/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java b/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java
index b0d29bd..08f9de6 100644
--- a/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java
@@ -22,8 +22,9 @@
import android.platform.test.annotations.Presubmit;
import android.provider.SettingsValidators.Validator;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/provider/SmsProviderTest.java b/core/tests/coretests/src/android/provider/SmsProviderTest.java
index af4d1a6..67ac8ea 100644
--- a/core/tests/coretests/src/android/provider/SmsProviderTest.java
+++ b/core/tests/coretests/src/android/provider/SmsProviderTest.java
@@ -22,8 +22,9 @@
import android.net.Uri;
import android.provider.Telephony.Sms;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.Suppress;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.Suppress;
import java.util.GregorianCalendar;
diff --git a/core/tests/coretests/src/android/provider/TestFontsProvider.java b/core/tests/coretests/src/android/provider/TestFontsProvider.java
index 46906df..c3457fa 100644
--- a/core/tests/coretests/src/android/provider/TestFontsProvider.java
+++ b/core/tests/coretests/src/android/provider/TestFontsProvider.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.provider;
import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
@@ -23,7 +24,6 @@
import android.content.ContentValues;
import android.database.Cursor;
import android.database.MatrixCursor;
-import android.graphics.Typeface;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
diff --git a/core/tests/coretests/src/android/security/keystore/recovery/KeyChainProtectionParamsTest.java b/core/tests/coretests/src/android/security/keystore/recovery/KeyChainProtectionParamsTest.java
index 0c9c4c1..ce0bf30 100644
--- a/core/tests/coretests/src/android/security/keystore/recovery/KeyChainProtectionParamsTest.java
+++ b/core/tests/coretests/src/android/security/keystore/recovery/KeyChainProtectionParamsTest.java
@@ -20,8 +20,9 @@
import static org.junit.Assert.assertEquals;
import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/security/keystore/recovery/KeyChainSnapshotTest.java b/core/tests/coretests/src/android/security/keystore/recovery/KeyChainSnapshotTest.java
index 61ab152..2a962c2 100644
--- a/core/tests/coretests/src/android/security/keystore/recovery/KeyChainSnapshotTest.java
+++ b/core/tests/coretests/src/android/security/keystore/recovery/KeyChainSnapshotTest.java
@@ -20,8 +20,9 @@
import static org.junit.Assert.assertEquals;
import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import com.google.common.collect.Lists;
diff --git a/core/tests/coretests/src/android/security/keystore/recovery/KeyDerivationParamsTest.java b/core/tests/coretests/src/android/security/keystore/recovery/KeyDerivationParamsTest.java
index b6af9bb..2b37b52 100644
--- a/core/tests/coretests/src/android/security/keystore/recovery/KeyDerivationParamsTest.java
+++ b/core/tests/coretests/src/android/security/keystore/recovery/KeyDerivationParamsTest.java
@@ -20,8 +20,9 @@
import static org.junit.Assert.assertEquals;
import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/security/keystore/recovery/RecoveryCertPathTest.java b/core/tests/coretests/src/android/security/keystore/recovery/RecoveryCertPathTest.java
index dd8cd8d..3b8f715 100644
--- a/core/tests/coretests/src/android/security/keystore/recovery/RecoveryCertPathTest.java
+++ b/core/tests/coretests/src/android/security/keystore/recovery/RecoveryCertPathTest.java
@@ -20,8 +20,9 @@
import static org.junit.Assert.fail;
import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/security/keystore/recovery/TrustedRootCertificatesTest.java b/core/tests/coretests/src/android/security/keystore/recovery/TrustedRootCertificatesTest.java
index a5a3ca9..2b15d73 100644
--- a/core/tests/coretests/src/android/security/keystore/recovery/TrustedRootCertificatesTest.java
+++ b/core/tests/coretests/src/android/security/keystore/recovery/TrustedRootCertificatesTest.java
@@ -20,8 +20,8 @@
import static org.junit.Assert.assertTrue;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/security/keystore/recovery/WrappedApplicationKeyTest.java b/core/tests/coretests/src/android/security/keystore/recovery/WrappedApplicationKeyTest.java
index 15afbdd..8522e62 100644
--- a/core/tests/coretests/src/android/security/keystore/recovery/WrappedApplicationKeyTest.java
+++ b/core/tests/coretests/src/android/security/keystore/recovery/WrappedApplicationKeyTest.java
@@ -20,8 +20,9 @@
import static org.junit.Assert.assertEquals;
import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Before;
diff --git a/core/tests/coretests/src/android/security/keystore/recovery/X509CertificateParsingUtilsTest.java b/core/tests/coretests/src/android/security/keystore/recovery/X509CertificateParsingUtilsTest.java
index 7f0eb43..17486d5 100644
--- a/core/tests/coretests/src/android/security/keystore/recovery/X509CertificateParsingUtilsTest.java
+++ b/core/tests/coretests/src/android/security/keystore/recovery/X509CertificateParsingUtilsTest.java
@@ -21,8 +21,8 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/service/euicc/EuiccProfileInfoTest.java b/core/tests/coretests/src/android/service/euicc/EuiccProfileInfoTest.java
index e69d1e7..d00d052 100644
--- a/core/tests/coretests/src/android/service/euicc/EuiccProfileInfoTest.java
+++ b/core/tests/coretests/src/android/service/euicc/EuiccProfileInfoTest.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.service.euicc;
import static org.junit.Assert.assertArrayEquals;
@@ -23,10 +24,11 @@
import android.os.Parcel;
import android.service.carrier.CarrierIdentifier;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.telephony.UiccAccessRule;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java b/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java
index 8a3ba8c..4aa1000 100644
--- a/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java
+++ b/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.service.notification;
import static junit.framework.Assert.assertEquals;
@@ -28,9 +29,10 @@
import android.content.pm.PackageManager;
import android.metrics.LogMaker;
import android.os.UserHandle;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
diff --git a/core/tests/coretests/src/android/service/settings/suggestions/MockSuggestionService.java b/core/tests/coretests/src/android/service/settings/suggestions/MockSuggestionService.java
index ab541a1..9c8e868 100644
--- a/core/tests/coretests/src/android/service/settings/suggestions/MockSuggestionService.java
+++ b/core/tests/coretests/src/android/service/settings/suggestions/MockSuggestionService.java
@@ -16,16 +16,12 @@
package android.service.settings.suggestions;
-import android.support.annotation.VisibleForTesting;
-
import java.util.ArrayList;
import java.util.List;
public class MockSuggestionService extends SuggestionService {
- @VisibleForTesting
static boolean sOnSuggestionLaunchedCalled;
- @VisibleForTesting
static boolean sOnSuggestionDismissedCalled;
public static void reset() {
diff --git a/core/tests/coretests/src/android/service/settings/suggestions/SuggestionServiceTest.java b/core/tests/coretests/src/android/service/settings/suggestions/SuggestionServiceTest.java
index dca8c09..64edda5 100644
--- a/core/tests/coretests/src/android/service/settings/suggestions/SuggestionServiceTest.java
+++ b/core/tests/coretests/src/android/service/settings/suggestions/SuggestionServiceTest.java
@@ -21,10 +21,11 @@
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.rule.ServiceTestRule;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.rule.ServiceTestRule;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Before;
diff --git a/core/tests/coretests/src/android/service/settings/suggestions/SuggestionTest.java b/core/tests/coretests/src/android/service/settings/suggestions/SuggestionTest.java
index b0ec55d..8c47fcb 100644
--- a/core/tests/coretests/src/android/service/settings/suggestions/SuggestionTest.java
+++ b/core/tests/coretests/src/android/service/settings/suggestions/SuggestionTest.java
@@ -24,9 +24,10 @@
import android.graphics.Bitmap;
import android.graphics.drawable.Icon;
import android.os.Parcel;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/text/AndroidCharacterTest.java b/core/tests/coretests/src/android/text/AndroidCharacterTest.java
index 0c7e730..1c5986a 100644
--- a/core/tests/coretests/src/android/text/AndroidCharacterTest.java
+++ b/core/tests/coretests/src/android/text/AndroidCharacterTest.java
@@ -19,7 +19,8 @@
import static org.junit.Assert.assertArrayEquals;
import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/text/BidiFormatterTest.java b/core/tests/coretests/src/android/text/BidiFormatterTest.java
index 1b936c7..312fb68 100644
--- a/core/tests/coretests/src/android/text/BidiFormatterTest.java
+++ b/core/tests/coretests/src/android/text/BidiFormatterTest.java
@@ -19,8 +19,9 @@
import static org.junit.Assert.assertEquals;
import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/DynamicLayoutBlocksTest.java b/core/tests/coretests/src/android/text/DynamicLayoutBlocksTest.java
index c69f4f5..cca1ad3 100644
--- a/core/tests/coretests/src/android/text/DynamicLayoutBlocksTest.java
+++ b/core/tests/coretests/src/android/text/DynamicLayoutBlocksTest.java
@@ -22,8 +22,9 @@
import static org.junit.Assert.assertTrue;
import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/DynamicLayoutTest.java b/core/tests/coretests/src/android/text/DynamicLayoutTest.java
index ea954f6..699243b 100644
--- a/core/tests/coretests/src/android/text/DynamicLayoutTest.java
+++ b/core/tests/coretests/src/android/text/DynamicLayoutTest.java
@@ -27,11 +27,12 @@
import android.graphics.Canvas;
import android.graphics.Paint;
import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.text.style.ReplacementSpan;
import android.util.ArraySet;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/EmojiTest.java b/core/tests/coretests/src/android/text/EmojiTest.java
index 313f1b6..1948994 100644
--- a/core/tests/coretests/src/android/text/EmojiTest.java
+++ b/core/tests/coretests/src/android/text/EmojiTest.java
@@ -21,8 +21,9 @@
import android.icu.lang.UCharacterDirection;
import android.icu.text.Bidi;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/FontFallbackSetup.java b/core/tests/coretests/src/android/text/FontFallbackSetup.java
index 5592aac..cc51ec3 100644
--- a/core/tests/coretests/src/android/text/FontFallbackSetup.java
+++ b/core/tests/coretests/src/android/text/FontFallbackSetup.java
@@ -24,9 +24,10 @@
import android.graphics.fonts.FontCustomizationParser;
import android.graphics.fonts.FontFamily;
import android.graphics.fonts.SystemFonts;
-import android.support.test.InstrumentationRegistry;
import android.util.ArrayMap;
+import androidx.test.InstrumentationRegistry;
+
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
diff --git a/core/tests/coretests/src/android/text/LayoutBidiCursorPathTest.java b/core/tests/coretests/src/android/text/LayoutBidiCursorPathTest.java
index 1208d7c..96e7fb9 100644
--- a/core/tests/coretests/src/android/text/LayoutBidiCursorPathTest.java
+++ b/core/tests/coretests/src/android/text/LayoutBidiCursorPathTest.java
@@ -22,12 +22,13 @@
import android.graphics.Path;
import android.graphics.Typeface;
import android.platform.test.annotations.Presubmit;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.text.method.MetaKeyKeyListener;
import android.view.KeyEvent;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/LayoutTest.java b/core/tests/coretests/src/android/text/LayoutTest.java
index 97937a4..990161a 100644
--- a/core/tests/coretests/src/android/text/LayoutTest.java
+++ b/core/tests/coretests/src/android/text/LayoutTest.java
@@ -31,11 +31,12 @@
import android.graphics.Rect;
import android.graphics.RectF;
import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.text.Layout.Alignment;
import android.text.style.StrikethroughSpan;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/MeasuredParagraphTest.java b/core/tests/coretests/src/android/text/MeasuredParagraphTest.java
index a0dca2c..57bb434 100644
--- a/core/tests/coretests/src/android/text/MeasuredParagraphTest.java
+++ b/core/tests/coretests/src/android/text/MeasuredParagraphTest.java
@@ -23,9 +23,10 @@
import android.content.Context;
import android.graphics.Typeface;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/PackedIntVectorTest.java b/core/tests/coretests/src/android/text/PackedIntVectorTest.java
index d9dc6fc..ba15b92 100644
--- a/core/tests/coretests/src/android/text/PackedIntVectorTest.java
+++ b/core/tests/coretests/src/android/text/PackedIntVectorTest.java
@@ -19,8 +19,9 @@
import static org.junit.Assert.assertEquals;
import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/SpannableStringBuilderTest.java b/core/tests/coretests/src/android/text/SpannableStringBuilderTest.java
index d0f2d46..91b8c6a 100644
--- a/core/tests/coretests/src/android/text/SpannableStringBuilderTest.java
+++ b/core/tests/coretests/src/android/text/SpannableStringBuilderTest.java
@@ -16,18 +16,18 @@
package android.text;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.text.style.BulletSpan;
import android.text.style.QuoteSpan;
import android.text.style.SubscriptSpan;
import android.text.style.UnderlineSpan;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/SpannableStringNoCopyTest.java b/core/tests/coretests/src/android/text/SpannableStringNoCopyTest.java
index 6c05601..9149f7b 100644
--- a/core/tests/coretests/src/android/text/SpannableStringNoCopyTest.java
+++ b/core/tests/coretests/src/android/text/SpannableStringNoCopyTest.java
@@ -21,11 +21,12 @@
import static org.junit.Assert.assertNotNull;
import android.annotation.NonNull;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.text.style.QuoteSpan;
import android.text.style.UnderlineSpan;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/SpannableTest.java b/core/tests/coretests/src/android/text/SpannableTest.java
index f368428..d248a1f 100644
--- a/core/tests/coretests/src/android/text/SpannableTest.java
+++ b/core/tests/coretests/src/android/text/SpannableTest.java
@@ -19,10 +19,11 @@
import static org.junit.Assert.assertEquals;
import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.test.MoreAsserts;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/SpannedStringNoCopyTest.java b/core/tests/coretests/src/android/text/SpannedStringNoCopyTest.java
index 380e315..ca43733 100644
--- a/core/tests/coretests/src/android/text/SpannedStringNoCopyTest.java
+++ b/core/tests/coretests/src/android/text/SpannedStringNoCopyTest.java
@@ -21,11 +21,12 @@
import static org.junit.Assert.assertNotNull;
import android.annotation.NonNull;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.text.style.QuoteSpan;
import android.text.style.UnderlineSpan;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/SpannedTest.java b/core/tests/coretests/src/android/text/SpannedTest.java
index 5737571..3ab0755 100644
--- a/core/tests/coretests/src/android/text/SpannedTest.java
+++ b/core/tests/coretests/src/android/text/SpannedTest.java
@@ -21,13 +21,14 @@
import android.graphics.Typeface;
import android.os.Parcel;
import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.text.style.CharacterStyle;
import android.text.style.StyleSpan;
import android.text.style.TextAppearanceSpan;
import android.text.style.TypefaceSpan;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/StaticLayoutBidiTest.java b/core/tests/coretests/src/android/text/StaticLayoutBidiTest.java
index bf0d427..32370b3e 100644
--- a/core/tests/coretests/src/android/text/StaticLayoutBidiTest.java
+++ b/core/tests/coretests/src/android/text/StaticLayoutBidiTest.java
@@ -19,10 +19,11 @@
import static org.junit.Assert.assertEquals;
import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.util.Log;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/StaticLayoutDirectionsTest.java b/core/tests/coretests/src/android/text/StaticLayoutDirectionsTest.java
index 5cf5426..4221ac2 100644
--- a/core/tests/coretests/src/android/text/StaticLayoutDirectionsTest.java
+++ b/core/tests/coretests/src/android/text/StaticLayoutDirectionsTest.java
@@ -19,11 +19,12 @@
import static org.junit.Assert.fail;
import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.text.Layout.Directions;
import android.text.StaticLayoutTest.LayoutBuilder;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/StaticLayoutTest.java b/core/tests/coretests/src/android/text/StaticLayoutTest.java
index 2521712..b1c896e 100644
--- a/core/tests/coretests/src/android/text/StaticLayoutTest.java
+++ b/core/tests/coretests/src/android/text/StaticLayoutTest.java
@@ -25,13 +25,14 @@
import android.graphics.Paint.FontMetricsInt;
import android.os.LocaleList;
import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.text.Layout.Alignment;
import android.text.method.EditorState;
import android.text.style.LocaleSpan;
import android.util.Log;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/StaticLayoutTextMeasuringTest.java b/core/tests/coretests/src/android/text/StaticLayoutTextMeasuringTest.java
index f6888e3..0d42326 100644
--- a/core/tests/coretests/src/android/text/StaticLayoutTextMeasuringTest.java
+++ b/core/tests/coretests/src/android/text/StaticLayoutTextMeasuringTest.java
@@ -19,10 +19,11 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.text.Layout.Alignment;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/TextLayoutTest.java b/core/tests/coretests/src/android/text/TextLayoutTest.java
index 24020ce..15fbc9e 100644
--- a/core/tests/coretests/src/android/text/TextLayoutTest.java
+++ b/core/tests/coretests/src/android/text/TextLayoutTest.java
@@ -17,8 +17,9 @@
package android.text;
import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/text/TextLineTest.java b/core/tests/coretests/src/android/text/TextLineTest.java
index 2fe882c..90ce305 100644
--- a/core/tests/coretests/src/android/text/TextLineTest.java
+++ b/core/tests/coretests/src/android/text/TextLineTest.java
@@ -25,14 +25,15 @@
import android.graphics.Paint;
import android.graphics.Typeface;
import android.platform.test.annotations.Presubmit;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.filters.Suppress;
-import android.support.test.runner.AndroidJUnit4;
import android.text.Layout.TabStops;
import android.text.style.ReplacementSpan;
import android.text.style.TabStopSpan;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.filters.Suppress;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/TextUtilsTest.java b/core/tests/coretests/src/android/text/TextUtilsTest.java
index 72290bf..be6ef19 100644
--- a/core/tests/coretests/src/android/text/TextUtilsTest.java
+++ b/core/tests/coretests/src/android/text/TextUtilsTest.java
@@ -26,15 +26,16 @@
import android.os.Parcel;
import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.LargeTest;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.test.MoreAsserts;
import android.text.style.StyleSpan;
import android.text.util.Rfc822Token;
import android.text.util.Rfc822Tokenizer;
import android.view.View;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import com.google.android.collect.Lists;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/text/VariationParserTest.java b/core/tests/coretests/src/android/text/VariationParserTest.java
index fbd2412..0afe811 100644
--- a/core/tests/coretests/src/android/text/VariationParserTest.java
+++ b/core/tests/coretests/src/android/text/VariationParserTest.java
@@ -21,8 +21,9 @@
import android.graphics.fonts.FontVariationAxis;
import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/format/DateFormatTest.java b/core/tests/coretests/src/android/text/format/DateFormatTest.java
index 9000ed0..5a0a84d 100644
--- a/core/tests/coretests/src/android/text/format/DateFormatTest.java
+++ b/core/tests/coretests/src/android/text/format/DateFormatTest.java
@@ -20,8 +20,9 @@
import static org.junit.Assert.assertTrue;
import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/format/DateUtilsTest.java b/core/tests/coretests/src/android/text/format/DateUtilsTest.java
index 872b71a..381c051 100644
--- a/core/tests/coretests/src/android/text/format/DateUtilsTest.java
+++ b/core/tests/coretests/src/android/text/format/DateUtilsTest.java
@@ -22,8 +22,9 @@
import android.content.res.Resources;
import android.os.LocaleList;
import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Before;
diff --git a/core/tests/coretests/src/android/text/format/FormatterTest.java b/core/tests/coretests/src/android/text/format/FormatterTest.java
index 82e4bff..068d047 100644
--- a/core/tests/coretests/src/android/text/format/FormatterTest.java
+++ b/core/tests/coretests/src/android/text/format/FormatterTest.java
@@ -25,11 +25,12 @@
import android.content.res.Configuration;
import android.content.res.Resources;
import android.platform.test.annotations.Presubmit;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.text.format.Formatter.BytesResult;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/text/format/TimeTest.java b/core/tests/coretests/src/android/text/format/TimeTest.java
index d563f2e..ac00411 100644
--- a/core/tests/coretests/src/android/text/format/TimeTest.java
+++ b/core/tests/coretests/src/android/text/format/TimeTest.java
@@ -21,12 +21,13 @@
import static org.junit.Assert.fail;
import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.filters.Suppress;
-import android.support.test.runner.AndroidJUnit4;
import android.util.Log;
import android.util.TimeFormatException;
+import androidx.test.filters.SmallTest;
+import androidx.test.filters.Suppress;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/method/BackspaceTest.java b/core/tests/coretests/src/android/text/method/BackspaceTest.java
index df4609f..ddae652 100644
--- a/core/tests/coretests/src/android/text/method/BackspaceTest.java
+++ b/core/tests/coretests/src/android/text/method/BackspaceTest.java
@@ -17,15 +17,16 @@
package android.text.method;
import android.platform.test.annotations.Presubmit;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.text.InputType;
import android.util.KeyUtils;
import android.view.KeyEvent;
import android.widget.EditText;
import android.widget.TextView.BufferType;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/method/EditorState.java b/core/tests/coretests/src/android/text/method/EditorState.java
index 12bb8c8..4eff7a4 100644
--- a/core/tests/coretests/src/android/text/method/EditorState.java
+++ b/core/tests/coretests/src/android/text/method/EditorState.java
@@ -21,8 +21,6 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-import android.graphics.Canvas;
-import android.graphics.Paint;
import android.text.Editable;
import android.text.Spannable;
import android.text.SpannableString;
diff --git a/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java b/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java
index 45a5010..45b63e0 100644
--- a/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java
+++ b/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java
@@ -17,15 +17,16 @@
package android.text.method;
import android.platform.test.annotations.Presubmit;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.text.InputType;
import android.util.KeyUtils;
import android.view.KeyEvent;
import android.widget.EditText;
import android.widget.TextView.BufferType;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/method/WordIteratorTest.java b/core/tests/coretests/src/android/text/method/WordIteratorTest.java
index 6845863..cc345f5 100644
--- a/core/tests/coretests/src/android/text/method/WordIteratorTest.java
+++ b/core/tests/coretests/src/android/text/method/WordIteratorTest.java
@@ -22,8 +22,9 @@
import static org.junit.Assert.fail;
import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/style/UnderlineSpanTest.java b/core/tests/coretests/src/android/text/style/UnderlineSpanTest.java
index 3d7e5ba..a0d2f85 100644
--- a/core/tests/coretests/src/android/text/style/UnderlineSpanTest.java
+++ b/core/tests/coretests/src/android/text/style/UnderlineSpanTest.java
@@ -16,17 +16,17 @@
package android.text.style;
-
import static org.junit.Assert.assertEquals;
import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.StaticLayout;
import android.text.TextPaint;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/util/LinkifyTest.java b/core/tests/coretests/src/android/text/util/LinkifyTest.java
index be3a0be..107ecd7 100644
--- a/core/tests/coretests/src/android/text/util/LinkifyTest.java
+++ b/core/tests/coretests/src/android/text/util/LinkifyTest.java
@@ -23,9 +23,6 @@
import android.content.Context;
import android.content.res.Configuration;
import android.os.LocaleList;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.method.LinkMovementMethod;
@@ -33,6 +30,10 @@
import android.util.Patterns;
import android.widget.TextView;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/transition/AutoTransitionTest.java b/core/tests/coretests/src/android/transition/AutoTransitionTest.java
index 834fb7a..deae967 100644
--- a/core/tests/coretests/src/android/transition/AutoTransitionTest.java
+++ b/core/tests/coretests/src/android/transition/AutoTransitionTest.java
@@ -16,16 +16,16 @@
package android.transition;
-import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@RunWith(AndroidJUnit4.class)
public class AutoTransitionTest {
@Test
diff --git a/core/tests/coretests/src/android/transition/FadeTransitionTest.java b/core/tests/coretests/src/android/transition/FadeTransitionTest.java
index 22365ba..2077d94 100644
--- a/core/tests/coretests/src/android/transition/FadeTransitionTest.java
+++ b/core/tests/coretests/src/android/transition/FadeTransitionTest.java
@@ -22,13 +22,14 @@
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.SmallTest;
import android.transition.Transition.TransitionListener;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
+import androidx.test.filters.SmallTest;
+
import com.android.frameworks.coretests.R;
import java.util.concurrent.CountDownLatch;
diff --git a/core/tests/coretests/src/android/transition/SlideTransitionTest.java b/core/tests/coretests/src/android/transition/SlideTransitionTest.java
index 8b9ec74..046e49d 100644
--- a/core/tests/coretests/src/android/transition/SlideTransitionTest.java
+++ b/core/tests/coretests/src/android/transition/SlideTransitionTest.java
@@ -19,18 +19,18 @@
import android.animation.AnimatorSetActivity;
import android.app.Activity;
import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.SmallTest;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
+import androidx.test.filters.SmallTest;
+
import com.android.frameworks.coretests.R;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-
public class SlideTransitionTest extends ActivityInstrumentationTestCase2<AnimatorSetActivity> {
Activity mActivity;
diff --git a/core/tests/coretests/src/android/transition/TransitionTest.java b/core/tests/coretests/src/android/transition/TransitionTest.java
index 7e629f9..f59c406 100644
--- a/core/tests/coretests/src/android/transition/TransitionTest.java
+++ b/core/tests/coretests/src/android/transition/TransitionTest.java
@@ -19,7 +19,6 @@
import android.animation.AnimatorSetActivity;
import android.app.Activity;
import android.graphics.Rect;
-import android.support.test.filters.LargeTest;
import android.test.ActivityInstrumentationTestCase2;
import android.transition.Transition.EpicenterCallback;
import android.util.ArrayMap;
@@ -27,6 +26,8 @@
import android.view.animation.AccelerateInterpolator;
import android.widget.TextView;
+import androidx.test.filters.LargeTest;
+
import com.android.frameworks.coretests.R;
import java.lang.reflect.Field;
diff --git a/core/tests/coretests/src/android/util/ArrayMapTest.java b/core/tests/coretests/src/android/util/ArrayMapTest.java
index f0cc7f7..b212cf6 100644
--- a/core/tests/coretests/src/android/util/ArrayMapTest.java
+++ b/core/tests/coretests/src/android/util/ArrayMapTest.java
@@ -14,10 +14,10 @@
package android.util;
-import android.support.test.filters.LargeTest;
-import android.util.ArrayMap;
+import androidx.test.filters.LargeTest;
import junit.framework.TestCase;
+
import org.junit.Test;
import java.util.ConcurrentModificationException;
diff --git a/core/tests/coretests/src/android/util/Base64Test.java b/core/tests/coretests/src/android/util/Base64Test.java
index af608c3..15c51af 100644
--- a/core/tests/coretests/src/android/util/Base64Test.java
+++ b/core/tests/coretests/src/android/util/Base64Test.java
@@ -16,7 +16,7 @@
package android.util;
-import android.support.test.filters.LargeTest;
+import androidx.test.filters.LargeTest;
import junit.framework.TestCase;
diff --git a/core/tests/coretests/src/android/util/DataUnitTest.java b/core/tests/coretests/src/android/util/DataUnitTest.java
index 4eae8b4..ec296b7 100644
--- a/core/tests/coretests/src/android/util/DataUnitTest.java
+++ b/core/tests/coretests/src/android/util/DataUnitTest.java
@@ -16,7 +16,7 @@
package android.util;
-import android.support.test.filters.SmallTest;
+import androidx.test.filters.SmallTest;
import junit.framework.TestCase;
diff --git a/core/tests/coretests/src/android/util/DayOfMonthCursorTest.java b/core/tests/coretests/src/android/util/DayOfMonthCursorTest.java
index 4c5ad76..572e9b0 100644
--- a/core/tests/coretests/src/android/util/DayOfMonthCursorTest.java
+++ b/core/tests/coretests/src/android/util/DayOfMonthCursorTest.java
@@ -16,10 +16,11 @@
package android.util;
+import androidx.test.filters.SmallTest;
+
import junit.framework.TestCase;
import java.util.Calendar;
-import android.test.suitebuilder.annotation.SmallTest;
/**
* Unit tests for {@link DayOfMonthCursor}.
diff --git a/core/tests/coretests/src/android/util/InternalSelectionView.java b/core/tests/coretests/src/android/util/InternalSelectionView.java
index a0fb0f1..4a1baef 100644
--- a/core/tests/coretests/src/android/util/InternalSelectionView.java
+++ b/core/tests/coretests/src/android/util/InternalSelectionView.java
@@ -16,19 +16,16 @@
package android.util;
-import com.android.frameworks.coretests.R;
-
-import android.view.View;
-import android.view.KeyEvent;
import android.content.Context;
import android.content.res.TypedArray;
-import android.graphics.Paint;
import android.graphics.Canvas;
-import android.graphics.Rect;
import android.graphics.Color;
-import android.util.AttributeSet;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.view.KeyEvent;
+import android.view.View;
-
+import com.android.frameworks.coretests.R;
/**
* A view that has a known number of selectable rows, and maintains a notion of which
diff --git a/core/tests/coretests/src/android/util/KeyUtils.java b/core/tests/coretests/src/android/util/KeyUtils.java
index 593f727..612643e 100644
--- a/core/tests/coretests/src/android/util/KeyUtils.java
+++ b/core/tests/coretests/src/android/util/KeyUtils.java
@@ -17,16 +17,10 @@
package android.util;
import android.app.Instrumentation;
-import android.os.SystemClock;
import android.test.ActivityInstrumentationTestCase;
-import android.test.InstrumentationTestCase;
-import android.view.Gravity;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.View;
import android.view.ViewConfiguration;
-import android.view.ViewGroup;
/**
* Reusable methods for generating key events.
diff --git a/core/tests/coretests/src/android/util/KeyValueListParserTest.java b/core/tests/coretests/src/android/util/KeyValueListParserTest.java
index 038f0b7..f65c4c7 100644
--- a/core/tests/coretests/src/android/util/KeyValueListParserTest.java
+++ b/core/tests/coretests/src/android/util/KeyValueListParserTest.java
@@ -19,8 +19,9 @@
import static org.junit.Assert.assertEquals;
import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/util/ListUtil.java b/core/tests/coretests/src/android/util/ListUtil.java
index 2a7cb96..3748cf8 100644
--- a/core/tests/coretests/src/android/util/ListUtil.java
+++ b/core/tests/coretests/src/android/util/ListUtil.java
@@ -20,13 +20,11 @@
import android.view.KeyEvent;
import android.widget.ListView;
-
/**
* Various useful stuff for instrumentation testing listview.
*/
public class ListUtil {
-
private final ListView mListView;
private final Instrumentation mInstrumentation;
diff --git a/core/tests/coretests/src/android/util/LocalLogTest.java b/core/tests/coretests/src/android/util/LocalLogTest.java
index 5144c85e..6cdcb5e 100644
--- a/core/tests/coretests/src/android/util/LocalLogTest.java
+++ b/core/tests/coretests/src/android/util/LocalLogTest.java
@@ -16,7 +16,7 @@
package android.util;
-import android.support.test.filters.LargeTest;
+import androidx.test.filters.LargeTest;
import junit.framework.TestCase;
diff --git a/core/tests/coretests/src/android/util/LogNullabilityTest.java b/core/tests/coretests/src/android/util/LogNullabilityTest.java
index 3f4776d..370885d 100644
--- a/core/tests/coretests/src/android/util/LogNullabilityTest.java
+++ b/core/tests/coretests/src/android/util/LogNullabilityTest.java
@@ -19,8 +19,8 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
-import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/util/LogTest.java b/core/tests/coretests/src/android/util/LogTest.java
index 30c81b0..d783c12 100644
--- a/core/tests/coretests/src/android/util/LogTest.java
+++ b/core/tests/coretests/src/android/util/LogTest.java
@@ -16,13 +16,12 @@
package android.util;
-import junit.framework.Assert;
-import junit.framework.TestCase;
-
import android.os.SystemProperties;
import android.test.PerformanceTestCase;
-import android.test.suitebuilder.annotation.Suppress;
-import android.util.Log;
+
+import androidx.test.filters.Suppress;
+
+import junit.framework.TestCase;
//This is an empty TestCase.
@Suppress
diff --git a/core/tests/coretests/src/android/util/LongSparseLongArrayTest.java b/core/tests/coretests/src/android/util/LongSparseLongArrayTest.java
index 3f03db9..a1d48e6 100644
--- a/core/tests/coretests/src/android/util/LongSparseLongArrayTest.java
+++ b/core/tests/coretests/src/android/util/LongSparseLongArrayTest.java
@@ -16,7 +16,7 @@
package android.util;
-import android.support.test.filters.LargeTest;
+import androidx.test.filters.LargeTest;
import junit.framework.TestCase;
diff --git a/core/tests/coretests/src/android/util/LruCacheTest.java b/core/tests/coretests/src/android/util/LruCacheTest.java
index 5a97158..1928bfd 100644
--- a/core/tests/coretests/src/android/util/LruCacheTest.java
+++ b/core/tests/coretests/src/android/util/LruCacheTest.java
@@ -16,12 +16,13 @@
package android.util;
+import junit.framework.TestCase;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
-import junit.framework.TestCase;
public final class LruCacheTest extends TestCase {
private int expectedCreateCount;
diff --git a/core/tests/coretests/src/android/util/MonthDisplayHelperTest.java b/core/tests/coretests/src/android/util/MonthDisplayHelperTest.java
index 55da665..30d5f77 100644
--- a/core/tests/coretests/src/android/util/MonthDisplayHelperTest.java
+++ b/core/tests/coretests/src/android/util/MonthDisplayHelperTest.java
@@ -16,12 +16,12 @@
package android.util;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import java.util.Calendar;
+import androidx.test.filters.SmallTest;
import junit.framework.TestCase;
+import java.util.Calendar;
+
/**
* Unit tests for {@link MonthDisplayHelper}.
*/
diff --git a/core/tests/coretests/src/android/util/OrientationUtil.java b/core/tests/coretests/src/android/util/OrientationUtil.java
index ecdca5d..0361194 100644
--- a/core/tests/coretests/src/android/util/OrientationUtil.java
+++ b/core/tests/coretests/src/android/util/OrientationUtil.java
@@ -19,7 +19,6 @@
import android.app.Activity;
import android.app.Instrumentation;
import android.content.pm.ActivityInfo;
-
import android.test.ActivityInstrumentationTestCase2;
import com.android.internal.util.Preconditions;
diff --git a/core/tests/coretests/src/android/util/PatternsTest.java b/core/tests/coretests/src/android/util/PatternsTest.java
index 360b875..6cea2f3 100644
--- a/core/tests/coretests/src/android/util/PatternsTest.java
+++ b/core/tests/coretests/src/android/util/PatternsTest.java
@@ -13,15 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.util;
-import android.support.test.filters.SmallTest;
+import androidx.test.filters.SmallTest;
+
+import junit.framework.TestCase;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import junit.framework.TestCase;
-
public class PatternsTest extends TestCase {
// Tests for Patterns.TOP_LEVEL_DOMAIN
diff --git a/core/tests/coretests/src/android/util/RecurrenceRuleTest.java b/core/tests/coretests/src/android/util/RecurrenceRuleTest.java
index 39d492d..caa1208 100644
--- a/core/tests/coretests/src/android/util/RecurrenceRuleTest.java
+++ b/core/tests/coretests/src/android/util/RecurrenceRuleTest.java
@@ -16,7 +16,7 @@
package android.util;
-import android.support.test.filters.SmallTest;
+import androidx.test.filters.SmallTest;
import junit.framework.TestCase;
diff --git a/core/tests/coretests/src/android/util/SparseLongArrayTest.java b/core/tests/coretests/src/android/util/SparseLongArrayTest.java
index 5a5e893..df2d752 100644
--- a/core/tests/coretests/src/android/util/SparseLongArrayTest.java
+++ b/core/tests/coretests/src/android/util/SparseLongArrayTest.java
@@ -19,9 +19,10 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import android.support.annotation.NonNull;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+import android.annotation.NonNull;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/util/StateSetTest.java b/core/tests/coretests/src/android/util/StateSetTest.java
index e481ce0..b5d6270 100644
--- a/core/tests/coretests/src/android/util/StateSetTest.java
+++ b/core/tests/coretests/src/android/util/StateSetTest.java
@@ -16,8 +16,9 @@
package android.util;
+import androidx.test.filters.SmallTest;
+
import junit.framework.TestCase;
-import android.test.suitebuilder.annotation.SmallTest;
/**
* Tests for {@link StateSet}
diff --git a/core/tests/coretests/src/android/util/TimestampedValueTest.java b/core/tests/coretests/src/android/util/TimestampedValueTest.java
index 03b4abd..6e3ab79 100644
--- a/core/tests/coretests/src/android/util/TimestampedValueTest.java
+++ b/core/tests/coretests/src/android/util/TimestampedValueTest.java
@@ -21,7 +21,8 @@
import static org.junit.Assert.fail;
import android.os.Parcel;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/util/TimingsTraceLogTest.java b/core/tests/coretests/src/android/util/TimingsTraceLogTest.java
index 7bb4ab8..77d0552 100644
--- a/core/tests/coretests/src/android/util/TimingsTraceLogTest.java
+++ b/core/tests/coretests/src/android/util/TimingsTraceLogTest.java
@@ -19,8 +19,9 @@
import static org.junit.Assert.assertTrue;
import android.os.Trace;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -28,7 +29,6 @@
import java.util.ArrayList;
import java.util.List;
-
/**
* Tests for {@link TimingsTraceLog}.
* <p>Usage: bit FrameworksCoreTests:android.util.TimingsTraceLogTest
diff --git a/core/tests/coretests/src/android/util/TouchModeFlexibleAsserts.java b/core/tests/coretests/src/android/util/TouchModeFlexibleAsserts.java
index ca12a15..fc08235 100644
--- a/core/tests/coretests/src/android/util/TouchModeFlexibleAsserts.java
+++ b/core/tests/coretests/src/android/util/TouchModeFlexibleAsserts.java
@@ -16,12 +16,12 @@
package android.util;
-import junit.framework.Assert;
-
import android.test.InstrumentationTestCase;
import android.test.TouchUtils;
import android.view.View;
+import junit.framework.Assert;
+
/**
* When entering touch mode via touch, the tests can be flaky. These asserts
* are more flexible (allowing up to MAX_ATTEMPTS touches to enter touch mode via touch or
diff --git a/core/tests/coretests/src/android/view/BigCache.java b/core/tests/coretests/src/android/view/BigCache.java
index 2182176..6a1bcaa 100644
--- a/core/tests/coretests/src/android/view/BigCache.java
+++ b/core/tests/coretests/src/android/view/BigCache.java
@@ -16,16 +16,12 @@
package android.view;
-import com.android.frameworks.coretests.R;
-
-import android.os.Bundle;
import android.app.Activity;
+import android.os.Bundle;
import android.widget.LinearLayout;
import android.widget.ScrollView;
-import android.view.ViewGroup;
-import android.view.View;
-import android.view.Display;
-import android.view.ViewConfiguration;
+
+import com.android.frameworks.coretests.R;
/**
* This activity contains two Views, one as big as the screen, one much larger. The large one
diff --git a/core/tests/coretests/src/android/view/BigCacheTest.java b/core/tests/coretests/src/android/view/BigCacheTest.java
index 8c2c865..ed4b996 100644
--- a/core/tests/coretests/src/android/view/BigCacheTest.java
+++ b/core/tests/coretests/src/android/view/BigCacheTest.java
@@ -16,14 +16,12 @@
package android.view;
-import android.view.BigCache;
-import com.android.frameworks.coretests.R;
-
-import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.view.View;
-import android.view.ViewConfiguration;
import android.graphics.Bitmap;
+import android.test.ActivityInstrumentationTestCase;
+
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
/**
* Builds the drawing cache of two Views, one smaller than the maximum cache size,
diff --git a/core/tests/coretests/src/android/view/BitmapDrawable.java b/core/tests/coretests/src/android/view/BitmapDrawable.java
index f7bad84..42c176f 100644
--- a/core/tests/coretests/src/android/view/BitmapDrawable.java
+++ b/core/tests/coretests/src/android/view/BitmapDrawable.java
@@ -16,19 +16,10 @@
package android.view;
-import com.android.frameworks.coretests.R;
-
import android.app.Activity;
-import android.graphics.drawable.Drawable;
import android.os.Bundle;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.AbsoluteLayout;
-import android.widget.Button;
-import android.widget.FrameLayout;
-import android.widget.LinearLayout;
-import android.widget.RelativeLayout;
-import android.widget.TextView;
+
+import com.android.frameworks.coretests.R;
public class BitmapDrawable extends Activity {
@Override
diff --git a/core/tests/coretests/src/android/view/CreateViewTest.java b/core/tests/coretests/src/android/view/CreateViewTest.java
index 16656f6..520f83f 100644
--- a/core/tests/coretests/src/android/view/CreateViewTest.java
+++ b/core/tests/coretests/src/android/view/CreateViewTest.java
@@ -16,16 +16,17 @@
package android.view;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+
import android.content.Context;
import android.test.AndroidTestCase;
import android.test.PerformanceTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.view.View;
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import android.widget.LinearLayout;
import android.widget.TextView;
+import androidx.test.filters.SmallTest;
+
public class CreateViewTest extends AndroidTestCase implements PerformanceTestCase {
public boolean isPerformanceOnly() {
diff --git a/core/tests/coretests/src/android/view/Disabled.java b/core/tests/coretests/src/android/view/Disabled.java
index d3c7470..ce90039 100644
--- a/core/tests/coretests/src/android/view/Disabled.java
+++ b/core/tests/coretests/src/android/view/Disabled.java
@@ -16,13 +16,12 @@
package android.view;
-import com.android.frameworks.coretests.R;
-
-import android.os.Bundle;
-import android.widget.Button;
-import android.view.View;
-import android.view.View.OnClickListener;
import android.app.Activity;
+import android.os.Bundle;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+
+import com.android.frameworks.coretests.R;
/**
* Exercise View's disabled state.
diff --git a/core/tests/coretests/src/android/view/DisabledLongpressTest.java b/core/tests/coretests/src/android/view/DisabledLongpressTest.java
index faa0865..a9fec01 100644
--- a/core/tests/coretests/src/android/view/DisabledLongpressTest.java
+++ b/core/tests/coretests/src/android/view/DisabledLongpressTest.java
@@ -18,11 +18,12 @@
import android.test.ActivityInstrumentationTestCase;
import android.test.TouchUtils;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
import android.util.KeyUtils;
import android.view.View.OnLongClickListener;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
import com.android.frameworks.coretests.R;
/**
diff --git a/core/tests/coretests/src/android/view/DisabledTest.java b/core/tests/coretests/src/android/view/DisabledTest.java
index 291a11c..8922e5f 100644
--- a/core/tests/coretests/src/android/view/DisabledTest.java
+++ b/core/tests/coretests/src/android/view/DisabledTest.java
@@ -18,12 +18,11 @@
import android.test.ActivityInstrumentationTestCase;
import android.test.TouchUtils;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.view.KeyEvent;
-import android.view.View;
import android.widget.Button;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
import com.android.frameworks.coretests.R;
/**
diff --git a/core/tests/coretests/src/android/view/DisplayCutoutTest.java b/core/tests/coretests/src/android/view/DisplayCutoutTest.java
index 8e4f2cd..dd50af877 100644
--- a/core/tests/coretests/src/android/view/DisplayCutoutTest.java
+++ b/core/tests/coretests/src/android/view/DisplayCutoutTest.java
@@ -33,17 +33,17 @@
import android.graphics.Rect;
import android.os.Parcel;
import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.view.DisplayCutout.ParcelableWrapper;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.Arrays;
import java.util.Collections;
-
@RunWith(AndroidJUnit4.class)
@SmallTest
@Presubmit
diff --git a/core/tests/coretests/src/android/view/DrawableBgMinSize.java b/core/tests/coretests/src/android/view/DrawableBgMinSize.java
index 58bfb8a..ba9ba00 100644
--- a/core/tests/coretests/src/android/view/DrawableBgMinSize.java
+++ b/core/tests/coretests/src/android/view/DrawableBgMinSize.java
@@ -16,12 +16,9 @@
package android.view;
-import com.android.frameworks.coretests.R;
-
import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
-import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AbsoluteLayout;
import android.widget.Button;
@@ -30,6 +27,8 @@
import android.widget.RelativeLayout;
import android.widget.TextView;
+import com.android.frameworks.coretests.R;
+
/**
* Views should obey their background {@link Drawable}'s minimum size
* requirements ({@link Drawable#getMinimumHeight()} and
diff --git a/core/tests/coretests/src/android/view/DrawableBgMinSizeTest.java b/core/tests/coretests/src/android/view/DrawableBgMinSizeTest.java
index e705c87..1735e8c 100644
--- a/core/tests/coretests/src/android/view/DrawableBgMinSizeTest.java
+++ b/core/tests/coretests/src/android/view/DrawableBgMinSizeTest.java
@@ -16,14 +16,9 @@
package android.view;
-import com.android.frameworks.coretests.R;
-import android.view.DrawableBgMinSize;
-import android.test.TouchUtils;
-import android.test.suitebuilder.annotation.MediumTest;
-
import android.graphics.drawable.Drawable;
import android.test.ActivityInstrumentationTestCase;
-import android.view.View;
+import android.test.TouchUtils;
import android.widget.AbsoluteLayout;
import android.widget.Button;
import android.widget.FrameLayout;
@@ -31,6 +26,10 @@
import android.widget.RelativeLayout;
import android.widget.TextView;
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
+
/**
* {@link DrawableBgMinSize} exercises Views to obey their background drawable's
* minimum sizes.
diff --git a/core/tests/coretests/src/android/view/FocusFinderTest.java b/core/tests/coretests/src/android/view/FocusFinderTest.java
index 2732a04..b35c64a 100644
--- a/core/tests/coretests/src/android/view/FocusFinderTest.java
+++ b/core/tests/coretests/src/android/view/FocusFinderTest.java
@@ -18,7 +18,8 @@
import android.graphics.Rect;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
public class FocusFinderTest extends AndroidTestCase {
diff --git a/core/tests/coretests/src/android/view/GlobalFocusChange.java b/core/tests/coretests/src/android/view/GlobalFocusChange.java
index 041c0de..ee92b64 100644
--- a/core/tests/coretests/src/android/view/GlobalFocusChange.java
+++ b/core/tests/coretests/src/android/view/GlobalFocusChange.java
@@ -16,12 +16,10 @@
package android.view;
-import com.android.frameworks.coretests.R;
-
import android.app.Activity;
import android.os.Bundle;
-import android.view.ViewTreeObserver;
-import android.view.View;
+
+import com.android.frameworks.coretests.R;
public class GlobalFocusChange extends Activity implements ViewTreeObserver.OnGlobalFocusChangeListener {
public View mOldFocus;
diff --git a/core/tests/coretests/src/android/view/GlobalFocusChangeTest.java b/core/tests/coretests/src/android/view/GlobalFocusChangeTest.java
index dab7b90..960654a 100644
--- a/core/tests/coretests/src/android/view/GlobalFocusChangeTest.java
+++ b/core/tests/coretests/src/android/view/GlobalFocusChangeTest.java
@@ -17,13 +17,13 @@
package android.view;
import android.test.ActivityInstrumentationTestCase;
-import android.test.FlakyTest;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
import android.test.TouchUtils;
-import android.test.suitebuilder.annotation.Suppress;
-import android.view.View;
-import android.view.KeyEvent;
+
+import androidx.test.filters.FlakyTest;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
import com.android.frameworks.coretests.R;
@Suppress // Flaky
@@ -50,7 +50,7 @@
super.tearDown();
}
- @FlakyTest(tolerance = 4)
+ @FlakyTest
@LargeTest
public void testFocusChange() throws Exception {
sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
@@ -62,7 +62,7 @@
assertSame(mRight, mActivity.mNewFocus);
}
- @FlakyTest(tolerance = 4)
+ @FlakyTest
@MediumTest
public void testEnterTouchMode() throws Exception {
assertTrue(mLeft.isFocused());
@@ -73,7 +73,7 @@
assertSame(null, mActivity.mNewFocus);
}
- @FlakyTest(tolerance = 4)
+ @FlakyTest
@MediumTest
public void testLeaveTouchMode() throws Exception {
assertTrue(mLeft.isFocused());
diff --git a/core/tests/coretests/src/android/view/HandlerActionQueueTest.java b/core/tests/coretests/src/android/view/HandlerActionQueueTest.java
index fd8f23a..bedb75b 100644
--- a/core/tests/coretests/src/android/view/HandlerActionQueueTest.java
+++ b/core/tests/coretests/src/android/view/HandlerActionQueueTest.java
@@ -17,7 +17,8 @@
package android.view;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
public class HandlerActionQueueTest extends AndroidTestCase {
diff --git a/core/tests/coretests/src/android/view/Include.java b/core/tests/coretests/src/android/view/Include.java
index e90c484..4b6aefb 100644
--- a/core/tests/coretests/src/android/view/Include.java
+++ b/core/tests/coretests/src/android/view/Include.java
@@ -16,10 +16,10 @@
package android.view;
-import com.android.frameworks.coretests.R;
-
-import android.os.Bundle;
import android.app.Activity;
+import android.os.Bundle;
+
+import com.android.frameworks.coretests.R;
/**
* Exercise <include /> tag in XML files.
diff --git a/core/tests/coretests/src/android/view/IncludeTest.java b/core/tests/coretests/src/android/view/IncludeTest.java
index cdcfa3c..e490559 100644
--- a/core/tests/coretests/src/android/view/IncludeTest.java
+++ b/core/tests/coretests/src/android/view/IncludeTest.java
@@ -16,13 +16,11 @@
package android.view;
-import android.view.Include;
-import com.android.frameworks.coretests.R;
-
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.view.View;
-import android.view.ViewGroup;
+
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
public class IncludeTest extends ActivityInstrumentationTestCase<Include> {
public IncludeTest() {
diff --git a/core/tests/coretests/src/android/view/InflateTest.java b/core/tests/coretests/src/android/view/InflateTest.java
index cb4f8e2..939d6ea 100644
--- a/core/tests/coretests/src/android/view/InflateTest.java
+++ b/core/tests/coretests/src/android/view/InflateTest.java
@@ -20,13 +20,11 @@
import android.content.res.Resources;
import android.test.AndroidTestCase;
import android.test.PerformanceTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.view.View;
-import com.android.frameworks.coretests.R;
-import java.util.Map;
+import androidx.test.filters.SmallTest;
+
+import com.android.frameworks.coretests.R;
public class InflateTest extends AndroidTestCase implements PerformanceTestCase {
private LayoutInflater mInflater;
diff --git a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
index 81ca910..7f00ad9 100644
--- a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
+++ b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
@@ -18,7 +18,9 @@
import static android.view.InsetsState.TYPE_NAVIGATION_BAR;
import static android.view.InsetsState.TYPE_TOP_BAR;
+
import static junit.framework.Assert.assertEquals;
+
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -27,12 +29,13 @@
import android.graphics.Rect;
import android.graphics.RectF;
import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.FlakyTest;
-import android.support.test.runner.AndroidJUnit4;
import android.util.SparseArray;
import android.view.SurfaceControl.Transaction;
import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
+import androidx.test.filters.FlakyTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index d3d274a..d447451 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -17,18 +17,20 @@
package android.view;
import static android.view.InsetsState.TYPE_TOP_BAR;
+
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNull;
+
import static org.mockito.Mockito.mock;
import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.FlakyTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.FlakyTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.Mockito;
@Presubmit
@FlakyTest(detail = "Promote once confirmed non-flaky")
diff --git a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
index 6d0f984..82cd213 100644
--- a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
@@ -17,6 +17,7 @@
package android.view;
import static android.view.InsetsState.TYPE_TOP_BAR;
+
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.reset;
@@ -24,10 +25,11 @@
import static org.mockito.Mockito.verifyZeroInteractions;
import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.FlakyTest;
-import android.support.test.runner.AndroidJUnit4;
import android.view.SurfaceControl.Transaction;
+import androidx.test.filters.FlakyTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/view/InsetsSourceTest.java b/core/tests/coretests/src/android/view/InsetsSourceTest.java
index ed472d2..98ab3e7 100644
--- a/core/tests/coretests/src/android/view/InsetsSourceTest.java
+++ b/core/tests/coretests/src/android/view/InsetsSourceTest.java
@@ -17,13 +17,15 @@
package android.view;
import static android.view.InsetsState.TYPE_NAVIGATION_BAR;
+
import static junit.framework.Assert.assertEquals;
import android.graphics.Insets;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.FlakyTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.FlakyTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java
index 95af525..9857b7a 100644
--- a/core/tests/coretests/src/android/view/InsetsStateTest.java
+++ b/core/tests/coretests/src/android/view/InsetsStateTest.java
@@ -24,20 +24,23 @@
import static android.view.InsetsState.TYPE_SIDE_BAR_2;
import static android.view.InsetsState.TYPE_SIDE_BAR_3;
import static android.view.InsetsState.TYPE_TOP_BAR;
+
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
+
import static org.junit.Assert.assertNotEquals;
import android.graphics.Insets;
import android.graphics.Rect;
import android.os.Parcel;
import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.FlakyTest;
-import android.support.test.runner.AndroidJUnit4;
import android.util.SparseIntArray;
import android.view.WindowInsets.Type;
+import androidx.test.filters.FlakyTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/view/KeyEventTest.java b/core/tests/coretests/src/android/view/KeyEventTest.java
index b9d95e5..88d3bdb 100644
--- a/core/tests/coretests/src/android/view/KeyEventTest.java
+++ b/core/tests/coretests/src/android/view/KeyEventTest.java
@@ -20,8 +20,8 @@
import static org.junit.Assert.assertEquals;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/view/ListContextMenu.java b/core/tests/coretests/src/android/view/ListContextMenu.java
index 1b4ece6..e333b96 100644
--- a/core/tests/coretests/src/android/view/ListContextMenu.java
+++ b/core/tests/coretests/src/android/view/ListContextMenu.java
@@ -16,24 +16,17 @@
package android.view;
-import com.android.frameworks.coretests.R;
-
import android.app.ListActivity;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
-import android.view.ContextMenu;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.SubMenu;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.LayoutInflater;
import android.view.ContextMenu.ContextMenuInfo;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.TextView;
+import com.android.frameworks.coretests.R;
+
/**
* Exercises context menus in lists
*/
diff --git a/core/tests/coretests/src/android/view/Longpress.java b/core/tests/coretests/src/android/view/Longpress.java
index e8e6f13..86fa9e5 100644
--- a/core/tests/coretests/src/android/view/Longpress.java
+++ b/core/tests/coretests/src/android/view/Longpress.java
@@ -16,11 +16,11 @@
package android.view;
-import com.android.frameworks.coretests.R;
-
import android.app.Activity;
import android.os.Bundle;
+import com.android.frameworks.coretests.R;
+
public class Longpress extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
diff --git a/core/tests/coretests/src/android/view/LongpressTest.java b/core/tests/coretests/src/android/view/LongpressTest.java
index d3d7589..4dfecd0 100644
--- a/core/tests/coretests/src/android/view/LongpressTest.java
+++ b/core/tests/coretests/src/android/view/LongpressTest.java
@@ -18,11 +18,12 @@
import android.test.ActivityInstrumentationTestCase;
import android.test.TouchUtils;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
import android.util.KeyUtils;
import android.view.View.OnLongClickListener;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
import com.android.frameworks.coretests.R;
/**
diff --git a/core/tests/coretests/src/android/view/MenuTest.java b/core/tests/coretests/src/android/view/MenuTest.java
index 116b38a..794769cc 100644
--- a/core/tests/coretests/src/android/view/MenuTest.java
+++ b/core/tests/coretests/src/android/view/MenuTest.java
@@ -17,7 +17,8 @@
package android.view;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
import com.android.frameworks.coretests.R;
import com.android.internal.view.menu.MenuBuilder;
diff --git a/core/tests/coretests/src/android/view/Merge.java b/core/tests/coretests/src/android/view/Merge.java
index bdacd81..8020e4b 100644
--- a/core/tests/coretests/src/android/view/Merge.java
+++ b/core/tests/coretests/src/android/view/Merge.java
@@ -16,13 +16,11 @@
package android.view;
-import com.android.frameworks.coretests.R;
-
-import android.os.Bundle;
import android.app.Activity;
+import android.os.Bundle;
import android.widget.LinearLayout;
-import android.view.ViewGroup;
-import android.view.LayoutInflater;
+
+import com.android.frameworks.coretests.R;
/**
* Exercise <merge /> tag in XML files.
diff --git a/core/tests/coretests/src/android/view/MergeTest.java b/core/tests/coretests/src/android/view/MergeTest.java
index acfee7e..eccc9cb 100644
--- a/core/tests/coretests/src/android/view/MergeTest.java
+++ b/core/tests/coretests/src/android/view/MergeTest.java
@@ -16,11 +16,9 @@
package android.view;
-import android.view.Merge;
-
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.view.ViewGroup;
+
+import androidx.test.filters.MediumTest;
public class MergeTest extends ActivityInstrumentationTestCase<Merge> {
public MergeTest() {
diff --git a/core/tests/coretests/src/android/view/MotionEventTest.java b/core/tests/coretests/src/android/view/MotionEventTest.java
index 023526f..cadf37e 100644
--- a/core/tests/coretests/src/android/view/MotionEventTest.java
+++ b/core/tests/coretests/src/android/view/MotionEventTest.java
@@ -22,11 +22,12 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.view.MotionEvent.PointerCoords;
import android.view.MotionEvent.PointerProperties;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/view/MutateDrawable.java b/core/tests/coretests/src/android/view/MutateDrawable.java
index 39b5789..1ec525d 100644
--- a/core/tests/coretests/src/android/view/MutateDrawable.java
+++ b/core/tests/coretests/src/android/view/MutateDrawable.java
@@ -18,8 +18,9 @@
import android.app.Activity;
import android.os.Bundle;
-import android.widget.LinearLayout;
import android.widget.Button;
+import android.widget.LinearLayout;
+
import com.android.frameworks.coretests.R;
public class MutateDrawable extends Activity {
diff --git a/core/tests/coretests/src/android/view/MutateDrawableTest.java b/core/tests/coretests/src/android/view/MutateDrawableTest.java
index 74e011d..d63ffb1 100644
--- a/core/tests/coretests/src/android/view/MutateDrawableTest.java
+++ b/core/tests/coretests/src/android/view/MutateDrawableTest.java
@@ -17,9 +17,8 @@
package android.view;
import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.view.View;
-import android.view.MutateDrawable;
+
+import androidx.test.filters.MediumTest;
public class MutateDrawableTest extends ActivityInstrumentationTestCase2<MutateDrawable> {
private View mFirstButton;
diff --git a/core/tests/coretests/src/android/view/PinchZoomAction.java b/core/tests/coretests/src/android/view/PinchZoomAction.java
index 97fe980..bec9b55 100644
--- a/core/tests/coretests/src/android/view/PinchZoomAction.java
+++ b/core/tests/coretests/src/android/view/PinchZoomAction.java
@@ -30,8 +30,6 @@
import android.support.test.espresso.ViewAction;
import android.support.test.espresso.action.Swiper;
import android.support.test.espresso.util.HumanReadables;
-import android.view.MotionEvent;
-import android.view.View;
import org.hamcrest.Matcher;
diff --git a/core/tests/coretests/src/android/view/PopupWindowVisibility.java b/core/tests/coretests/src/android/view/PopupWindowVisibility.java
index 85ce04f..e6430d3 100644
--- a/core/tests/coretests/src/android/view/PopupWindowVisibility.java
+++ b/core/tests/coretests/src/android/view/PopupWindowVisibility.java
@@ -18,7 +18,6 @@
import android.app.Activity;
import android.os.Bundle;
-import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
diff --git a/core/tests/coretests/src/android/view/PreDrawListener.java b/core/tests/coretests/src/android/view/PreDrawListener.java
index 60bbee4..77bd36c 100644
--- a/core/tests/coretests/src/android/view/PreDrawListener.java
+++ b/core/tests/coretests/src/android/view/PreDrawListener.java
@@ -20,15 +20,12 @@
import android.content.Context;
import android.os.Bundle;
import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewTreeObserver;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import com.android.frameworks.coretests.R;
-
/**
* Tests views with popupWindows becoming invisible
*/
diff --git a/core/tests/coretests/src/android/view/RenderNodeAnimatorTest.java b/core/tests/coretests/src/android/view/RenderNodeAnimatorTest.java
index b52d98c..786c22b 100644
--- a/core/tests/coretests/src/android/view/RenderNodeAnimatorTest.java
+++ b/core/tests/coretests/src/android/view/RenderNodeAnimatorTest.java
@@ -21,10 +21,11 @@
import android.app.Activity;
import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.annotation.UiThreadTest;
-import android.support.test.filters.MediumTest;
-import android.support.test.rule.ActivityTestRule;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.rule.ActivityTestRule;
import org.junit.Rule;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/view/RunQueue.java b/core/tests/coretests/src/android/view/RunQueue.java
index 85dd32e..7544433 100644
--- a/core/tests/coretests/src/android/view/RunQueue.java
+++ b/core/tests/coretests/src/android/view/RunQueue.java
@@ -19,8 +19,7 @@
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
-import android.view.View;
-import android.view.ViewTreeObserver;
+
import com.android.frameworks.coretests.R;
/**
diff --git a/core/tests/coretests/src/android/view/RunQueueTest.java b/core/tests/coretests/src/android/view/RunQueueTest.java
index d69860b..f42f590 100644
--- a/core/tests/coretests/src/android/view/RunQueueTest.java
+++ b/core/tests/coretests/src/android/view/RunQueueTest.java
@@ -17,7 +17,8 @@
package android.view;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
+
+import androidx.test.filters.MediumTest;
public class RunQueueTest extends ActivityInstrumentationTestCase<RunQueue> {
public RunQueueTest() {
diff --git a/core/tests/coretests/src/android/view/ScaleGesture.java b/core/tests/coretests/src/android/view/ScaleGesture.java
index a954a4a..235b224 100644
--- a/core/tests/coretests/src/android/view/ScaleGesture.java
+++ b/core/tests/coretests/src/android/view/ScaleGesture.java
@@ -16,16 +16,11 @@
package android.view;
-import com.android.frameworks.coretests.R;
-
import android.app.Activity;
import android.os.Bundle;
-import android.util.Log;
-import android.util.TypedValue;
-import android.view.MotionEvent;
-import android.view.ScaleGestureDetector;
import android.view.ScaleGestureDetector.SimpleOnScaleGestureListener;
-import android.widget.TextView;
+
+import com.android.frameworks.coretests.R;
public class ScaleGesture extends Activity {
private ScaleGestureDetector mScaleGestureDetector;
diff --git a/core/tests/coretests/src/android/view/ScaleGestureDetectorTest.java b/core/tests/coretests/src/android/view/ScaleGestureDetectorTest.java
index fba8eae..1990135 100644
--- a/core/tests/coretests/src/android/view/ScaleGestureDetectorTest.java
+++ b/core/tests/coretests/src/android/view/ScaleGestureDetectorTest.java
@@ -16,26 +16,22 @@
package android.view;
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+
import android.content.Context;
-import android.support.test.filters.LargeTest;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
import android.test.ActivityInstrumentationTestCase2;
import android.util.DisplayMetrics;
-import android.view.PinchZoomAction;
-import android.view.ScaleGesture;
-import android.view.WindowManager;
import android.widget.TextView;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+
import com.android.frameworks.coretests.R;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-import static android.support.test.espresso.Espresso.onView;
@LargeTest
public class ScaleGestureDetectorTest extends ActivityInstrumentationTestCase2<ScaleGesture> {
diff --git a/core/tests/coretests/src/android/view/SetTagsTest.java b/core/tests/coretests/src/android/view/SetTagsTest.java
index 373dce6..1699713 100644
--- a/core/tests/coretests/src/android/view/SetTagsTest.java
+++ b/core/tests/coretests/src/android/view/SetTagsTest.java
@@ -16,12 +16,13 @@
package android.view;
-import com.android.frameworks.coretests.R;
-import android.test.suitebuilder.annotation.MediumTest;
-
import android.test.ActivityInstrumentationTestCase2;
import android.widget.Button;
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
+
/**
* Exercises {@link android.view.View}'s tags property.
*/
diff --git a/core/tests/coretests/src/android/view/StubbedView.java b/core/tests/coretests/src/android/view/StubbedView.java
index 612095c..c96b9b7 100644
--- a/core/tests/coretests/src/android/view/StubbedView.java
+++ b/core/tests/coretests/src/android/view/StubbedView.java
@@ -16,11 +16,10 @@
package android.view;
-import com.android.frameworks.coretests.R;
-
-import android.os.Bundle;
import android.app.Activity;
-import android.view.View;
+import android.os.Bundle;
+
+import com.android.frameworks.coretests.R;
/**
* Exercise <ViewStub /> tag in XML files.
diff --git a/core/tests/coretests/src/android/view/VelocityTest.java b/core/tests/coretests/src/android/view/VelocityTest.java
index 7f32208..c116f4d 100644
--- a/core/tests/coretests/src/android/view/VelocityTest.java
+++ b/core/tests/coretests/src/android/view/VelocityTest.java
@@ -16,16 +16,17 @@
package android.view;
-import android.test.suitebuilder.annotation.Suppress;
-import junit.framework.Assert;
-
import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
+import junit.framework.Assert;
+
/**
* Exercises {@link android.view.VelocityTracker} to compute correct velocity.<br>
* To launch this test, use :<br>
diff --git a/core/tests/coretests/src/android/view/ViewAttachTest.java b/core/tests/coretests/src/android/view/ViewAttachTest.java
index aa8f8d8..1a8dd99 100644
--- a/core/tests/coretests/src/android/view/ViewAttachTest.java
+++ b/core/tests/coretests/src/android/view/ViewAttachTest.java
@@ -16,16 +16,13 @@
package android.view;
-import android.content.Context;
import android.content.pm.ActivityInfo;
import android.graphics.PixelFormat;
import android.os.SystemClock;
-import android.support.test.filters.LargeTest;
import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
+
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.LargeTest;
import com.android.frameworks.coretests.R;
diff --git a/core/tests/coretests/src/android/view/ViewAttachTestActivity.java b/core/tests/coretests/src/android/view/ViewAttachTestActivity.java
index 59e25ae..bcbc813 100644
--- a/core/tests/coretests/src/android/view/ViewAttachTestActivity.java
+++ b/core/tests/coretests/src/android/view/ViewAttachTestActivity.java
@@ -16,11 +16,11 @@
package android.view;
-import com.android.frameworks.coretests.R;
-
import android.app.Activity;
import android.os.Bundle;
+import com.android.frameworks.coretests.R;
+
public class ViewAttachTestActivity extends Activity {
public static final String TAG = "OnAttachedTest";
@Override
diff --git a/core/tests/coretests/src/android/view/ViewAttachView.java b/core/tests/coretests/src/android/view/ViewAttachView.java
index 5af2d8f..2f3ff8f 100644
--- a/core/tests/coretests/src/android/view/ViewAttachView.java
+++ b/core/tests/coretests/src/android/view/ViewAttachView.java
@@ -22,7 +22,6 @@
import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.Log;
-import android.view.View;
/**
* A View that will throw a RuntimeException if onAttachedToWindow and
diff --git a/core/tests/coretests/src/android/view/ViewCaptureTest.java b/core/tests/coretests/src/android/view/ViewCaptureTest.java
index 4405934..218047c 100644
--- a/core/tests/coretests/src/android/view/ViewCaptureTest.java
+++ b/core/tests/coretests/src/android/view/ViewCaptureTest.java
@@ -21,14 +21,15 @@
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
-import android.support.test.filters.SmallTest;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
import android.util.SparseIntArray;
import android.view.ViewDebug.CanvasProvider;
import android.view.ViewDebug.HardwareCanvasProvider;
import android.view.ViewDebug.SoftwareCanvasProvider;
+import androidx.test.filters.SmallTest;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
import com.android.frameworks.coretests.R;
import org.junit.Assert;
diff --git a/core/tests/coretests/src/android/view/ViewCaptureTestActivity.java b/core/tests/coretests/src/android/view/ViewCaptureTestActivity.java
index 20e3eb5..2f51c24 100644
--- a/core/tests/coretests/src/android/view/ViewCaptureTestActivity.java
+++ b/core/tests/coretests/src/android/view/ViewCaptureTestActivity.java
@@ -19,6 +19,7 @@
import android.annotation.Nullable;
import android.app.Activity;
import android.os.Bundle;
+
import com.android.frameworks.coretests.R;
public class ViewCaptureTestActivity extends Activity {
diff --git a/core/tests/coretests/src/android/view/ViewGroupAttributesTest.java b/core/tests/coretests/src/android/view/ViewGroupAttributesTest.java
index b4ef0e7..c24cd35 100644
--- a/core/tests/coretests/src/android/view/ViewGroupAttributesTest.java
+++ b/core/tests/coretests/src/android/view/ViewGroupAttributesTest.java
@@ -18,7 +18,8 @@
import android.content.Context;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
public class ViewGroupAttributesTest extends AndroidTestCase {
diff --git a/core/tests/coretests/src/android/view/ViewGroupChildren.java b/core/tests/coretests/src/android/view/ViewGroupChildren.java
index f39720b..d5d9879 100644
--- a/core/tests/coretests/src/android/view/ViewGroupChildren.java
+++ b/core/tests/coretests/src/android/view/ViewGroupChildren.java
@@ -16,12 +16,10 @@
package android.view;
-import com.android.frameworks.coretests.R;
-
-import android.os.Bundle;
-import android.widget.Button;
-import android.view.View;
import android.app.Activity;
+import android.os.Bundle;
+
+import com.android.frameworks.coretests.R;
/**
* Exercise ViewGroup's ability to add and remove children.
diff --git a/core/tests/coretests/src/android/view/ViewGroupChildrenTest.java b/core/tests/coretests/src/android/view/ViewGroupChildrenTest.java
index d1665ef..07cb2a1 100644
--- a/core/tests/coretests/src/android/view/ViewGroupChildrenTest.java
+++ b/core/tests/coretests/src/android/view/ViewGroupChildrenTest.java
@@ -16,18 +16,16 @@
package android.view;
-import com.android.frameworks.coretests.R;
-import android.view.ViewGroupChildren;
-
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
import android.test.ViewAsserts;
-import android.test.UiThreadTest;
-import android.view.View;
-import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
+
/**
* Exercises {@link android.view.ViewGroup}'s ability to add/remove children.
*/
diff --git a/core/tests/coretests/src/android/view/ViewGroupTransientViewTest.java b/core/tests/coretests/src/android/view/ViewGroupTransientViewTest.java
index 93ad41f0..54524b2 100644
--- a/core/tests/coretests/src/android/view/ViewGroupTransientViewTest.java
+++ b/core/tests/coretests/src/android/view/ViewGroupTransientViewTest.java
@@ -22,12 +22,13 @@
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
-import android.support.test.annotation.UiThreadTest;
-import android.support.test.filters.MediumTest;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
import android.widget.FrameLayout;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/view/ViewInvalidateTest.java b/core/tests/coretests/src/android/view/ViewInvalidateTest.java
index 115504b..c25a2deb 100644
--- a/core/tests/coretests/src/android/view/ViewInvalidateTest.java
+++ b/core/tests/coretests/src/android/view/ViewInvalidateTest.java
@@ -21,24 +21,30 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.Activity;
import android.content.Context;
import android.graphics.Rect;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.annotation.UiThreadTest;
-import android.support.test.filters.LargeTest;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
+import android.view.ViewTreeObserver.OnDrawListener;
import android.widget.FrameLayout;
-import com.android.compatibility.common.util.WidgetTestUtils;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.LargeTest;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
+import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
/**
* Test of invalidates, drawing, and the flags that support them
*/
@@ -281,4 +287,42 @@
View.PFLAG_DRAWN);
assertTrue(getViewRoot(mParent).mIsAnimating);
}
+
+ /** Copied from cts/common/device-side/util. */
+ static class WidgetTestUtils {
+ public static void runOnMainAndDrawSync(@NonNull final ActivityTestRule activityTestRule,
+ @NonNull final View view, @Nullable final Runnable runner) throws Throwable {
+ final CountDownLatch latch = new CountDownLatch(1);
+
+ activityTestRule.runOnUiThread(() -> {
+ final OnDrawListener listener = new OnDrawListener() {
+ @Override
+ public void onDraw() {
+ // posting so that the sync happens after the draw that's about to happen
+ view.post(() -> {
+ activityTestRule.getActivity().getWindow().getDecorView()
+ .getViewTreeObserver().removeOnDrawListener(this);
+ latch.countDown();
+ });
+ }
+ };
+
+ activityTestRule.getActivity().getWindow().getDecorView()
+ .getViewTreeObserver().addOnDrawListener(listener);
+
+ if (runner != null) {
+ runner.run();
+ }
+ view.invalidate();
+ });
+
+ try {
+ Assert.assertTrue("Expected draw pass occurred within 5 seconds",
+ latch.await(5, TimeUnit.SECONDS));
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ }
}
diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java
index ca6d6cfe..9a57847 100644
--- a/core/tests/coretests/src/android/view/ViewRootImplTest.java
+++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java
@@ -23,9 +23,10 @@
import android.graphics.Insets;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/view/ViewStubTest.java b/core/tests/coretests/src/android/view/ViewStubTest.java
index ebd52a6..504a4ec 100644
--- a/core/tests/coretests/src/android/view/ViewStubTest.java
+++ b/core/tests/coretests/src/android/view/ViewStubTest.java
@@ -16,14 +16,12 @@
package android.view;
-import android.view.StubbedView;
-import com.android.frameworks.coretests.R;
-
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.UiThreadTest;
-import android.view.View;
-import android.view.ViewStub;
+
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
public class ViewStubTest extends ActivityInstrumentationTestCase<StubbedView> {
public ViewStubTest() {
diff --git a/core/tests/coretests/src/android/view/ViewTransientStateTest.java b/core/tests/coretests/src/android/view/ViewTransientStateTest.java
index 36ea01d..3f73b07 100644
--- a/core/tests/coretests/src/android/view/ViewTransientStateTest.java
+++ b/core/tests/coretests/src/android/view/ViewTransientStateTest.java
@@ -18,13 +18,12 @@
import android.app.Activity;
import android.test.ActivityInstrumentationTestCase;
-import android.test.UiThreadTest;
-import android.test.suitebuilder.annotation.MediumTest;
+
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.MediumTest;
import com.android.frameworks.coretests.R;
-import static org.junit.Assert.assertFalse;
-
/**
* Exercise set View's transient state
*/
diff --git a/core/tests/coretests/src/android/view/Visibility.java b/core/tests/coretests/src/android/view/Visibility.java
index 031568c..8e3de4e 100644
--- a/core/tests/coretests/src/android/view/Visibility.java
+++ b/core/tests/coretests/src/android/view/Visibility.java
@@ -16,12 +16,11 @@
package android.view;
-import com.android.frameworks.coretests.R;
-
+import android.app.Activity;
import android.os.Bundle;
import android.widget.Button;
-import android.view.View;
-import android.app.Activity;
+
+import com.android.frameworks.coretests.R;
/**
* Exercise View's ability to change their visibility: GONE, INVISIBLE and
diff --git a/core/tests/coretests/src/android/view/VisibilityCallback.java b/core/tests/coretests/src/android/view/VisibilityCallback.java
index f98a0a8..c965973 100644
--- a/core/tests/coretests/src/android/view/VisibilityCallback.java
+++ b/core/tests/coretests/src/android/view/VisibilityCallback.java
@@ -16,16 +16,15 @@
package android.view;
+import android.app.Activity;
import android.content.Context;
+import android.os.Bundle;
import android.util.AttributeSet;
import android.util.Log;
-import android.widget.TextView;
-import com.android.frameworks.coretests.R;
-
-import android.os.Bundle;
import android.widget.Button;
-import android.view.View;
-import android.app.Activity;
+import android.widget.TextView;
+
+import com.android.frameworks.coretests.R;
/**
* Exercise View's ability to change their visibility: GONE, INVISIBLE and
diff --git a/core/tests/coretests/src/android/view/VisibilityCallbackTest.java b/core/tests/coretests/src/android/view/VisibilityCallbackTest.java
index ec956d2..d7c7b4c 100644
--- a/core/tests/coretests/src/android/view/VisibilityCallbackTest.java
+++ b/core/tests/coretests/src/android/view/VisibilityCallbackTest.java
@@ -17,12 +17,12 @@
package android.view;
import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.view.View;
-import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
+
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.MediumTest;
+
import com.android.frameworks.coretests.R;
/**
diff --git a/core/tests/coretests/src/android/view/VisibilityTest.java b/core/tests/coretests/src/android/view/VisibilityTest.java
index 29c1c8a..83a7702 100644
--- a/core/tests/coretests/src/android/view/VisibilityTest.java
+++ b/core/tests/coretests/src/android/view/VisibilityTest.java
@@ -20,11 +20,12 @@
import static android.view.KeyEvent.KEYCODE_DPAD_LEFT;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
import android.widget.Button;
import android.widget.TextView;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
import com.android.frameworks.coretests.R;
/**
diff --git a/core/tests/coretests/src/android/view/WindowInsetsTest.java b/core/tests/coretests/src/android/view/WindowInsetsTest.java
index 1513a1a..15a96a1 100644
--- a/core/tests/coretests/src/android/view/WindowInsetsTest.java
+++ b/core/tests/coretests/src/android/view/WindowInsetsTest.java
@@ -17,18 +17,18 @@
package android.view;
import static android.view.WindowInsets.Type.ime;
-import static android.view.WindowInsets.Type.indexOf;
import static android.view.WindowInsets.Type.sideBars;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import android.graphics.Insets;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.view.WindowInsets.Builder;
-import android.view.WindowInsets.Type;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/view/ZeroSized.java b/core/tests/coretests/src/android/view/ZeroSized.java
index f2a6b3e..9e2dfcb 100644
--- a/core/tests/coretests/src/android/view/ZeroSized.java
+++ b/core/tests/coretests/src/android/view/ZeroSized.java
@@ -16,10 +16,10 @@
package android.view;
-import com.android.frameworks.coretests.R;
-
-import android.os.Bundle;
import android.app.Activity;
+import android.os.Bundle;
+
+import com.android.frameworks.coretests.R;
/**
* This activity contains Views with various widths and heights. The goal is to exercise the
diff --git a/core/tests/coretests/src/android/view/ZeroSizedTest.java b/core/tests/coretests/src/android/view/ZeroSizedTest.java
index 193fc98..946bf68 100644
--- a/core/tests/coretests/src/android/view/ZeroSizedTest.java
+++ b/core/tests/coretests/src/android/view/ZeroSizedTest.java
@@ -16,13 +16,12 @@
package android.view;
-import android.view.ZeroSized;
-import com.android.frameworks.coretests.R;
-
-import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.view.View;
import android.graphics.Bitmap;
+import android.test.ActivityInstrumentationTestCase;
+
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
/**
* Builds the drawing cache of Views of various dimension. The assumption is that
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java
index 7f675ff..a88968b 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java
@@ -28,10 +28,11 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
import android.view.View;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java
index 3e03414..46c96c9 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java
@@ -21,7 +21,8 @@
import static junit.framework.Assert.assertTrue;
import android.os.Parcel;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java
index 318d122..ab24f89 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java
@@ -22,10 +22,12 @@
import android.os.Bundle;
import android.os.RemoteException;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
import libcore.util.EmptyArray;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
index 506e544..0ed690c 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
@@ -25,11 +25,12 @@
import static org.junit.Assert.fail;
import android.os.Parcel;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
import android.util.ArraySet;
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
import com.android.internal.util.CollectionUtils;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/view/accessibility/RecycleAccessibilityEventTest.java b/core/tests/coretests/src/android/view/accessibility/RecycleAccessibilityEventTest.java
index 4814c61..11f4e3c 100644
--- a/core/tests/coretests/src/android/view/accessibility/RecycleAccessibilityEventTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/RecycleAccessibilityEventTest.java
@@ -14,7 +14,7 @@
package android.view.accessibility;
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.SmallTest;
import junit.framework.TestCase;
diff --git a/core/tests/coretests/src/android/view/autofill/AutofillIdTest.java b/core/tests/coretests/src/android/view/autofill/AutofillIdTest.java
index 7619af2..33bc593 100644
--- a/core/tests/coretests/src/android/view/autofill/AutofillIdTest.java
+++ b/core/tests/coretests/src/android/view/autofill/AutofillIdTest.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.view.autofill;
import static com.google.common.truth.Truth.assertThat;
diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
index 73cceae..a2f0eba 100644
--- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
+++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.view.contentcapture;
import static com.google.common.truth.Truth.assertThat;
diff --git a/core/tests/coretests/src/android/view/contentcapture/ViewNodeTest.java b/core/tests/coretests/src/android/view/contentcapture/ViewNodeTest.java
index bbfe01c..099f41d 100644
--- a/core/tests/coretests/src/android/view/contentcapture/ViewNodeTest.java
+++ b/core/tests/coretests/src/android/view/contentcapture/ViewNodeTest.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.view.contentcapture;
import static com.google.common.truth.Truth.assertThat;
@@ -24,7 +25,6 @@
import android.os.Bundle;
import android.os.LocaleList;
import android.os.Parcel;
-import android.support.test.InstrumentationRegistry;
import android.view.View;
import android.view.ViewStructure.HtmlInfo;
import android.view.autofill.AutofillId;
@@ -32,6 +32,8 @@
import android.view.contentcapture.ViewNode.ViewStructureImpl;
import android.widget.FrameLayout;
+import androidx.test.InstrumentationRegistry;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
diff --git a/core/tests/coretests/src/android/view/inputmethod/CursorAnchorInfoTest.java b/core/tests/coretests/src/android/view/inputmethod/CursorAnchorInfoTest.java
index 0fd0136..ace6611 100644
--- a/core/tests/coretests/src/android/view/inputmethod/CursorAnchorInfoTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/CursorAnchorInfoTest.java
@@ -28,11 +28,12 @@
import android.graphics.Matrix;
import android.graphics.RectF;
import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.text.TextUtils;
import android.view.inputmethod.CursorAnchorInfo.Builder;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java b/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java
index 1b00e09..f24e232 100644
--- a/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java
@@ -26,9 +26,10 @@
import android.content.pm.ServiceInfo;
import android.os.Bundle;
import android.os.Parcel;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import com.android.frameworks.coretests.R;
diff --git a/core/tests/coretests/src/android/view/inputmethod/InputMethodManagerTest.java b/core/tests/coretests/src/android/view/inputmethod/InputMethodManagerTest.java
index 55e5e36..9f259a8 100644
--- a/core/tests/coretests/src/android/view/inputmethod/InputMethodManagerTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/InputMethodManagerTest.java
@@ -20,11 +20,12 @@
import static org.junit.Assert.assertNotNull;
import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.view.WindowManager;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeArrayTest.java b/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeArrayTest.java
index 8df1848..e2fb46a 100644
--- a/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeArrayTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeArrayTest.java
@@ -19,10 +19,11 @@
import static org.junit.Assert.assertEquals;
import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeTest.java b/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeTest.java
index c76359e..1e0e1235 100644
--- a/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeTest.java
@@ -23,10 +23,11 @@
import static org.junit.Assert.assertTrue;
import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/view/inputmethod/SparseRectFArrayTest.java b/core/tests/coretests/src/android/view/inputmethod/SparseRectFArrayTest.java
index 8c96b58..453ad72 100644
--- a/core/tests/coretests/src/android/view/inputmethod/SparseRectFArrayTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/SparseRectFArrayTest.java
@@ -23,10 +23,11 @@
import android.graphics.RectF;
import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.view.inputmethod.SparseRectFArray.SparseRectFArrayBuilder;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/view/menu/ContextMenuTest.java b/core/tests/coretests/src/android/view/menu/ContextMenuTest.java
index 657a7fc..ba85d76 100644
--- a/core/tests/coretests/src/android/view/menu/ContextMenuTest.java
+++ b/core/tests/coretests/src/android/view/menu/ContextMenuTest.java
@@ -18,7 +18,6 @@
import android.content.Context;
import android.graphics.Point;
-import android.support.test.filters.MediumTest;
import android.test.ActivityInstrumentationTestCase;
import android.util.PollingCheck;
import android.view.Display;
@@ -26,6 +25,8 @@
import android.view.WindowManager;
import android.widget.espresso.ContextMenuUtils;
+import androidx.test.filters.MediumTest;
+
@MediumTest
public class ContextMenuTest extends ActivityInstrumentationTestCase<ContextMenuActivity> {
diff --git a/core/tests/coretests/src/android/view/menu/MenuLayout.java b/core/tests/coretests/src/android/view/menu/MenuLayout.java
index 356c948..33ee515 100644
--- a/core/tests/coretests/src/android/view/menu/MenuLayout.java
+++ b/core/tests/coretests/src/android/view/menu/MenuLayout.java
@@ -16,8 +16,6 @@
package android.view.menu;
-import android.view.menu.MenuScenario.Params;
-
import android.os.Bundle;
import android.view.Menu;
import android.widget.Button;
diff --git a/core/tests/coretests/src/android/view/menu/MenuLayoutLandscapeTest.java b/core/tests/coretests/src/android/view/menu/MenuLayoutLandscapeTest.java
index 8ed0d86..ff9f166 100644
--- a/core/tests/coretests/src/android/view/menu/MenuLayoutLandscapeTest.java
+++ b/core/tests/coretests/src/android/view/menu/MenuLayoutLandscapeTest.java
@@ -16,13 +16,10 @@
package android.view.menu;
-import android.util.KeyUtils;
-import com.android.internal.view.menu.IconMenuView;
-import com.android.internal.view.menu.MenuBuilder;
-
-import android.content.pm.ActivityInfo;
-import android.support.test.filters.LargeTest;
import android.test.ActivityInstrumentationTestCase;
+import android.util.KeyUtils;
+
+import androidx.test.filters.LargeTest;
@LargeTest
public class MenuLayoutLandscapeTest extends ActivityInstrumentationTestCase<MenuLayoutLandscape> {
diff --git a/core/tests/coretests/src/android/view/menu/MenuLayoutPortraitTest.java b/core/tests/coretests/src/android/view/menu/MenuLayoutPortraitTest.java
index ccf1264..360be53 100644
--- a/core/tests/coretests/src/android/view/menu/MenuLayoutPortraitTest.java
+++ b/core/tests/coretests/src/android/view/menu/MenuLayoutPortraitTest.java
@@ -16,11 +16,11 @@
package android.view.menu;
-import android.content.pm.ActivityInfo;
-import android.support.test.filters.LargeTest;
import android.test.ActivityInstrumentationTestCase;
import android.util.KeyUtils;
+import androidx.test.filters.LargeTest;
+
@LargeTest
public class MenuLayoutPortraitTest extends ActivityInstrumentationTestCase<MenuLayoutPortrait> {
private static final String LONG_TITLE = "Really really really really really really really really really really long title";
diff --git a/core/tests/coretests/src/android/view/menu/MenuWith1ItemTest.java b/core/tests/coretests/src/android/view/menu/MenuWith1ItemTest.java
index 82ad858..c18e361 100644
--- a/core/tests/coretests/src/android/view/menu/MenuWith1ItemTest.java
+++ b/core/tests/coretests/src/android/view/menu/MenuWith1ItemTest.java
@@ -16,17 +16,12 @@
package android.view.menu;
-import android.view.menu.MenuWith1Item;
-import android.util.KeyUtils;
-import com.android.internal.view.menu.MenuBuilder;
-
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.TouchUtils;
-
import android.test.ActivityInstrumentationTestCase;
+import android.util.KeyUtils;
import android.view.KeyEvent;
-import android.view.View;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
public class MenuWith1ItemTest extends ActivityInstrumentationTestCase<MenuWith1Item> {
private MenuWith1Item mActivity;
diff --git a/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java b/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java
index 4a6c093..780e15a 100644
--- a/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java
@@ -22,8 +22,9 @@
import static com.google.common.truth.Truth.assertThat;
import android.app.Person;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import com.google.android.textclassifier.ActionsSuggestionsModel;
diff --git a/core/tests/coretests/src/android/view/textclassifier/FakeContextBuilder.java b/core/tests/coretests/src/android/view/textclassifier/FakeContextBuilder.java
index 0180856..fef6583 100644
--- a/core/tests/coretests/src/android/view/textclassifier/FakeContextBuilder.java
+++ b/core/tests/coretests/src/android/view/textclassifier/FakeContextBuilder.java
@@ -21,6 +21,7 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
import android.content.ContextWrapper;
@@ -29,9 +30,8 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.support.test.InstrumentationRegistry;
-import androidx.annotation.Nullable;
+import androidx.test.InstrumentationRegistry;
import com.google.common.base.Preconditions;
diff --git a/core/tests/coretests/src/android/view/textclassifier/IntentFactoryTest.java b/core/tests/coretests/src/android/view/textclassifier/IntentFactoryTest.java
index aaadefb..3fc8e4c 100644
--- a/core/tests/coretests/src/android/view/textclassifier/IntentFactoryTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/IntentFactoryTest.java
@@ -13,14 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.view.textclassifier;
import static com.google.common.truth.Truth.assertThat;
import android.content.Intent;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import com.google.android.textclassifier.AnnotatorModel;
diff --git a/core/tests/coretests/src/android/view/textclassifier/ModelFileManagerTest.java b/core/tests/coretests/src/android/view/textclassifier/ModelFileManagerTest.java
index 88d162b..74b8e3b 100644
--- a/core/tests/coretests/src/android/view/textclassifier/ModelFileManagerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/ModelFileManagerTest.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.view.textclassifier;
import static com.google.common.truth.Truth.assertThat;
@@ -20,9 +21,10 @@
import static org.mockito.Mockito.when;
import android.os.LocaleList;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Before;
diff --git a/core/tests/coretests/src/android/view/textclassifier/SelectionEventTest.java b/core/tests/coretests/src/android/view/textclassifier/SelectionEventTest.java
index a3c6179..46e3a4c 100644
--- a/core/tests/coretests/src/android/view/textclassifier/SelectionEventTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/SelectionEventTest.java
@@ -19,8 +19,9 @@
import static org.junit.Assert.assertEquals;
import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java
index 54007fb..9662182 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java
@@ -20,8 +20,8 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
index a3f69d9..4fcd51c 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
@@ -26,9 +26,10 @@
import android.content.Intent;
import android.os.LocaleList;
import android.service.textclassifier.TextClassifierService;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
index aaf7312..99c959e 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
@@ -32,11 +32,12 @@
import android.os.Bundle;
import android.os.LocaleList;
import android.os.Parcel;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.view.View;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
index ec6101c..7009fb2 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
@@ -24,11 +24,12 @@
import android.content.Context;
import android.content.Intent;
import android.os.LocaleList;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
import android.text.Spannable;
import android.text.SpannableString;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextLanguageTest.java b/core/tests/coretests/src/android/view/textclassifier/TextLanguageTest.java
index 1dcaed6..d0d32e3 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextLanguageTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextLanguageTest.java
@@ -21,8 +21,9 @@
import android.icu.util.ULocale;
import android.os.Bundle;
import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextLinksTest.java b/core/tests/coretests/src/android/view/textclassifier/TextLinksTest.java
index f022d04..b9cc8f4 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextLinksTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextLinksTest.java
@@ -21,10 +21,11 @@
import android.os.Bundle;
import android.os.LocaleList;
import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.util.ArrayMap;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java b/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java
index 2ea49f7..30cc4e8 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java
@@ -21,8 +21,9 @@
import android.os.Bundle;
import android.os.LocaleList;
import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/view/textclassifier/logging/GenerateLinksLoggerTest.java b/core/tests/coretests/src/android/view/textclassifier/logging/GenerateLinksLoggerTest.java
index 8e4f02c..5e8e582 100644
--- a/core/tests/coretests/src/android/view/textclassifier/logging/GenerateLinksLoggerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/logging/GenerateLinksLoggerTest.java
@@ -23,13 +23,14 @@
import static org.mockito.Mockito.mock;
import android.metrics.LogMaker;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.util.ArrayMap;
import android.view.textclassifier.GenerateLinksLogger;
import android.view.textclassifier.TextClassifier;
import android.view.textclassifier.TextLinks;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
diff --git a/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java b/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java
index 0597a89..b1b7416 100644
--- a/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.view.textclassifier.logging;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_TEXT_SELECTION_SMART_SHARE;
@@ -24,13 +25,14 @@
import static com.google.common.truth.Truth.assertThat;
import android.metrics.LogMaker;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.view.textclassifier.ConversationAction;
import android.view.textclassifier.TextClassificationContext;
import android.view.textclassifier.TextClassifierEvent;
import android.view.textclassifier.TextClassifierEventTronLogger;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import com.android.internal.logging.MetricsLogger;
import org.junit.Before;
diff --git a/core/tests/coretests/src/android/view/textservice/SpellCheckerSubtypeTest.java b/core/tests/coretests/src/android/view/textservice/SpellCheckerSubtypeTest.java
index 4a1c414..638d894 100644
--- a/core/tests/coretests/src/android/view/textservice/SpellCheckerSubtypeTest.java
+++ b/core/tests/coretests/src/android/view/textservice/SpellCheckerSubtypeTest.java
@@ -16,15 +16,16 @@
package android.view.textservice;
+import static android.test.MoreAsserts.assertNotEqual;
+
import android.os.Parcel;
import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
import java.util.Arrays;
import java.util.Locale;
-import static android.test.MoreAsserts.assertNotEqual;
-
/**
* TODO: Most of part can be, and probably should be, moved to CTS.
*/
diff --git a/core/tests/coretests/src/android/widget/AppWidgetHostViewTest.java b/core/tests/coretests/src/android/widget/AppWidgetHostViewTest.java
index 4f31c4e..6edc162 100644
--- a/core/tests/coretests/src/android/widget/AppWidgetHostViewTest.java
+++ b/core/tests/coretests/src/android/widget/AppWidgetHostViewTest.java
@@ -24,18 +24,14 @@
import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetManager;
import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.view.View;
import android.view.ViewGroup.OnHierarchyChangeListener;
-import com.android.frameworks.coretests.R;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
-import java.util.ArrayList;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.Executor;
-import java.util.concurrent.Future;
+import com.android.frameworks.coretests.R;
import org.junit.Before;
import org.junit.Rule;
@@ -43,6 +39,11 @@
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
+import java.util.ArrayList;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Future;
+
/**
* Tests for AppWidgetHostView
*/
diff --git a/core/tests/coretests/src/android/widget/AutoCompleteTextViewCallbacks.java b/core/tests/coretests/src/android/widget/AutoCompleteTextViewCallbacks.java
index 8e73b52..01e82a5 100644
--- a/core/tests/coretests/src/android/widget/AutoCompleteTextViewCallbacks.java
+++ b/core/tests/coretests/src/android/widget/AutoCompleteTextViewCallbacks.java
@@ -18,7 +18,8 @@
import android.app.Instrumentation;
import android.test.ActivityInstrumentationTestCase2;
-import android.test.FlakyTest;
+
+import androidx.test.filters.FlakyTest;
// TODO: tests fail intermittently. Add back MediumTest annotation when fixed
public class AutoCompleteTextViewCallbacks
@@ -32,7 +33,7 @@
/** Test that the initial popup of the suggestions does not select anything.
*/
- @FlakyTest(tolerance=3)
+ @FlakyTest
public void testPopupNoSelection() throws Exception {
AutoCompleteTextViewSimple theActivity = getActivity();
AutoCompleteTextView textView = theActivity.getTextView();
@@ -57,7 +58,7 @@
}
/** Test that arrow-down into the popup calls the onSelected callback. */
- @FlakyTest(tolerance=3)
+ @FlakyTest
public void testPopupEnterSelection() throws Exception {
final AutoCompleteTextViewSimple theActivity = getActivity();
AutoCompleteTextView textView = theActivity.getTextView();
@@ -106,7 +107,7 @@
}
/** Test that arrow-up out of the popup calls the onNothingSelected callback */
- @FlakyTest(tolerance=3)
+ @FlakyTest
public void testPopupLeaveSelection() {
final AutoCompleteTextViewSimple theActivity = getActivity();
AutoCompleteTextView textView = theActivity.getTextView();
diff --git a/core/tests/coretests/src/android/widget/AutoCompleteTextViewPopup.java b/core/tests/coretests/src/android/widget/AutoCompleteTextViewPopup.java
index ee0abae..21e4184 100644
--- a/core/tests/coretests/src/android/widget/AutoCompleteTextViewPopup.java
+++ b/core/tests/coretests/src/android/widget/AutoCompleteTextViewPopup.java
@@ -18,8 +18,8 @@
import android.app.Instrumentation;
import android.test.ActivityInstrumentationTestCase2;
-import android.test.FlakyTest;
-import android.test.suitebuilder.annotation.MediumTest;
+
+import androidx.test.filters.FlakyTest;
/**
* A collection of tests on aspects of the AutoCompleteTextView's popup
@@ -41,7 +41,7 @@
}
/** Test that we can move the selection and it responds as expected */
- @FlakyTest(tolerance=3)
+ @FlakyTest
public void testPopupSetListSelection() throws Throwable {
AutoCompleteTextViewSimple theActivity = getActivity();
final AutoCompleteTextView textView = theActivity.getTextView();
@@ -73,7 +73,7 @@
}
/** Test that we can look at the selection as we move around */
- @FlakyTest(tolerance=3)
+ @FlakyTest
public void testPopupGetListSelection() throws Throwable {
AutoCompleteTextViewSimple theActivity = getActivity();
final AutoCompleteTextView textView = theActivity.getTextView();
@@ -100,7 +100,7 @@
}
/** Test that we can clear the selection */
- @FlakyTest(tolerance=3)
+ @FlakyTest
public void testPopupClearListSelection() throws Throwable {
AutoCompleteTextViewSimple theActivity = getActivity();
final AutoCompleteTextView textView = theActivity.getTextView();
@@ -133,7 +133,7 @@
}
/** Make sure we handle an empty adapter properly */
- @FlakyTest(tolerance=3)
+ @FlakyTest
public void testPopupNavigateNoAdapter() throws Throwable {
AutoCompleteTextViewSimple theActivity = getActivity();
final AutoCompleteTextView textView = theActivity.getTextView();
@@ -167,7 +167,7 @@
}
/** Test the show/hide behavior of the drop-down. */
- @FlakyTest(tolerance=3)
+ @FlakyTest
public void testPopupShow() throws Throwable {
AutoCompleteTextViewSimple theActivity = getActivity();
final AutoCompleteTextView textView = theActivity.getTextView();
diff --git a/core/tests/coretests/src/android/widget/AutoCompleteTextViewSimple.java b/core/tests/coretests/src/android/widget/AutoCompleteTextViewSimple.java
index b4e05aa..063bec5 100644
--- a/core/tests/coretests/src/android/widget/AutoCompleteTextViewSimple.java
+++ b/core/tests/coretests/src/android/widget/AutoCompleteTextViewSimple.java
@@ -16,8 +16,6 @@
package android.widget;
-import com.android.frameworks.coretests.R;
-
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
@@ -25,6 +23,8 @@
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemSelectedListener;
+import com.android.frameworks.coretests.R;
+
public class AutoCompleteTextViewSimple extends Activity
implements OnItemClickListener, OnItemSelectedListener {
diff --git a/core/tests/coretests/src/android/widget/DatePickerActivity.java b/core/tests/coretests/src/android/widget/DatePickerActivity.java
index c3b25a1..9e455b2 100644
--- a/core/tests/coretests/src/android/widget/DatePickerActivity.java
+++ b/core/tests/coretests/src/android/widget/DatePickerActivity.java
@@ -18,6 +18,7 @@
import android.app.Activity;
import android.os.Bundle;
+
import com.android.frameworks.coretests.R;
/**
diff --git a/core/tests/coretests/src/android/widget/DatePickerFocusTest.java b/core/tests/coretests/src/android/widget/DatePickerFocusTest.java
index be85450..f067230 100644
--- a/core/tests/coretests/src/android/widget/DatePickerFocusTest.java
+++ b/core/tests/coretests/src/android/widget/DatePickerFocusTest.java
@@ -19,11 +19,12 @@
import android.app.Activity;
import android.app.Instrumentation;
import android.os.SystemClock;
-import android.support.test.filters.LargeTest;
import android.test.ActivityInstrumentationTestCase2;
import android.view.KeyEvent;
import android.view.View;
+import androidx.test.filters.LargeTest;
+
import com.android.frameworks.coretests.R;
/**
diff --git a/core/tests/coretests/src/android/widget/DateTimeViewTest.java b/core/tests/coretests/src/android/widget/DateTimeViewTest.java
index 40a6b7a..d0bd4b8 100644
--- a/core/tests/coretests/src/android/widget/DateTimeViewTest.java
+++ b/core/tests/coretests/src/android/widget/DateTimeViewTest.java
@@ -16,10 +16,10 @@
package android.widget;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.annotation.UiThreadTest;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/widget/EditorCursorTest.java b/core/tests/coretests/src/android/widget/EditorCursorTest.java
index 9186827b..e4f55df 100644
--- a/core/tests/coretests/src/android/widget/EditorCursorTest.java
+++ b/core/tests/coretests/src/android/widget/EditorCursorTest.java
@@ -31,10 +31,11 @@
import android.app.Activity;
import android.app.Instrumentation;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.MediumTest;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.MediumTest;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
import com.android.frameworks.coretests.R;
diff --git a/core/tests/coretests/src/android/widget/ListViewTest.java b/core/tests/coretests/src/android/widget/ListViewTest.java
index 449b696..254af2a 100644
--- a/core/tests/coretests/src/android/widget/ListViewTest.java
+++ b/core/tests/coretests/src/android/widget/ListViewTest.java
@@ -16,20 +16,19 @@
package android.widget;
-import android.test.suitebuilder.annotation.Suppress;
-import com.google.android.collect.Lists;
-
-import junit.framework.Assert;
-
import android.content.Context;
import android.content.res.Resources;
import android.test.InstrumentationTestCase;
import android.test.mock.MockContext;
-import android.test.suitebuilder.annotation.MediumTest;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import android.widget.ListView;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
+import com.google.android.collect.Lists;
+
+import junit.framework.Assert;
import java.util.List;
diff --git a/core/tests/coretests/src/android/widget/RadioGroupActivity.java b/core/tests/coretests/src/android/widget/RadioGroupActivity.java
index c87aa3a..dd3b30a 100644
--- a/core/tests/coretests/src/android/widget/RadioGroupActivity.java
+++ b/core/tests/coretests/src/android/widget/RadioGroupActivity.java
@@ -17,11 +17,11 @@
package android.widget;
-import com.android.frameworks.coretests.R;
-
import android.app.Activity;
import android.os.Bundle;
+import com.android.frameworks.coretests.R;
+
public class RadioGroupActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
diff --git a/core/tests/coretests/src/android/widget/RadioGroupPreCheckedTest.java b/core/tests/coretests/src/android/widget/RadioGroupPreCheckedTest.java
index 1ab3628..18c1ea1 100644
--- a/core/tests/coretests/src/android/widget/RadioGroupPreCheckedTest.java
+++ b/core/tests/coretests/src/android/widget/RadioGroupPreCheckedTest.java
@@ -16,12 +16,13 @@
package android.widget;
-import com.android.frameworks.coretests.R;
-
import android.test.ActivityInstrumentationTestCase2;
import android.test.TouchUtils;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
/**
* Exercises {@link android.widget.RadioGroup}'s check feature.
diff --git a/core/tests/coretests/src/android/widget/RemoteViewsAdapterTest.java b/core/tests/coretests/src/android/widget/RemoteViewsAdapterTest.java
index 06b860a..da53f6d 100644
--- a/core/tests/coretests/src/android/widget/RemoteViewsAdapterTest.java
+++ b/core/tests/coretests/src/android/widget/RemoteViewsAdapterTest.java
@@ -38,11 +38,12 @@
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.view.View;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import com.android.frameworks.coretests.R;
import com.android.internal.widget.IRemoteViewsFactory;
diff --git a/core/tests/coretests/src/android/widget/RemoteViewsTest.java b/core/tests/coretests/src/android/widget/RemoteViewsTest.java
index 36792bb..8cb7e1b 100644
--- a/core/tests/coretests/src/android/widget/RemoteViewsTest.java
+++ b/core/tests/coretests/src/android/widget/RemoteViewsTest.java
@@ -32,12 +32,13 @@
import android.os.AsyncTask;
import android.os.Binder;
import android.os.Parcel;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.view.View;
import android.view.ViewGroup;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import com.android.frameworks.coretests.R;
import org.junit.Before;
diff --git a/core/tests/coretests/src/android/widget/SelectionActionModeHelperTest.java b/core/tests/coretests/src/android/widget/SelectionActionModeHelperTest.java
index 2add221..74aad9a 100644
--- a/core/tests/coretests/src/android/widget/SelectionActionModeHelperTest.java
+++ b/core/tests/coretests/src/android/widget/SelectionActionModeHelperTest.java
@@ -22,7 +22,8 @@
import android.graphics.PointF;
import android.graphics.RectF;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/widget/SimpleCursorAdapterTest.java b/core/tests/coretests/src/android/widget/SimpleCursorAdapterTest.java
index 1731c08..a79b30d 100644
--- a/core/tests/coretests/src/android/widget/SimpleCursorAdapterTest.java
+++ b/core/tests/coretests/src/android/widget/SimpleCursorAdapterTest.java
@@ -16,14 +16,15 @@
package android.widget;
-import android.test.suitebuilder.annotation.Suppress;
-import com.google.android.collect.Lists;
-
import android.content.Context;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.filters.Suppress;
+
+import com.google.android.collect.Lists;
import java.util.ArrayList;
import java.util.Random;
diff --git a/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java b/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java
index eafe427..483270e 100644
--- a/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java
+++ b/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java
@@ -36,13 +36,13 @@
import static android.widget.espresso.SuggestionsPopupwindowUtils.onSuggestionsPopup;
import static android.widget.espresso.TextViewActions.clickOnTextAtIndex;
import static android.widget.espresso.TextViewActions.longPressOnTextAtIndex;
+
import static org.hamcrest.Matchers.is;
+
import android.content.res.TypedArray;
import android.support.test.espresso.NoMatchingViewException;
import android.support.test.espresso.ViewAssertion;
import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.Suppress;
import android.text.Selection;
import android.text.Spannable;
import android.text.Spanned;
@@ -51,6 +51,8 @@
import android.text.style.TextAppearanceSpan;
import android.view.View;
+import androidx.test.filters.SmallTest;
+
import com.android.frameworks.coretests.R;
/**
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java b/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java
index ff4a7da..41fa08b 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java
@@ -43,14 +43,15 @@
import static android.widget.espresso.TextViewAssertions.hasSelection;
import android.app.Activity;
-import android.support.test.filters.MediumTest;
-import android.support.test.filters.Suppress;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
import android.view.MotionEvent;
import android.view.textclassifier.TextClassificationManager;
import android.view.textclassifier.TextClassifier;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
import com.android.frameworks.coretests.R;
import org.junit.Before;
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
index 90758ba..9d93421 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
@@ -27,10 +27,8 @@
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static android.widget.espresso.CustomViewActions.longPressAtRelativeCoordinates;
import static android.widget.espresso.DragHandleUtils.onHandleView;
-import static android.widget.espresso.FloatingToolbarEspressoUtils
- .assertFloatingToolbarContainsItem;
-import static android.widget.espresso.FloatingToolbarEspressoUtils
- .assertFloatingToolbarDoesNotContainItem;
+import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarContainsItem;
+import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarDoesNotContainItem;
import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarIsDisplayed;
import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarItemIndex;
import static android.widget.espresso.FloatingToolbarEspressoUtils.clickFloatingToolbarItem;
@@ -62,13 +60,8 @@
import android.app.Instrumentation;
import android.content.ClipData;
import android.content.ClipboardManager;
-import android.support.test.InstrumentationRegistry;
import android.support.test.espresso.action.EspressoKey;
-import android.support.test.filters.MediumTest;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
import android.support.test.uiautomator.UiDevice;
-import android.test.suitebuilder.annotation.Suppress;
import android.text.InputType;
import android.text.Selection;
import android.text.Spannable;
@@ -85,6 +78,12 @@
import android.view.textclassifier.TextLinksParams;
import android.widget.espresso.CustomViewActions.RelativeCoordinatesProvider;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
import com.android.frameworks.coretests.R;
import org.junit.Before;
diff --git a/core/tests/coretests/src/android/widget/TextViewFallbackLineSpacingTest.java b/core/tests/coretests/src/android/widget/TextViewFallbackLineSpacingTest.java
index e9d1d3e..113db9d 100644
--- a/core/tests/coretests/src/android/widget/TextViewFallbackLineSpacingTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewFallbackLineSpacingTest.java
@@ -21,8 +21,6 @@
import static org.junit.Assert.assertTrue;
import android.app.Activity;
-import android.support.test.filters.MediumTest;
-import android.support.test.rule.ActivityTestRule;
import android.text.DynamicLayout;
import android.text.FontFallbackSetup;
import android.text.Layout;
@@ -31,6 +29,9 @@
import android.view.View;
import android.widget.TextView.BufferType;
+import androidx.test.filters.MediumTest;
+import androidx.test.rule.ActivityTestRule;
+
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/widget/TextViewPerformanceTest.java b/core/tests/coretests/src/android/widget/TextViewPerformanceTest.java
index cf173fb..a769ea4 100644
--- a/core/tests/coretests/src/android/widget/TextViewPerformanceTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewPerformanceTest.java
@@ -20,14 +20,15 @@
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.MediumTest;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.text.SpannedString;
import android.view.View;
import android.view.ViewGroup;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/widget/TextViewTest.java b/core/tests/coretests/src/android/widget/TextViewTest.java
index 1c5610b..585360f 100644
--- a/core/tests/coretests/src/android/widget/TextViewTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewTest.java
@@ -27,11 +27,6 @@
import android.content.Intent;
import android.graphics.Paint;
import android.platform.test.annotations.Presubmit;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.annotation.UiThreadTest;
-import android.support.test.filters.MediumTest;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
import android.text.GetChars;
import android.text.Layout;
import android.text.PrecomputedText;
@@ -40,6 +35,12 @@
import android.view.View;
import android.widget.TextView.BufferType;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/widget/focus/AdjacentVerticalRectLists.java b/core/tests/coretests/src/android/widget/focus/AdjacentVerticalRectLists.java
index 75da6fe..85a4509 100644
--- a/core/tests/coretests/src/android/widget/focus/AdjacentVerticalRectLists.java
+++ b/core/tests/coretests/src/android/widget/focus/AdjacentVerticalRectLists.java
@@ -16,12 +16,11 @@
package android.widget.focus;
-import android.util.InternalSelectionView;
-
import android.app.Activity;
import android.os.Bundle;
-import android.widget.LinearLayout;
+import android.util.InternalSelectionView;
import android.view.ViewGroup;
+import android.widget.LinearLayout;
/**
* {@link android.view.FocusFinder#findNextFocus(android.view.ViewGroup, android.view.View, int)}
diff --git a/core/tests/coretests/src/android/widget/focus/DescendantFocusability.java b/core/tests/coretests/src/android/widget/focus/DescendantFocusability.java
index f6b0520..fe6d3c8 100644
--- a/core/tests/coretests/src/android/widget/focus/DescendantFocusability.java
+++ b/core/tests/coretests/src/android/widget/focus/DescendantFocusability.java
@@ -16,13 +16,13 @@
package android.widget.focus;
-import com.android.frameworks.coretests.R;
-
import android.app.Activity;
import android.os.Bundle;
import android.view.ViewGroup;
import android.widget.Button;
+import com.android.frameworks.coretests.R;
+
public class DescendantFocusability extends Activity {
public ViewGroup beforeDescendants;
diff --git a/core/tests/coretests/src/android/widget/focus/DescendantFocusabilityTest.java b/core/tests/coretests/src/android/widget/focus/DescendantFocusabilityTest.java
index 2af42ac..1c570df 100644
--- a/core/tests/coretests/src/android/widget/focus/DescendantFocusabilityTest.java
+++ b/core/tests/coretests/src/android/widget/focus/DescendantFocusabilityTest.java
@@ -16,15 +16,14 @@
package android.widget.focus;
-import android.widget.focus.DescendantFocusability;
-
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.UiThreadTest;
import android.test.TouchUtils;
import android.view.ViewGroup;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
public class DescendantFocusabilityTest extends ActivityInstrumentationTestCase<DescendantFocusability> {
private DescendantFocusability a;
diff --git a/core/tests/coretests/src/android/widget/focus/FocusAfterRemoval.java b/core/tests/coretests/src/android/widget/focus/FocusAfterRemoval.java
index b3d5ec5..0cb80ce 100644
--- a/core/tests/coretests/src/android/widget/focus/FocusAfterRemoval.java
+++ b/core/tests/coretests/src/android/widget/focus/FocusAfterRemoval.java
@@ -16,13 +16,13 @@
package android.widget.focus;
-import com.android.frameworks.coretests.R;
-
import android.app.Activity;
import android.os.Bundle;
-import android.widget.LinearLayout;
-import android.widget.Button;
import android.view.View;
+import android.widget.Button;
+import android.widget.LinearLayout;
+
+import com.android.frameworks.coretests.R;
/**
* Exercises cases where elements of the UI are removed (and
diff --git a/core/tests/coretests/src/android/widget/focus/FocusAfterRemovalTest.java b/core/tests/coretests/src/android/widget/focus/FocusAfterRemovalTest.java
index a1b7bcb..6c46d08 100644
--- a/core/tests/coretests/src/android/widget/focus/FocusAfterRemovalTest.java
+++ b/core/tests/coretests/src/android/widget/focus/FocusAfterRemovalTest.java
@@ -16,15 +16,15 @@
package android.widget.focus;
-import android.widget.focus.FocusAfterRemoval;
-import com.android.frameworks.coretests.R;
-
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.widget.Button;
-import android.widget.LinearLayout;
import android.view.KeyEvent;
import android.view.View;
+import android.widget.Button;
+import android.widget.LinearLayout;
+
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
/**
* {@link FocusAfterRemoval} is set up to exercise cases where the views that
diff --git a/core/tests/coretests/src/android/widget/focus/FocusChangeWithInterestingRectHintTest.java b/core/tests/coretests/src/android/widget/focus/FocusChangeWithInterestingRectHintTest.java
index 8f8f184..26dc233 100644
--- a/core/tests/coretests/src/android/widget/focus/FocusChangeWithInterestingRectHintTest.java
+++ b/core/tests/coretests/src/android/widget/focus/FocusChangeWithInterestingRectHintTest.java
@@ -16,14 +16,13 @@
package android.widget.focus;
-import android.widget.focus.AdjacentVerticalRectLists;
-import android.util.InternalSelectionView;
-
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.util.InternalSelectionView;
import android.view.KeyEvent;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
/**
* {@link android.view.FocusFinder#findNextFocus(android.view.ViewGroup, android.view.View, int)}
* and
diff --git a/core/tests/coretests/src/android/widget/focus/GoneParentFocusedChildTest.java b/core/tests/coretests/src/android/widget/focus/GoneParentFocusedChildTest.java
index dcbddef..b7974e3 100644
--- a/core/tests/coretests/src/android/widget/focus/GoneParentFocusedChildTest.java
+++ b/core/tests/coretests/src/android/widget/focus/GoneParentFocusedChildTest.java
@@ -17,10 +17,10 @@
package android.widget.focus;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
import android.view.KeyEvent;
import android.view.View;
-import android.widget.focus.GoneParentFocusedChild;
+
+import androidx.test.filters.MediumTest;
/**
* When a parent is GONE, key events shouldn't go to its children, even if they
diff --git a/core/tests/coretests/src/android/widget/focus/HorizontalFocusSearch.java b/core/tests/coretests/src/android/widget/focus/HorizontalFocusSearch.java
index 11cac1e..aab9119 100644
--- a/core/tests/coretests/src/android/widget/focus/HorizontalFocusSearch.java
+++ b/core/tests/coretests/src/android/widget/focus/HorizontalFocusSearch.java
@@ -17,12 +17,12 @@
package android.widget.focus;
import android.app.Activity;
-import android.widget.LinearLayout;
-import android.widget.Button;
-import android.widget.TextView;
+import android.content.Context;
import android.os.Bundle;
import android.view.ViewGroup;
-import android.content.Context;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.TextView;
public class HorizontalFocusSearch extends Activity {
diff --git a/core/tests/coretests/src/android/widget/focus/HorizontalFocusSearchTest.java b/core/tests/coretests/src/android/widget/focus/HorizontalFocusSearchTest.java
index 43986ee..855a3219 100644
--- a/core/tests/coretests/src/android/widget/focus/HorizontalFocusSearchTest.java
+++ b/core/tests/coretests/src/android/widget/focus/HorizontalFocusSearchTest.java
@@ -16,18 +16,17 @@
package android.widget.focus;
-import android.widget.focus.HorizontalFocusSearch;
-
-import android.support.test.filters.LargeTest;
-import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.Suppress;
-import android.widget.LinearLayout;
-import android.widget.Button;
-import android.view.View;
-
import static android.widget.focus.VerticalFocusSearchTest.FocusSearchAlg;
import static android.widget.focus.VerticalFocusSearchTest.NewFocusSearchAlg;
+import android.test.ActivityInstrumentationTestCase;
+import android.view.View;
+import android.widget.Button;
+import android.widget.LinearLayout;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.Suppress;
+
/**
* Tests that focus searching works on a horizontal linear layout of buttons of
* various widths and vertical placements.
diff --git a/core/tests/coretests/src/android/widget/focus/LinearLayoutGrid.java b/core/tests/coretests/src/android/widget/focus/LinearLayoutGrid.java
index acd632f..ec234bc 100644
--- a/core/tests/coretests/src/android/widget/focus/LinearLayoutGrid.java
+++ b/core/tests/coretests/src/android/widget/focus/LinearLayoutGrid.java
@@ -21,6 +21,7 @@
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
+
import com.android.frameworks.coretests.R;
public class LinearLayoutGrid extends Activity {
diff --git a/core/tests/coretests/src/android/widget/focus/LinearLayoutGridTest.java b/core/tests/coretests/src/android/widget/focus/LinearLayoutGridTest.java
index 89cb8bb..c81317c 100644
--- a/core/tests/coretests/src/android/widget/focus/LinearLayoutGridTest.java
+++ b/core/tests/coretests/src/android/widget/focus/LinearLayoutGridTest.java
@@ -17,11 +17,11 @@
package android.widget.focus;
import android.test.SingleLaunchActivityTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
import android.view.FocusFinder;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.focus.LinearLayoutGrid;
+
+import androidx.test.filters.MediumTest;
/**
* Tests focus searching between buttons within a grid that are touching, for example,
diff --git a/core/tests/coretests/src/android/widget/focus/ListOfButtons.java b/core/tests/coretests/src/android/widget/focus/ListOfButtons.java
index 308861d..5663ed2 100644
--- a/core/tests/coretests/src/android/widget/focus/ListOfButtons.java
+++ b/core/tests/coretests/src/android/widget/focus/ListOfButtons.java
@@ -16,8 +16,6 @@
package android.widget.focus;
-import com.android.frameworks.coretests.R;
-
import android.app.ListActivity;
import android.content.Context;
import android.os.Bundle;
@@ -26,6 +24,8 @@
import android.widget.ArrayAdapter;
import android.widget.Button;
+import com.android.frameworks.coretests.R;
+
/**
* A layout with a ListView containing buttons.
*/
diff --git a/core/tests/coretests/src/android/widget/focus/ListOfButtonsTest.java b/core/tests/coretests/src/android/widget/focus/ListOfButtonsTest.java
index bec6f80..4cf4a3a 100644
--- a/core/tests/coretests/src/android/widget/focus/ListOfButtonsTest.java
+++ b/core/tests/coretests/src/android/widget/focus/ListOfButtonsTest.java
@@ -16,17 +16,17 @@
package android.widget.focus;
-import android.test.suitebuilder.annotation.Suppress;
-import android.widget.focus.ListOfButtons;
-import com.android.frameworks.coretests.R;
-
import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.widget.ListAdapter;
-import android.widget.Button;
-import android.widget.ListView;
import android.view.KeyEvent;
import android.view.View;
+import android.widget.Button;
+import android.widget.ListAdapter;
+import android.widget.ListView;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
+import com.android.frameworks.coretests.R;
/**
* Tests that focus works as expected when navigating into and out of
diff --git a/core/tests/coretests/src/android/widget/focus/ListOfEditTexts.java b/core/tests/coretests/src/android/widget/focus/ListOfEditTexts.java
index c2e7a26..936c999 100644
--- a/core/tests/coretests/src/android/widget/focus/ListOfEditTexts.java
+++ b/core/tests/coretests/src/android/widget/focus/ListOfEditTexts.java
@@ -21,7 +21,12 @@
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.*;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+
import com.google.android.collect.Lists;
import java.util.List;
diff --git a/core/tests/coretests/src/android/widget/focus/ListOfInternalSelectionViews.java b/core/tests/coretests/src/android/widget/focus/ListOfInternalSelectionViews.java
index 53b866c..73e4ea8 100644
--- a/core/tests/coretests/src/android/widget/focus/ListOfInternalSelectionViews.java
+++ b/core/tests/coretests/src/android/widget/focus/ListOfInternalSelectionViews.java
@@ -19,11 +19,11 @@
import android.app.Activity;
import android.graphics.Point;
import android.os.Bundle;
+import android.util.InternalSelectionView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
-import android.util.InternalSelectionView;
/**
* A list of {@link InternalSelectionView}s paramatarized by the number of items,
diff --git a/core/tests/coretests/src/android/widget/focus/ListWithFooterViewAndNewLabels.java b/core/tests/coretests/src/android/widget/focus/ListWithFooterViewAndNewLabels.java
index b908201..8accf21 100644
--- a/core/tests/coretests/src/android/widget/focus/ListWithFooterViewAndNewLabels.java
+++ b/core/tests/coretests/src/android/widget/focus/ListWithFooterViewAndNewLabels.java
@@ -27,9 +27,10 @@
import android.widget.Button;
import android.widget.TextView;
-import com.google.android.collect.Lists;
import com.android.frameworks.coretests.R;
+import com.google.android.collect.Lists;
+
import java.util.List;
public class ListWithFooterViewAndNewLabels extends ListActivity {
diff --git a/core/tests/coretests/src/android/widget/focus/ListWithFooterViewAndNewLabelsTest.java b/core/tests/coretests/src/android/widget/focus/ListWithFooterViewAndNewLabelsTest.java
index 57dbb78..d0fcde5 100644
--- a/core/tests/coretests/src/android/widget/focus/ListWithFooterViewAndNewLabelsTest.java
+++ b/core/tests/coretests/src/android/widget/focus/ListWithFooterViewAndNewLabelsTest.java
@@ -16,14 +16,13 @@
package android.widget.focus;
-import android.widget.focus.ListWithFooterViewAndNewLabels;
-import com.android.frameworks.coretests.R;
-
import android.test.ActivityInstrumentationTestCase;
import android.widget.Button;
import android.widget.ListAdapter;
import android.widget.ListView;
+import com.android.frameworks.coretests.R;
+
public class ListWithFooterViewAndNewLabelsTest
extends ActivityInstrumentationTestCase<ListWithFooterViewAndNewLabels> {
diff --git a/core/tests/coretests/src/android/widget/focus/ListWithMailMessages.java b/core/tests/coretests/src/android/widget/focus/ListWithMailMessages.java
index 5c891f9..50a8614 100644
--- a/core/tests/coretests/src/android/widget/focus/ListWithMailMessages.java
+++ b/core/tests/coretests/src/android/widget/focus/ListWithMailMessages.java
@@ -16,19 +16,20 @@
package android.widget.focus;
-import com.android.frameworks.coretests.R;
-import com.google.android.collect.Lists;
-
import android.app.ListActivity;
+import android.content.Context;
import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.webkit.WebView;
import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
import android.widget.TextView;
-import android.content.Context;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.LayoutInflater;
-import android.webkit.WebView;
+
+import com.android.frameworks.coretests.R;
+
+import com.google.android.collect.Lists;
import java.util.List;
diff --git a/core/tests/coretests/src/android/widget/focus/RequestFocus.java b/core/tests/coretests/src/android/widget/focus/RequestFocus.java
index 4daf0b4..5042efd 100644
--- a/core/tests/coretests/src/android/widget/focus/RequestFocus.java
+++ b/core/tests/coretests/src/android/widget/focus/RequestFocus.java
@@ -16,13 +16,13 @@
package android.widget.focus;
-import com.android.frameworks.coretests.R;
-
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.widget.Button;
+import com.android.frameworks.coretests.R;
+
/**
* Exercises cases where elements of the UI are requestFocus()ed.
*/
diff --git a/core/tests/coretests/src/android/widget/focus/RequestFocusTest.java b/core/tests/coretests/src/android/widget/focus/RequestFocusTest.java
index cdfa217..bc770c5 100644
--- a/core/tests/coretests/src/android/widget/focus/RequestFocusTest.java
+++ b/core/tests/coretests/src/android/widget/focus/RequestFocusTest.java
@@ -21,16 +21,18 @@
import android.os.Handler;
import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
import android.util.AndroidRuntimeException;
import android.view.View;
import android.view.View.OnFocusChangeListener;
import android.view.ViewTreeObserver.OnGlobalFocusChangeListener;
import android.widget.Button;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
import com.android.frameworks.coretests.R;
+
import org.mockito.InOrder;
/**
diff --git a/core/tests/coretests/src/android/widget/focus/ScrollingThroughListOfFocusablesTest.java b/core/tests/coretests/src/android/widget/focus/ScrollingThroughListOfFocusablesTest.java
index 06cb75d..e6e76cc 100644
--- a/core/tests/coretests/src/android/widget/focus/ScrollingThroughListOfFocusablesTest.java
+++ b/core/tests/coretests/src/android/widget/focus/ScrollingThroughListOfFocusablesTest.java
@@ -18,12 +18,12 @@
import android.graphics.Rect;
import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
import android.util.InternalSelectionView;
import android.view.KeyEvent;
import android.widget.ListView;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
/**
* TODO: extract base test case that launches {@link ListOfInternalSelectionViews} with
diff --git a/core/tests/coretests/src/android/widget/focus/VerticalFocusSearch.java b/core/tests/coretests/src/android/widget/focus/VerticalFocusSearch.java
index 4a809e0..2ca9f6d 100644
--- a/core/tests/coretests/src/android/widget/focus/VerticalFocusSearch.java
+++ b/core/tests/coretests/src/android/widget/focus/VerticalFocusSearch.java
@@ -17,13 +17,13 @@
package android.widget.focus;
import android.app.Activity;
+import android.content.Context;
import android.os.Bundle;
-import android.widget.LinearLayout;
-import android.widget.Button;
-import android.widget.TextView;
import android.view.Gravity;
import android.view.ViewGroup;
-import android.content.Context;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.TextView;
/**
* Holds a few buttons of various sizes and horizontal placements in a
diff --git a/core/tests/coretests/src/android/widget/focus/VerticalFocusSearchTest.java b/core/tests/coretests/src/android/widget/focus/VerticalFocusSearchTest.java
index f01422e..319756c 100644
--- a/core/tests/coretests/src/android/widget/focus/VerticalFocusSearchTest.java
+++ b/core/tests/coretests/src/android/widget/focus/VerticalFocusSearchTest.java
@@ -16,17 +16,16 @@
package android.widget.focus;
-import android.widget.focus.VerticalFocusSearch;
-
-import android.support.test.filters.LargeTest;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.Suppress;
import android.view.FocusFinder;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.Suppress;
+
/**
* Tests that focus searching works on a vertical linear layout of buttons of
* various widths and horizontal placements.
diff --git a/core/tests/coretests/src/android/widget/gridview/GridDelete.java b/core/tests/coretests/src/android/widget/gridview/GridDelete.java
index 57ae8f39..b040f69 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridDelete.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridDelete.java
@@ -16,6 +16,7 @@
package android.widget.gridview;
+import android.util.GridScenario;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
@@ -23,8 +24,6 @@
import android.widget.GridView;
import android.widget.ListAdapter;
-import android.util.GridScenario;
-
import java.util.ArrayList;
/**
diff --git a/core/tests/coretests/src/android/widget/gridview/GridInHorizontalTest.java b/core/tests/coretests/src/android/widget/gridview/GridInHorizontalTest.java
index 21ca655..5247009 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridInHorizontalTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridInHorizontalTest.java
@@ -17,10 +17,9 @@
package android.widget.gridview;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
import android.widget.GridView;
-import android.widget.gridview.GridInHorizontal;
+import androidx.test.filters.MediumTest;
public class GridInHorizontalTest extends ActivityInstrumentationTestCase<GridInHorizontal> {
diff --git a/core/tests/coretests/src/android/widget/gridview/GridInVerticalTest.java b/core/tests/coretests/src/android/widget/gridview/GridInVerticalTest.java
index a674db2..290f70e 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridInVerticalTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridInVerticalTest.java
@@ -17,10 +17,9 @@
package android.widget.gridview;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
import android.widget.GridView;
-import android.widget.gridview.GridInVertical;
+import androidx.test.filters.MediumTest;
public class GridInVerticalTest extends ActivityInstrumentationTestCase<GridInVertical> {
diff --git a/core/tests/coretests/src/android/widget/gridview/GridPaddingTest.java b/core/tests/coretests/src/android/widget/gridview/GridPaddingTest.java
index ecd4b1c..d2ae7cf 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridPaddingTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridPaddingTest.java
@@ -17,9 +17,10 @@
package android.widget.gridview;
import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.MediumTest;
import android.widget.GridView;
+import androidx.test.filters.MediumTest;
+
public class GridPaddingTest extends ActivityInstrumentationTestCase2<GridPadding> {
private GridView mGridView;
diff --git a/core/tests/coretests/src/android/widget/gridview/GridScrollListenerTest.java b/core/tests/coretests/src/android/widget/gridview/GridScrollListenerTest.java
index 53eeb48..466c55f 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridScrollListenerTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridScrollListenerTest.java
@@ -19,12 +19,13 @@
import android.app.Instrumentation;
import android.test.ActivityInstrumentationTestCase;
import android.test.TouchUtils;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
import android.view.KeyEvent;
import android.widget.AbsListView;
import android.widget.GridView;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
public class GridScrollListenerTest extends ActivityInstrumentationTestCase<GridScrollListener> implements
AbsListView.OnScrollListener {
private GridScrollListener mActivity;
diff --git a/core/tests/coretests/src/android/widget/gridview/GridSetSelectionBaseTest.java b/core/tests/coretests/src/android/widget/gridview/GridSetSelectionBaseTest.java
index 0e362b6..db4f2dc 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridSetSelectionBaseTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridSetSelectionBaseTest.java
@@ -16,13 +16,13 @@
package android.widget.gridview;
-import android.util.GridScenario;
-
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
import android.test.ViewAsserts;
+import android.util.GridScenario;
import android.widget.GridView;
+import androidx.test.filters.MediumTest;
+
public class GridSetSelectionBaseTest<T extends GridScenario> extends ActivityInstrumentationTestCase<T> {
private T mActivity;
private GridView mGridView;
diff --git a/core/tests/coretests/src/android/widget/gridview/GridSetSelectionManyTest.java b/core/tests/coretests/src/android/widget/gridview/GridSetSelectionManyTest.java
index 6739645..17a6044 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridSetSelectionManyTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridSetSelectionManyTest.java
@@ -16,8 +16,6 @@
package android.widget.gridview;
-import android.widget.gridview.GridSetSelectionMany;
-
public class GridSetSelectionManyTest extends GridSetSelectionBaseTest<GridSetSelectionMany> {
public GridSetSelectionManyTest() {
super(GridSetSelectionMany.class);
diff --git a/core/tests/coretests/src/android/widget/gridview/GridSetSelectionStackFromBottomManyTest.java b/core/tests/coretests/src/android/widget/gridview/GridSetSelectionStackFromBottomManyTest.java
index 46922b97..a71f732 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridSetSelectionStackFromBottomManyTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridSetSelectionStackFromBottomManyTest.java
@@ -16,8 +16,6 @@
package android.widget.gridview;
-import android.widget.gridview.GridSetSelectionStackFromBottomMany;
-
public class GridSetSelectionStackFromBottomManyTest extends GridSetSelectionBaseTest<GridSetSelectionStackFromBottomMany> {
public GridSetSelectionStackFromBottomManyTest() {
super(GridSetSelectionStackFromBottomMany.class);
diff --git a/core/tests/coretests/src/android/widget/gridview/GridSetSelectionStackFromBottomTest.java b/core/tests/coretests/src/android/widget/gridview/GridSetSelectionStackFromBottomTest.java
index 67dd6f1..4e6e8aa 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridSetSelectionStackFromBottomTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridSetSelectionStackFromBottomTest.java
@@ -16,8 +16,6 @@
package android.widget.gridview;
-import android.widget.gridview.GridSetSelectionStackFromBottom;
-
public class GridSetSelectionStackFromBottomTest extends GridSetSelectionBaseTest<GridSetSelectionStackFromBottom> {
public GridSetSelectionStackFromBottomTest() {
super(GridSetSelectionStackFromBottom.class);
diff --git a/core/tests/coretests/src/android/widget/gridview/GridSetSelectionTest.java b/core/tests/coretests/src/android/widget/gridview/GridSetSelectionTest.java
index 2127b3c..68802fe 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridSetSelectionTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridSetSelectionTest.java
@@ -16,8 +16,6 @@
package android.widget.gridview;
-import android.widget.gridview.GridSetSelection;
-
public class GridSetSelectionTest extends GridSetSelectionBaseTest<GridSetSelection> {
public GridSetSelectionTest() {
super(GridSetSelection.class);
diff --git a/core/tests/coretests/src/android/widget/gridview/GridSimple.java b/core/tests/coretests/src/android/widget/gridview/GridSimple.java
index 7c2c696..67bb751 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridSimple.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridSimple.java
@@ -18,12 +18,11 @@
import android.graphics.drawable.PaintDrawable;
import android.os.Bundle;
+import android.util.GridScenario;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
-import android.util.GridScenario;
-
public class GridSimple extends GridScenario {
@Override
protected void init(Params params) {
diff --git a/core/tests/coretests/src/android/widget/gridview/GridSingleColumnTest.java b/core/tests/coretests/src/android/widget/gridview/GridSingleColumnTest.java
index 3b2504e..0f67522 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridSingleColumnTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridSingleColumnTest.java
@@ -17,10 +17,9 @@
package android.widget.gridview;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
import android.widget.GridView;
-import android.widget.gridview.GridSingleColumn;
+import androidx.test.filters.MediumTest;
public class GridSingleColumnTest extends ActivityInstrumentationTestCase<GridSingleColumn> {
private GridSingleColumn mActivity;
diff --git a/core/tests/coretests/src/android/widget/gridview/GridStackFromBottomManyTest.java b/core/tests/coretests/src/android/widget/gridview/GridStackFromBottomManyTest.java
index 640737e..a369616 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridStackFromBottomManyTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridStackFromBottomManyTest.java
@@ -16,11 +16,10 @@
package android.widget.gridview;
-import android.widget.gridview.GridStackFromBottomMany;
-
-import android.test.suitebuilder.annotation.MediumTest;
-import android.widget.GridView;
import android.test.ActivityInstrumentationTestCase;
+import android.widget.GridView;
+
+import androidx.test.filters.MediumTest;
public class GridStackFromBottomManyTest extends ActivityInstrumentationTestCase<GridStackFromBottomMany> {
private GridStackFromBottomMany mActivity;
diff --git a/core/tests/coretests/src/android/widget/gridview/GridStackFromBottomTest.java b/core/tests/coretests/src/android/widget/gridview/GridStackFromBottomTest.java
index 8fec241..da1b638 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridStackFromBottomTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridStackFromBottomTest.java
@@ -16,12 +16,11 @@
package android.widget.gridview;
-import android.widget.gridview.GridStackFromBottom;
-
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
import android.widget.GridView;
+import androidx.test.filters.MediumTest;
+
public class GridStackFromBottomTest extends ActivityInstrumentationTestCase<GridStackFromBottom> {
private GridStackFromBottom mActivity;
private GridView mGridView;
diff --git a/core/tests/coretests/src/android/widget/gridview/GridThrasher.java b/core/tests/coretests/src/android/widget/gridview/GridThrasher.java
index ad89bb6..34c19c3 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridThrasher.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridThrasher.java
@@ -16,20 +16,20 @@
package android.widget.gridview;
-import com.android.frameworks.coretests.R;
-
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
+import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.view.LayoutInflater;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.TextView;
+import com.android.frameworks.coretests.R;
+
import java.util.Random;
/**
diff --git a/core/tests/coretests/src/android/widget/gridview/touch/GridTouchSetSelectionTest.java b/core/tests/coretests/src/android/widget/gridview/touch/GridTouchSetSelectionTest.java
index ca789af..ab5fcfa 100644
--- a/core/tests/coretests/src/android/widget/gridview/touch/GridTouchSetSelectionTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/touch/GridTouchSetSelectionTest.java
@@ -17,14 +17,14 @@
package android.widget.gridview.touch;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
import android.test.TouchUtils;
import android.view.View;
import android.widget.GridView;
-
import android.widget.gridview.GridSimple;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
/**
* Tests setting the selection in touch mode
*/
diff --git a/core/tests/coretests/src/android/widget/gridview/touch/GridTouchStackFromBottomManyTest.java b/core/tests/coretests/src/android/widget/gridview/touch/GridTouchStackFromBottomManyTest.java
index 9a8d307..e312873 100644
--- a/core/tests/coretests/src/android/widget/gridview/touch/GridTouchStackFromBottomManyTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/touch/GridTouchStackFromBottomManyTest.java
@@ -16,14 +16,14 @@
package android.widget.gridview.touch;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.test.ActivityInstrumentationTestCase;
import android.test.TouchUtils;
+import android.view.View;
+import android.widget.GridView;
import android.widget.gridview.GridStackFromBottomMany;
-import android.widget.GridView;
-import android.view.View;
-import android.test.ActivityInstrumentationTestCase;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
public class GridTouchStackFromBottomManyTest extends ActivityInstrumentationTestCase<GridStackFromBottomMany> {
private GridStackFromBottomMany mActivity;
diff --git a/core/tests/coretests/src/android/widget/gridview/touch/GridTouchStackFromBottomTest.java b/core/tests/coretests/src/android/widget/gridview/touch/GridTouchStackFromBottomTest.java
index d8d4e43..c98c10a 100644
--- a/core/tests/coretests/src/android/widget/gridview/touch/GridTouchStackFromBottomTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/touch/GridTouchStackFromBottomTest.java
@@ -16,13 +16,13 @@
package android.widget.gridview.touch;
-import android.widget.gridview.GridStackFromBottom;
-import android.test.TouchUtils;
-import android.test.suitebuilder.annotation.MediumTest;
-
import android.test.ActivityInstrumentationTestCase;
-import android.widget.GridView;
+import android.test.TouchUtils;
import android.view.View;
+import android.widget.GridView;
+import android.widget.gridview.GridStackFromBottom;
+
+import androidx.test.filters.MediumTest;
public class GridTouchStackFromBottomTest extends ActivityInstrumentationTestCase<GridStackFromBottom> {
private GridStackFromBottom mActivity;
diff --git a/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingStackFromBottomTest.java b/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingStackFromBottomTest.java
index 55a66d9..0d3092c 100644
--- a/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingStackFromBottomTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingStackFromBottomTest.java
@@ -18,16 +18,16 @@
import android.content.Context;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
import android.test.TouchUtils;
import android.view.Gravity;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.GridView;
-
import android.widget.gridview.GridVerticalSpacingStackFromBottom;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
public class GridTouchVerticalSpacingStackFromBottomTest extends ActivityInstrumentationTestCase<GridVerticalSpacingStackFromBottom> {
private GridVerticalSpacingStackFromBottom mActivity;
private GridView mGridView;
diff --git a/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingTest.java b/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingTest.java
index bae4ee7..e831e62 100644
--- a/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingTest.java
@@ -17,16 +17,16 @@
package android.widget.gridview.touch;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
import android.test.TouchUtils;
import android.view.Gravity;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.GridView;
-
import android.widget.gridview.GridVerticalSpacing;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
public class GridTouchVerticalSpacingTest extends ActivityInstrumentationTestCase<GridVerticalSpacing> {
private GridVerticalSpacing mActivity;
private GridView mGridView;
diff --git a/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutGravity.java b/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutGravity.java
index 9791e36..d159be8 100644
--- a/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutGravity.java
+++ b/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutGravity.java
@@ -16,11 +16,10 @@
package android.widget.layout.frame;
-import com.android.frameworks.coretests.R;
-
import android.app.Activity;
import android.os.Bundle;
-import android.view.View;
+
+import com.android.frameworks.coretests.R;
public class FrameLayoutGravity extends Activity {
@Override
diff --git a/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutGravityTest.java b/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutGravityTest.java
index fe4e932..0cab660 100644
--- a/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutGravityTest.java
+++ b/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutGravityTest.java
@@ -16,12 +16,13 @@
package android.widget.layout.frame;
-import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.ViewAsserts;
import android.app.Activity;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.ViewAsserts;
import android.view.View;
-import android.widget.layout.frame.FrameLayoutGravity;
+
+import androidx.test.filters.MediumTest;
+
import com.android.frameworks.coretests.R;
public class FrameLayoutGravityTest extends ActivityInstrumentationTestCase<FrameLayoutGravity> {
diff --git a/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutMargin.java b/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutMargin.java
index 81b3ea1..8c54557 100644
--- a/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutMargin.java
+++ b/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutMargin.java
@@ -16,11 +16,10 @@
package android.widget.layout.frame;
-import com.android.frameworks.coretests.R;
-
import android.app.Activity;
import android.os.Bundle;
-import android.view.View;
+
+import com.android.frameworks.coretests.R;
public class FrameLayoutMargin extends Activity {
@Override
diff --git a/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutMarginTest.java b/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutMarginTest.java
index c052d65..4973078 100644
--- a/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutMarginTest.java
+++ b/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutMarginTest.java
@@ -16,13 +16,14 @@
package android.widget.layout.frame;
-import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.ViewAsserts;
import android.app.Activity;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.ViewAsserts;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.layout.frame.FrameLayoutMargin;
+
+import androidx.test.filters.MediumTest;
+
import com.android.frameworks.coretests.R;
public class FrameLayoutMarginTest extends ActivityInstrumentationTestCase<FrameLayoutMargin> {
diff --git a/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentCenterGravity.java b/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentCenterGravity.java
index 766dd0a..79a34e5 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentCenterGravity.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentCenterGravity.java
@@ -16,11 +16,10 @@
package android.widget.layout.linear;
-import com.android.frameworks.coretests.R;
-
import android.app.Activity;
import android.os.Bundle;
-import android.view.View;
+
+import com.android.frameworks.coretests.R;
public class BaselineAlignmentCenterGravity extends Activity {
@Override
diff --git a/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentCenterGravityTest.java b/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentCenterGravityTest.java
index 079e9d0..60b7c2f 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentCenterGravityTest.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentCenterGravityTest.java
@@ -18,13 +18,13 @@
import android.app.Activity;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
import android.test.ViewAsserts;
import android.view.View;
import android.widget.Button;
+import androidx.test.filters.MediumTest;
+
import com.android.frameworks.coretests.R;
-import android.widget.layout.linear.BaselineAlignmentCenterGravity;
public class BaselineAlignmentCenterGravityTest extends ActivityInstrumentationTestCase<BaselineAlignmentCenterGravity> {
private Button mButton1;
diff --git a/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentSpinnerButton.java b/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentSpinnerButton.java
index c3bfe3a..a429b75 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentSpinnerButton.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentSpinnerButton.java
@@ -18,12 +18,12 @@
import android.app.Activity;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
import android.test.ViewAsserts;
import android.view.View;
+import androidx.test.filters.MediumTest;
+
import com.android.frameworks.coretests.R;
-import android.widget.layout.linear.HorizontalOrientationVerticalAlignment;
public class BaselineAlignmentSpinnerButton extends ActivityInstrumentationTestCase<HorizontalOrientationVerticalAlignment> {
private View mSpinner;
diff --git a/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentZeroWidthAndWeight.java b/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentZeroWidthAndWeight.java
index 5ed5e71..f33feb0 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentZeroWidthAndWeight.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentZeroWidthAndWeight.java
@@ -16,12 +16,12 @@
package android.widget.layout.linear;
-import com.android.frameworks.coretests.R;
-
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
+import com.android.frameworks.coretests.R;
+
public class BaselineAlignmentZeroWidthAndWeight extends Activity {
@Override
protected void onCreate(Bundle icicle) {
diff --git a/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentZeroWidthAndWeightTest.java b/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentZeroWidthAndWeightTest.java
index 2dd2bb8..443b0f7 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentZeroWidthAndWeightTest.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentZeroWidthAndWeightTest.java
@@ -16,16 +16,15 @@
package android.widget.layout.linear;
-import com.android.frameworks.coretests.R;
-import android.widget.layout.linear.BaselineAlignmentZeroWidthAndWeight;
-import android.widget.layout.linear.ExceptionTextView;
-
import android.app.Activity;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
import android.view.KeyEvent;
import android.widget.Button;
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
+
public class BaselineAlignmentZeroWidthAndWeightTest extends ActivityInstrumentationTestCase<BaselineAlignmentZeroWidthAndWeight> {
private Button mShowButton;
diff --git a/core/tests/coretests/src/android/widget/layout/linear/BaselineButtons.java b/core/tests/coretests/src/android/widget/layout/linear/BaselineButtons.java
index c9ad831..9d91316 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/BaselineButtons.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/BaselineButtons.java
@@ -16,11 +16,10 @@
package android.widget.layout.linear;
-import com.android.frameworks.coretests.R;
-
import android.app.Activity;
import android.os.Bundle;
-import android.view.View;
+
+import com.android.frameworks.coretests.R;
public class BaselineButtons extends Activity {
@Override
diff --git a/core/tests/coretests/src/android/widget/layout/linear/BaselineButtonsTest.java b/core/tests/coretests/src/android/widget/layout/linear/BaselineButtonsTest.java
index 6f1fc90..ac3c5d8 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/BaselineButtonsTest.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/BaselineButtonsTest.java
@@ -18,12 +18,12 @@
import android.app.Activity;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
import android.view.View;
import android.widget.ImageButton;
+import androidx.test.filters.MediumTest;
+
import com.android.frameworks.coretests.R;
-import android.widget.layout.linear.BaselineButtons;
public class BaselineButtonsTest extends ActivityInstrumentationTestCase<BaselineButtons> {
private View mCurrentTime;
diff --git a/core/tests/coretests/src/android/widget/layout/linear/ExceptionTextView.java b/core/tests/coretests/src/android/widget/layout/linear/ExceptionTextView.java
index 6129b5b..c684501 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/ExceptionTextView.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/ExceptionTextView.java
@@ -21,7 +21,6 @@
import android.util.AttributeSet;
import android.widget.EditText;
-
/**
* A special EditText that sets {@link #isFailed()} to true as its internal makeNewLayout() method is called
* with a width lower than 0. This is used to fail the unit test in
diff --git a/core/tests/coretests/src/android/widget/layout/linear/FillInWrap.java b/core/tests/coretests/src/android/widget/layout/linear/FillInWrap.java
index 50aa5b7..c8a5f34 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/FillInWrap.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/FillInWrap.java
@@ -16,12 +16,12 @@
package android.widget.layout.linear;
-import com.android.frameworks.coretests.R;
-
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
+import com.android.frameworks.coretests.R;
+
public class FillInWrap extends Activity {
@Override
protected void onCreate(Bundle icicle) {
diff --git a/core/tests/coretests/src/android/widget/layout/linear/FillInWrapTest.java b/core/tests/coretests/src/android/widget/layout/linear/FillInWrapTest.java
index f161802..0e69efc 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/FillInWrapTest.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/FillInWrapTest.java
@@ -18,9 +18,10 @@
import android.app.Activity;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
import android.view.View;
+import androidx.test.filters.MediumTest;
+
import com.android.frameworks.coretests.R;
public class FillInWrapTest extends ActivityInstrumentationTestCase<FillInWrap> {
diff --git a/core/tests/coretests/src/android/widget/layout/linear/HorizontalOrientationVerticalAlignment.java b/core/tests/coretests/src/android/widget/layout/linear/HorizontalOrientationVerticalAlignment.java
index 9f937a9..255f7b3 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/HorizontalOrientationVerticalAlignment.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/HorizontalOrientationVerticalAlignment.java
@@ -16,11 +16,10 @@
package android.widget.layout.linear;
-import com.android.frameworks.coretests.R;
-
import android.app.Activity;
import android.os.Bundle;
-import android.view.View;
+
+import com.android.frameworks.coretests.R;
public class HorizontalOrientationVerticalAlignment extends Activity {
@Override
diff --git a/core/tests/coretests/src/android/widget/layout/linear/LLEditTextThenButton.java b/core/tests/coretests/src/android/widget/layout/linear/LLEditTextThenButton.java
index 83331ca..a0745dd 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/LLEditTextThenButton.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/LLEditTextThenButton.java
@@ -16,14 +16,14 @@
package android.widget.layout.linear;
-import com.android.frameworks.coretests.R;
-
import android.app.Activity;
import android.os.Bundle;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
+import com.android.frameworks.coretests.R;
+
public class LLEditTextThenButton extends Activity {
private EditText mEditText;
private Button mButton;
diff --git a/core/tests/coretests/src/android/widget/layout/linear/LLOfButtons1.java b/core/tests/coretests/src/android/widget/layout/linear/LLOfButtons1.java
index ab2f060..1153062 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/LLOfButtons1.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/LLOfButtons1.java
@@ -18,10 +18,10 @@
import android.app.Activity;
import android.os.Bundle;
-import android.os.RemoteException;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
+
import com.android.frameworks.coretests.R;
/**
diff --git a/core/tests/coretests/src/android/widget/layout/linear/LLOfButtons2.java b/core/tests/coretests/src/android/widget/layout/linear/LLOfButtons2.java
index 77f564d..0aca699 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/LLOfButtons2.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/LLOfButtons2.java
@@ -22,5 +22,4 @@
*/
public class LLOfButtons2 extends LLOfButtons1 {
-
}
diff --git a/core/tests/coretests/src/android/widget/layout/linear/LinearLayoutEditTexts.java b/core/tests/coretests/src/android/widget/layout/linear/LinearLayoutEditTexts.java
index 90db788..5d37245 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/LinearLayoutEditTexts.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/LinearLayoutEditTexts.java
@@ -16,11 +16,11 @@
package android.widget.layout.linear;
-import com.android.frameworks.coretests.R;
-
import android.app.Activity;
import android.os.Bundle;
+import com.android.frameworks.coretests.R;
+
public class LinearLayoutEditTexts extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
diff --git a/core/tests/coretests/src/android/widget/layout/linear/LinearLayoutEditTextsTest.java b/core/tests/coretests/src/android/widget/layout/linear/LinearLayoutEditTextsTest.java
index d5998b7..966ed6d 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/LinearLayoutEditTextsTest.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/LinearLayoutEditTextsTest.java
@@ -16,13 +16,13 @@
package android.widget.layout.linear;
-import android.widget.layout.linear.LinearLayoutEditTexts;
-import com.android.frameworks.coretests.R;
-
-import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.view.View;
import android.app.Activity;
+import android.test.ActivityInstrumentationTestCase;
+import android.view.View;
+
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
public class LinearLayoutEditTextsTest extends ActivityInstrumentationTestCase<LinearLayoutEditTexts> {
private View mChild;
diff --git a/core/tests/coretests/src/android/widget/layout/linear/Weight.java b/core/tests/coretests/src/android/widget/layout/linear/Weight.java
index 20edd7c..3722a14f 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/Weight.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/Weight.java
@@ -16,11 +16,11 @@
package android.widget.layout.linear;
-import com.android.frameworks.coretests.R;
-
import android.app.Activity;
import android.os.Bundle;
+import com.android.frameworks.coretests.R;
+
public class Weight extends Activity {
@Override
protected void onCreate(Bundle icicle) {
diff --git a/core/tests/coretests/src/android/widget/layout/linear/WeightSum.java b/core/tests/coretests/src/android/widget/layout/linear/WeightSum.java
index 2e421da..144600b 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/WeightSum.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/WeightSum.java
@@ -16,11 +16,10 @@
package android.widget.layout.linear;
-import com.android.frameworks.coretests.R;
-
import android.app.Activity;
import android.os.Bundle;
-import android.view.View;
+
+import com.android.frameworks.coretests.R;
public class WeightSum extends Activity {
@Override
diff --git a/core/tests/coretests/src/android/widget/layout/linear/WeightSumTest.java b/core/tests/coretests/src/android/widget/layout/linear/WeightSumTest.java
index f9a94ce..1d07db2 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/WeightSumTest.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/WeightSumTest.java
@@ -18,11 +18,11 @@
import android.app.Activity;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
import android.view.View;
+import androidx.test.filters.MediumTest;
+
import com.android.frameworks.coretests.R;
-import android.widget.layout.linear.WeightSum;
public class WeightSumTest extends ActivityInstrumentationTestCase<WeightSum> {
private View mChild;
diff --git a/core/tests/coretests/src/android/widget/layout/linear/WeightTest.java b/core/tests/coretests/src/android/widget/layout/linear/WeightTest.java
index 1c42e7c..db52495 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/WeightTest.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/WeightTest.java
@@ -18,13 +18,13 @@
import android.app.Activity;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
import android.test.ViewAsserts;
-import android.test.suitebuilder.annotation.Suppress;
import android.view.View;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
import com.android.frameworks.coretests.R;
-import android.widget.layout.linear.Weight;
@Suppress // Failing.
public class WeightTest extends ActivityInstrumentationTestCase<Weight> {
diff --git a/core/tests/coretests/src/android/widget/layout/table/AddColumn.java b/core/tests/coretests/src/android/widget/layout/table/AddColumn.java
index 400c32c..b407941 100644
--- a/core/tests/coretests/src/android/widget/layout/table/AddColumn.java
+++ b/core/tests/coretests/src/android/widget/layout/table/AddColumn.java
@@ -16,8 +16,6 @@
package android.widget.layout.table;
-import com.android.frameworks.coretests.R;
-
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
@@ -26,6 +24,8 @@
import android.widget.TableRow;
import android.widget.TextView;
+import com.android.frameworks.coretests.R;
+
/**
* This test adds an extra row with an extra column in the table.
*/
diff --git a/core/tests/coretests/src/android/widget/layout/table/AddColumnTest.java b/core/tests/coretests/src/android/widget/layout/table/AddColumnTest.java
index bfb4d17..08ae030 100644
--- a/core/tests/coretests/src/android/widget/layout/table/AddColumnTest.java
+++ b/core/tests/coretests/src/android/widget/layout/table/AddColumnTest.java
@@ -16,16 +16,16 @@
package android.widget.layout.table;
-import android.widget.layout.table.AddColumn;
-import com.android.frameworks.coretests.R;
-
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
import android.view.KeyEvent;
import android.widget.Button;
import android.widget.TableLayout;
import android.widget.TableRow;
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
+
/**
* {@link android.widget.layout.table.AddColumn} is
* setup to exercise the case of adding row programmatically in a table.
diff --git a/core/tests/coretests/src/android/widget/layout/table/CellSpan.java b/core/tests/coretests/src/android/widget/layout/table/CellSpan.java
index d91cf56..3102ac1 100644
--- a/core/tests/coretests/src/android/widget/layout/table/CellSpan.java
+++ b/core/tests/coretests/src/android/widget/layout/table/CellSpan.java
@@ -16,11 +16,11 @@
package android.widget.layout.table;
-import com.android.frameworks.coretests.R;
-
import android.app.Activity;
import android.os.Bundle;
+import com.android.frameworks.coretests.R;
+
/**
* Exercise table layout with cells spanning.
*/
diff --git a/core/tests/coretests/src/android/widget/layout/table/CellSpanTest.java b/core/tests/coretests/src/android/widget/layout/table/CellSpanTest.java
index 331ec45..aa8e66c 100644
--- a/core/tests/coretests/src/android/widget/layout/table/CellSpanTest.java
+++ b/core/tests/coretests/src/android/widget/layout/table/CellSpanTest.java
@@ -16,13 +16,13 @@
package android.widget.layout.table;
-import android.widget.layout.table.CellSpan;
-import com.android.frameworks.coretests.R;
-
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
import android.view.View;
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
+
/**
* {@link android.widget.layout.table.CellSpan} is
* setup to exercise tables in which cells use spanning.
diff --git a/core/tests/coretests/src/android/widget/layout/table/FixedWidth.java b/core/tests/coretests/src/android/widget/layout/table/FixedWidth.java
index 435815a4..c587f74 100644
--- a/core/tests/coretests/src/android/widget/layout/table/FixedWidth.java
+++ b/core/tests/coretests/src/android/widget/layout/table/FixedWidth.java
@@ -16,11 +16,11 @@
package android.widget.layout.table;
-import com.android.frameworks.coretests.R;
-
import android.app.Activity;
import android.os.Bundle;
+import com.android.frameworks.coretests.R;
+
/**
* Exercise table layout with cells having a fixed width and height.
*/
diff --git a/core/tests/coretests/src/android/widget/layout/table/FixedWidthTest.java b/core/tests/coretests/src/android/widget/layout/table/FixedWidthTest.java
index b20ec84..7d02453 100644
--- a/core/tests/coretests/src/android/widget/layout/table/FixedWidthTest.java
+++ b/core/tests/coretests/src/android/widget/layout/table/FixedWidthTest.java
@@ -16,13 +16,13 @@
package android.widget.layout.table;
-import android.widget.layout.table.FixedWidth;
-import com.android.frameworks.coretests.R;
-
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
import android.view.View;
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
+
/**
* {@link android.widget.layout.table.FixedWidth} is
* setup to exercise tables in which cells use fixed width and height.
diff --git a/core/tests/coretests/src/android/widget/layout/table/HorizontalGravity.java b/core/tests/coretests/src/android/widget/layout/table/HorizontalGravity.java
index 1444f60f..6f5148b 100644
--- a/core/tests/coretests/src/android/widget/layout/table/HorizontalGravity.java
+++ b/core/tests/coretests/src/android/widget/layout/table/HorizontalGravity.java
@@ -16,11 +16,11 @@
package android.widget.layout.table;
-import com.android.frameworks.coretests.R;
-
import android.app.Activity;
import android.os.Bundle;
+import com.android.frameworks.coretests.R;
+
/**
* Exercise table layout with cells using a horizontal gravity.
*/
diff --git a/core/tests/coretests/src/android/widget/layout/table/HorizontalGravityTest.java b/core/tests/coretests/src/android/widget/layout/table/HorizontalGravityTest.java
index 964df82..73e8334 100644
--- a/core/tests/coretests/src/android/widget/layout/table/HorizontalGravityTest.java
+++ b/core/tests/coretests/src/android/widget/layout/table/HorizontalGravityTest.java
@@ -16,14 +16,14 @@
package android.widget.layout.table;
-import android.widget.layout.table.HorizontalGravity;
-import com.android.frameworks.coretests.R;
-
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
import android.test.ViewAsserts;
import android.view.View;
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
+
/**
* {@link android.widget.layout.table.HorizontalGravity} is
* setup to exercise tables in which cells use horizontal gravity.
diff --git a/core/tests/coretests/src/android/widget/layout/table/VerticalGravity.java b/core/tests/coretests/src/android/widget/layout/table/VerticalGravity.java
index 4fdb378..9055b32 100644
--- a/core/tests/coretests/src/android/widget/layout/table/VerticalGravity.java
+++ b/core/tests/coretests/src/android/widget/layout/table/VerticalGravity.java
@@ -16,11 +16,11 @@
package android.widget.layout.table;
-import com.android.frameworks.coretests.R;
-
import android.app.Activity;
import android.os.Bundle;
+import com.android.frameworks.coretests.R;
+
/**
* Exercise table layout with cells using a vertical gravity.
*/
diff --git a/core/tests/coretests/src/android/widget/layout/table/VerticalGravityTest.java b/core/tests/coretests/src/android/widget/layout/table/VerticalGravityTest.java
index 1d6be3f..f14fa1c 100644
--- a/core/tests/coretests/src/android/widget/layout/table/VerticalGravityTest.java
+++ b/core/tests/coretests/src/android/widget/layout/table/VerticalGravityTest.java
@@ -16,15 +16,15 @@
package android.widget.layout.table;
-import android.widget.layout.table.VerticalGravity;
-import com.android.frameworks.coretests.R;
-
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
import android.test.ViewAsserts;
import android.view.View;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
+import com.android.frameworks.coretests.R;
+
/**
* {@link android.widget.layout.table.VerticalGravity} is
* setup to exercise tables in which cells use vertical gravity.
diff --git a/core/tests/coretests/src/android/widget/layout/table/Weight.java b/core/tests/coretests/src/android/widget/layout/table/Weight.java
index 6d4d51d..5c08247 100644
--- a/core/tests/coretests/src/android/widget/layout/table/Weight.java
+++ b/core/tests/coretests/src/android/widget/layout/table/Weight.java
@@ -16,11 +16,11 @@
package android.widget.layout.table;
-import com.android.frameworks.coretests.R;
-
import android.app.Activity;
import android.os.Bundle;
+import com.android.frameworks.coretests.R;
+
/**
* Exercise table layout with cells having a weight.
*/
diff --git a/core/tests/coretests/src/android/widget/layout/table/WeightTest.java b/core/tests/coretests/src/android/widget/layout/table/WeightTest.java
index b665573..fcf3de2 100644
--- a/core/tests/coretests/src/android/widget/layout/table/WeightTest.java
+++ b/core/tests/coretests/src/android/widget/layout/table/WeightTest.java
@@ -16,13 +16,13 @@
package android.widget.layout.table;
-import android.widget.layout.table.Weight;
-import com.android.frameworks.coretests.R;
-
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
import android.view.View;
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
+
/**
* {@link android.widget.layout.table.Weight} is
* setup to exercise tables in which cells use a weight.
diff --git a/core/tests/coretests/src/android/widget/listview/ListBottomGravity.java b/core/tests/coretests/src/android/widget/listview/ListBottomGravity.java
index a386ebd..cd76d70 100644
--- a/core/tests/coretests/src/android/widget/listview/ListBottomGravity.java
+++ b/core/tests/coretests/src/android/widget/listview/ListBottomGravity.java
@@ -16,8 +16,6 @@
package android.widget.listview;
-import android.view.Gravity;
-
import android.util.ListScenario;
/**
diff --git a/core/tests/coretests/src/android/widget/listview/ListBottomGravityMany.java b/core/tests/coretests/src/android/widget/listview/ListBottomGravityMany.java
index 519816c..e048e3e 100644
--- a/core/tests/coretests/src/android/widget/listview/ListBottomGravityMany.java
+++ b/core/tests/coretests/src/android/widget/listview/ListBottomGravityMany.java
@@ -16,8 +16,6 @@
package android.widget.listview;
-import android.view.Gravity;
-
import android.util.ListScenario;
/**
diff --git a/core/tests/coretests/src/android/widget/listview/ListBottomGravityManyTest.java b/core/tests/coretests/src/android/widget/listview/ListBottomGravityManyTest.java
index e1171eb..bd8dbe4 100644
--- a/core/tests/coretests/src/android/widget/listview/ListBottomGravityManyTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListBottomGravityManyTest.java
@@ -17,10 +17,9 @@
package android.widget.listview;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
import android.widget.ListView;
-import android.widget.listview.ListBottomGravityMany;
+import androidx.test.filters.MediumTest;
public class ListBottomGravityManyTest extends ActivityInstrumentationTestCase<ListBottomGravityMany> {
private ListBottomGravityMany mActivity;
diff --git a/core/tests/coretests/src/android/widget/listview/ListBottomGravityTest.java b/core/tests/coretests/src/android/widget/listview/ListBottomGravityTest.java
index c595f62..8da7358 100644
--- a/core/tests/coretests/src/android/widget/listview/ListBottomGravityTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListBottomGravityTest.java
@@ -17,10 +17,9 @@
package android.widget.listview;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
import android.widget.ListView;
-import android.widget.listview.ListBottomGravity;
+import androidx.test.filters.MediumTest;
public class ListBottomGravityTest extends ActivityInstrumentationTestCase<ListBottomGravity> {
private ListBottomGravity mActivity;
diff --git a/core/tests/coretests/src/android/widget/listview/ListButtonsDiagonalAcrossItems.java b/core/tests/coretests/src/android/widget/listview/ListButtonsDiagonalAcrossItems.java
index bbed73c..8640741 100644
--- a/core/tests/coretests/src/android/widget/listview/ListButtonsDiagonalAcrossItems.java
+++ b/core/tests/coretests/src/android/widget/listview/ListButtonsDiagonalAcrossItems.java
@@ -16,10 +16,10 @@
package android.widget.listview;
-import android.util.ListItemFactory;
import static android.util.ListItemFactory.Slot;
-import android.util.ListScenario;
+import android.util.ListItemFactory;
+import android.util.ListScenario;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
diff --git a/core/tests/coretests/src/android/widget/listview/ListEmptyViewTest.java b/core/tests/coretests/src/android/widget/listview/ListEmptyViewTest.java
index 258d3ef..81d71a9 100644
--- a/core/tests/coretests/src/android/widget/listview/ListEmptyViewTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListEmptyViewTest.java
@@ -19,12 +19,13 @@
import android.app.Instrumentation;
import android.content.Intent;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
import android.view.KeyEvent;
import android.view.View;
import android.widget.ListView;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
public class ListEmptyViewTest extends ActivityInstrumentationTestCase<ListWithEmptyView> {
private ListWithEmptyView mActivity;
private ListView mListView;
diff --git a/core/tests/coretests/src/android/widget/listview/ListFilter.java b/core/tests/coretests/src/android/widget/listview/ListFilter.java
index c2ac90e..1cda717 100644
--- a/core/tests/coretests/src/android/widget/listview/ListFilter.java
+++ b/core/tests/coretests/src/android/widget/listview/ListFilter.java
@@ -25,7 +25,6 @@
import com.android.frameworks.coretests.R;
-
/**
* Tests hiding and showing the list filter by hiding and showing an ancestor of the
* ListView
diff --git a/core/tests/coretests/src/android/widget/listview/ListFocusableTest.java b/core/tests/coretests/src/android/widget/listview/ListFocusableTest.java
index bf18a13..10b4a79 100644
--- a/core/tests/coretests/src/android/widget/listview/ListFocusableTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListFocusableTest.java
@@ -17,10 +17,11 @@
package android.widget.listview;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.widget.ListView;
-import android.widget.ListAdapter;
import android.widget.ArrayAdapter;
+import android.widget.ListAdapter;
+import android.widget.ListView;
+
+import androidx.test.filters.MediumTest;
public class ListFocusableTest extends ActivityInstrumentationTestCase<ListTopGravity> {
private ListTopGravity mActivity;
diff --git a/core/tests/coretests/src/android/widget/listview/ListGetCheckItemIdsTest.java b/core/tests/coretests/src/android/widget/listview/ListGetCheckItemIdsTest.java
index 33d61a0..c691ed7 100644
--- a/core/tests/coretests/src/android/widget/listview/ListGetCheckItemIdsTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListGetCheckItemIdsTest.java
@@ -17,10 +17,11 @@
package android.widget.listview;
import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.test.suitebuilder.annotation.MediumTest;
import android.widget.ListView;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.MediumTest;
+
import java.util.Arrays;
/**
diff --git a/core/tests/coretests/src/android/widget/listview/ListHeterogeneous.java b/core/tests/coretests/src/android/widget/listview/ListHeterogeneous.java
index 1f59c30..74eda3b 100644
--- a/core/tests/coretests/src/android/widget/listview/ListHeterogeneous.java
+++ b/core/tests/coretests/src/android/widget/listview/ListHeterogeneous.java
@@ -16,11 +16,10 @@
package android.widget.listview;
-import android.view.View;
-import android.view.ViewGroup;
-
import android.util.ListItemFactory;
import android.util.ListScenario;
+import android.view.View;
+import android.view.ViewGroup;
/**
* List that has different view types
diff --git a/core/tests/coretests/src/android/widget/listview/ListHeterogeneousTest.java b/core/tests/coretests/src/android/widget/listview/ListHeterogeneousTest.java
index 01b39db..dbd58d7 100644
--- a/core/tests/coretests/src/android/widget/listview/ListHeterogeneousTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListHeterogeneousTest.java
@@ -18,12 +18,11 @@
import android.app.Instrumentation;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
import android.view.KeyEvent;
import android.widget.ListView;
-import android.widget.listview.ListHeterogeneous;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
public class ListHeterogeneousTest extends ActivityInstrumentationTestCase<ListHeterogeneous> {
private ListHeterogeneous mActivity;
diff --git a/core/tests/coretests/src/android/widget/listview/ListHorizontalFocusWithinItemWins.java b/core/tests/coretests/src/android/widget/listview/ListHorizontalFocusWithinItemWins.java
index 2ff65de..e98de9c 100644
--- a/core/tests/coretests/src/android/widget/listview/ListHorizontalFocusWithinItemWins.java
+++ b/core/tests/coretests/src/android/widget/listview/ListHorizontalFocusWithinItemWins.java
@@ -16,11 +16,11 @@
package android.widget.listview;
-import android.util.ListItemFactory;
import static android.util.ListItemFactory.Slot;
-import android.util.ListScenario;
import android.content.Context;
+import android.util.ListItemFactory;
+import android.util.ListScenario;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
diff --git a/core/tests/coretests/src/android/widget/listview/ListInHorizontal.java b/core/tests/coretests/src/android/widget/listview/ListInHorizontal.java
index a373a5b..6622c0d 100644
--- a/core/tests/coretests/src/android/widget/listview/ListInHorizontal.java
+++ b/core/tests/coretests/src/android/widget/listview/ListInHorizontal.java
@@ -18,10 +18,7 @@
import android.app.Activity;
import android.os.Bundle;
-import android.os.Handler;
import android.widget.ArrayAdapter;
-import android.widget.GridView;
-import android.widget.TextView;
import android.widget.ListView;
import com.android.frameworks.coretests.R;
diff --git a/core/tests/coretests/src/android/widget/listview/ListInHorizontalTest.java b/core/tests/coretests/src/android/widget/listview/ListInHorizontalTest.java
index 3643f79..d8508ec 100644
--- a/core/tests/coretests/src/android/widget/listview/ListInHorizontalTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListInHorizontalTest.java
@@ -16,8 +16,6 @@
package android.widget.listview;
-import android.widget.listview.ListInHorizontal;
-
public class ListInHorizontalTest extends ListUnspecifiedMeasure<ListInHorizontal> {
public ListInHorizontalTest() {
super(ListInHorizontal.class);
diff --git a/core/tests/coretests/src/android/widget/listview/ListInVertical.java b/core/tests/coretests/src/android/widget/listview/ListInVertical.java
index 3b4885a..4ecf25d 100644
--- a/core/tests/coretests/src/android/widget/listview/ListInVertical.java
+++ b/core/tests/coretests/src/android/widget/listview/ListInVertical.java
@@ -18,10 +18,7 @@
import android.app.Activity;
import android.os.Bundle;
-import android.os.Handler;
import android.widget.ArrayAdapter;
-import android.widget.GridView;
-import android.widget.TextView;
import android.widget.ListView;
import com.android.frameworks.coretests.R;
diff --git a/core/tests/coretests/src/android/widget/listview/ListInVerticalTest.java b/core/tests/coretests/src/android/widget/listview/ListInVerticalTest.java
index 8586429..5e385a3 100644
--- a/core/tests/coretests/src/android/widget/listview/ListInVerticalTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListInVerticalTest.java
@@ -16,8 +16,6 @@
package android.widget.listview;
-import android.widget.listview.ListInVertical;
-
public class ListInVerticalTest extends ListUnspecifiedMeasure<ListInVertical> {
public ListInVerticalTest() {
super(ListInVertical.class);
diff --git a/core/tests/coretests/src/android/widget/listview/ListInterleaveFocusables.java b/core/tests/coretests/src/android/widget/listview/ListInterleaveFocusables.java
index d5da28e..0ec7a24 100644
--- a/core/tests/coretests/src/android/widget/listview/ListInterleaveFocusables.java
+++ b/core/tests/coretests/src/android/widget/listview/ListInterleaveFocusables.java
@@ -16,13 +16,14 @@
package android.widget.listview;
+import android.util.ListItemFactory;
+import android.util.ListScenario;
import android.view.View;
- import android.view.ViewGroup;
- import com.google.android.collect.Sets;
- import android.util.ListScenario;
- import android.util.ListItemFactory;
+import android.view.ViewGroup;
- import java.util.Set;
+import com.google.android.collect.Sets;
+
+import java.util.Set;
/**
* List that interleaves focusable items.
diff --git a/core/tests/coretests/src/android/widget/listview/ListItemFocusableAboveUnfocusable.java b/core/tests/coretests/src/android/widget/listview/ListItemFocusableAboveUnfocusable.java
index f7c01b1..3159e53 100644
--- a/core/tests/coretests/src/android/widget/listview/ListItemFocusableAboveUnfocusable.java
+++ b/core/tests/coretests/src/android/widget/listview/ListItemFocusableAboveUnfocusable.java
@@ -16,12 +16,10 @@
package android.widget.listview;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.TextView;
import android.util.ListItemFactory;
import android.util.ListScenario;
+import android.view.View;
+import android.view.ViewGroup;
/**
* A list where the items may befocusable, but the second item isn't actually focusabe.
diff --git a/core/tests/coretests/src/android/widget/listview/ListItemFocusablesClose.java b/core/tests/coretests/src/android/widget/listview/ListItemFocusablesClose.java
index b529b2e..861e2a91 100644
--- a/core/tests/coretests/src/android/widget/listview/ListItemFocusablesClose.java
+++ b/core/tests/coretests/src/android/widget/listview/ListItemFocusablesClose.java
@@ -16,8 +16,8 @@
package android.widget.listview;
-import android.util.ListScenario;
import android.util.ListItemFactory;
+import android.util.ListScenario;
import android.view.View;
import android.view.ViewGroup;
diff --git a/core/tests/coretests/src/android/widget/listview/ListItemFocusablesFarApart.java b/core/tests/coretests/src/android/widget/listview/ListItemFocusablesFarApart.java
index 59987ec..e9c9c1d 100644
--- a/core/tests/coretests/src/android/widget/listview/ListItemFocusablesFarApart.java
+++ b/core/tests/coretests/src/android/widget/listview/ListItemFocusablesFarApart.java
@@ -16,10 +16,10 @@
package android.widget.listview;
-import android.view.View;
-import android.view.ViewGroup;
import android.util.ListItemFactory;
import android.util.ListScenario;
+import android.view.View;
+import android.view.ViewGroup;
/**
* A list where each item is tall with buttons that are farther apart than the screen
diff --git a/core/tests/coretests/src/android/widget/listview/ListItemISVAndButton.java b/core/tests/coretests/src/android/widget/listview/ListItemISVAndButton.java
index ea2c5f2..2a0e013 100644
--- a/core/tests/coretests/src/android/widget/listview/ListItemISVAndButton.java
+++ b/core/tests/coretests/src/android/widget/listview/ListItemISVAndButton.java
@@ -17,13 +17,13 @@
package android.widget.listview;
import android.content.Context;
+import android.util.InternalSelectionView;
+import android.util.ListScenario;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
-import android.util.InternalSelectionView;
-import android.util.ListScenario;
/**
* Each item is an internal selection view, a button, and some filler
diff --git a/core/tests/coretests/src/android/widget/listview/ListItemRequestRectAboveThinFirstItemTest.java b/core/tests/coretests/src/android/widget/listview/ListItemRequestRectAboveThinFirstItemTest.java
index 73eb0a8..91ff06b 100644
--- a/core/tests/coretests/src/android/widget/listview/ListItemRequestRectAboveThinFirstItemTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListItemRequestRectAboveThinFirstItemTest.java
@@ -18,13 +18,13 @@
import android.graphics.Rect;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
-import android.view.View;
import android.view.KeyEvent;
+import android.view.View;
import android.widget.ListView;
-import android.widget.listview.ListOfThinItems;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
public class ListItemRequestRectAboveThinFirstItemTest
extends ActivityInstrumentationTestCase<ListOfThinItems> {
diff --git a/core/tests/coretests/src/android/widget/listview/ListItemsExpandOnSelection.java b/core/tests/coretests/src/android/widget/listview/ListItemsExpandOnSelection.java
index a5fe17a..d80fd90 100644
--- a/core/tests/coretests/src/android/widget/listview/ListItemsExpandOnSelection.java
+++ b/core/tests/coretests/src/android/widget/listview/ListItemsExpandOnSelection.java
@@ -17,13 +17,12 @@
package android.widget.listview;
import android.content.Context;
+import android.util.ListScenario;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.TextView;
-import android.util.ListScenario;
-
/**
* A list where each item expands by 1.5 when selected.
*/
diff --git a/core/tests/coretests/src/android/widget/listview/ListManagedCursor.java b/core/tests/coretests/src/android/widget/listview/ListManagedCursor.java
index 12b5ef4..54f302c 100644
--- a/core/tests/coretests/src/android/widget/listview/ListManagedCursor.java
+++ b/core/tests/coretests/src/android/widget/listview/ListManagedCursor.java
@@ -20,14 +20,13 @@
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
-import android.provider.Settings;
import android.provider.Contacts.People;
+import android.provider.Settings;
import android.view.View;
import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListAdapter;
import android.widget.SimpleCursorAdapter;
-import android.widget.AdapterView.OnItemClickListener;
-
public class ListManagedCursor extends ListActivity implements OnItemClickListener {
diff --git a/core/tests/coretests/src/android/widget/listview/ListManagedCursorTest.java b/core/tests/coretests/src/android/widget/listview/ListManagedCursorTest.java
index bc3776c..8e0b6fe 100644
--- a/core/tests/coretests/src/android/widget/listview/ListManagedCursorTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListManagedCursorTest.java
@@ -18,11 +18,12 @@
import android.app.Instrumentation;
import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.test.TouchUtils;
import android.view.KeyEvent;
import android.widget.ListView;
-import android.test.TouchUtils;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
/**
* Tests restoring the scroll position in a list with a managed cursor.
diff --git a/core/tests/coretests/src/android/widget/listview/ListOfTouchables.java b/core/tests/coretests/src/android/widget/listview/ListOfTouchables.java
index 919ef69..70b9081 100644
--- a/core/tests/coretests/src/android/widget/listview/ListOfTouchables.java
+++ b/core/tests/coretests/src/android/widget/listview/ListOfTouchables.java
@@ -16,12 +16,11 @@
package android.widget.listview;
+import android.util.ListScenario;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
-import android.util.ListScenario;
-
/**
* Each list item has two focusables that are close enough together that
* it shouldn't require panning to move focus.
diff --git a/core/tests/coretests/src/android/widget/listview/ListRecyclerProfiling.java b/core/tests/coretests/src/android/widget/listview/ListRecyclerProfiling.java
index 76814fb..075712e 100644
--- a/core/tests/coretests/src/android/widget/listview/ListRecyclerProfiling.java
+++ b/core/tests/coretests/src/android/widget/listview/ListRecyclerProfiling.java
@@ -18,11 +18,11 @@
import android.app.Activity;
import android.os.Bundle;
-import android.widget.ArrayAdapter;
-import android.widget.ListView;
-import android.widget.ImageButton;
-import android.view.ViewDebug;
import android.view.View;
+import android.view.ViewDebug;
+import android.widget.ArrayAdapter;
+import android.widget.ImageButton;
+import android.widget.ListView;
import com.android.frameworks.coretests.R;
diff --git a/core/tests/coretests/src/android/widget/listview/ListRetainsFocusAcrossLayoutsTest.java b/core/tests/coretests/src/android/widget/listview/ListRetainsFocusAcrossLayoutsTest.java
index 896bd19..be14de8 100644
--- a/core/tests/coretests/src/android/widget/listview/ListRetainsFocusAcrossLayoutsTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListRetainsFocusAcrossLayoutsTest.java
@@ -16,12 +16,11 @@
package android.widget.listview;
-import android.widget.listview.ListItemFocusablesClose;
-
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
import android.view.KeyEvent;
+import androidx.test.filters.MediumTest;
+
public class ListRetainsFocusAcrossLayoutsTest extends ActivityInstrumentationTestCase<ListItemFocusablesClose> {
public ListRetainsFocusAcrossLayoutsTest() {
diff --git a/core/tests/coretests/src/android/widget/listview/ListScrollListenerTest.java b/core/tests/coretests/src/android/widget/listview/ListScrollListenerTest.java
index 7b29a66..28addd6 100644
--- a/core/tests/coretests/src/android/widget/listview/ListScrollListenerTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListScrollListenerTest.java
@@ -19,12 +19,13 @@
import android.app.Instrumentation;
import android.test.ActivityInstrumentationTestCase;
import android.test.TouchUtils;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
import android.view.KeyEvent;
import android.widget.AbsListView;
import android.widget.ListView;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
public class ListScrollListenerTest extends ActivityInstrumentationTestCase<ListScrollListener> implements
AbsListView.OnScrollListener {
private ListScrollListener mActivity;
diff --git a/core/tests/coretests/src/android/widget/listview/ListSetSelection.java b/core/tests/coretests/src/android/widget/listview/ListSetSelection.java
index 6c2e264..af8e899 100644
--- a/core/tests/coretests/src/android/widget/listview/ListSetSelection.java
+++ b/core/tests/coretests/src/android/widget/listview/ListSetSelection.java
@@ -16,12 +16,12 @@
package android.widget.listview;
+import android.os.Bundle;
import android.util.ListScenario;
import android.view.KeyEvent;
import android.view.View;
-import android.os.Bundle;
-import android.widget.LinearLayout;
import android.widget.Button;
+import android.widget.LinearLayout;
/**
* List of 1,000 items used to test calls to setSelection() in touch mode.
diff --git a/core/tests/coretests/src/android/widget/listview/ListSetSelectionTest.java b/core/tests/coretests/src/android/widget/listview/ListSetSelectionTest.java
index 4cef164..2caca13 100644
--- a/core/tests/coretests/src/android/widget/listview/ListSetSelectionTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListSetSelectionTest.java
@@ -17,10 +17,11 @@
package android.widget.listview;
import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.test.suitebuilder.annotation.MediumTest;
import android.widget.ListView;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.MediumTest;
+
/**
* Basic tests of setting & clearing the selection
*/
diff --git a/core/tests/coretests/src/android/widget/listview/ListSimple.java b/core/tests/coretests/src/android/widget/listview/ListSimple.java
index 6accae1..f53638e 100644
--- a/core/tests/coretests/src/android/widget/listview/ListSimple.java
+++ b/core/tests/coretests/src/android/widget/listview/ListSimple.java
@@ -16,11 +16,10 @@
package android.widget.listview;
+import android.os.Bundle;
import android.util.ListScenario;
-
import android.view.View;
import android.view.ViewGroup;
-import android.os.Bundle;
import android.widget.TextView;
public class ListSimple extends ListScenario {
diff --git a/core/tests/coretests/src/android/widget/listview/ListTakeFocusFromSide.java b/core/tests/coretests/src/android/widget/listview/ListTakeFocusFromSide.java
index 95f09f6..c4e9fe9 100644
--- a/core/tests/coretests/src/android/widget/listview/ListTakeFocusFromSide.java
+++ b/core/tests/coretests/src/android/widget/listview/ListTakeFocusFromSide.java
@@ -16,17 +16,17 @@
package android.widget.listview;
-import com.android.frameworks.coretests.R;
-
import android.app.ListActivity;
import android.content.Context;
import android.os.Bundle;
+import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.view.LayoutInflater;
import android.widget.BaseAdapter;
import android.widget.TextView;
+import com.android.frameworks.coretests.R;
+
/**
* Exercises moving focus into the list from the side
*/
diff --git a/core/tests/coretests/src/android/widget/listview/ListThrasher.java b/core/tests/coretests/src/android/widget/listview/ListThrasher.java
index 0237a95..d82f68d 100644
--- a/core/tests/coretests/src/android/widget/listview/ListThrasher.java
+++ b/core/tests/coretests/src/android/widget/listview/ListThrasher.java
@@ -16,19 +16,19 @@
package android.widget.listview;
-import com.android.frameworks.coretests.R;
-
import android.app.ListActivity;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
+import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.view.LayoutInflater;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.TextView;
+import com.android.frameworks.coretests.R;
+
import java.util.Random;
/**
diff --git a/core/tests/coretests/src/android/widget/listview/ListTopGravity.java b/core/tests/coretests/src/android/widget/listview/ListTopGravity.java
index 986cc57..31339e9 100644
--- a/core/tests/coretests/src/android/widget/listview/ListTopGravity.java
+++ b/core/tests/coretests/src/android/widget/listview/ListTopGravity.java
@@ -16,8 +16,6 @@
package android.widget.listview;
-import android.view.Gravity;
-
import android.util.ListScenario;
/**
diff --git a/core/tests/coretests/src/android/widget/listview/ListUnspecifiedMeasure.java b/core/tests/coretests/src/android/widget/listview/ListUnspecifiedMeasure.java
index 199d069..0fc87ea 100644
--- a/core/tests/coretests/src/android/widget/listview/ListUnspecifiedMeasure.java
+++ b/core/tests/coretests/src/android/widget/listview/ListUnspecifiedMeasure.java
@@ -16,13 +16,14 @@
package android.widget.listview;
-import com.android.frameworks.coretests.R;
-
-import android.test.ActivityInstrumentationTestCase;
import android.app.Activity;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.test.ActivityInstrumentationTestCase;
import android.widget.ListView;
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
+
public class ListUnspecifiedMeasure<T extends Activity> extends ActivityInstrumentationTestCase<T> {
private T mActivity;
private ListView mListView;
diff --git a/core/tests/coretests/src/android/widget/listview/ListViewHeightTest.java b/core/tests/coretests/src/android/widget/listview/ListViewHeightTest.java
index 5ab2757..63941f1 100644
--- a/core/tests/coretests/src/android/widget/listview/ListViewHeightTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListViewHeightTest.java
@@ -18,12 +18,12 @@
import android.app.Instrumentation;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
import android.widget.Button;
import android.widget.ListView;
+import androidx.test.filters.MediumTest;
+
import com.android.frameworks.coretests.R;
-import android.widget.listview.ListViewHeight;
public class ListViewHeightTest extends ActivityInstrumentationTestCase<ListViewHeight> {
private ListViewHeight mActivity;
diff --git a/core/tests/coretests/src/android/widget/listview/ListWithDisappearingItemBug.java b/core/tests/coretests/src/android/widget/listview/ListWithDisappearingItemBug.java
index 348ea1b..10ba8b7 100644
--- a/core/tests/coretests/src/android/widget/listview/ListWithDisappearingItemBug.java
+++ b/core/tests/coretests/src/android/widget/listview/ListWithDisappearingItemBug.java
@@ -16,8 +16,6 @@
package android.widget.listview;
-import com.android.frameworks.coretests.R;
-
import android.app.ListActivity;
import android.database.Cursor;
import android.os.Bundle;
@@ -32,6 +30,8 @@
import android.widget.SimpleCursorAdapter;
import android.widget.Toast;
+import com.android.frameworks.coretests.R;
+
/**
* See 1080989. You need some contacts for this adapter.
*/
diff --git a/core/tests/coretests/src/android/widget/listview/ListWithEmptyView.java b/core/tests/coretests/src/android/widget/listview/ListWithEmptyView.java
index 74dd06c..52273fd 100644
--- a/core/tests/coretests/src/android/widget/listview/ListWithEmptyView.java
+++ b/core/tests/coretests/src/android/widget/listview/ListWithEmptyView.java
@@ -16,8 +16,6 @@
package android.widget.listview;
-import com.android.frameworks.coretests.R;
-
import android.app.ListActivity;
import android.content.Context;
import android.os.Bundle;
@@ -26,6 +24,8 @@
import android.view.View;
import android.widget.ArrayAdapter;
+import com.android.frameworks.coretests.R;
+
/**
* Tests using an empty view with a list */
diff --git a/core/tests/coretests/src/android/widget/listview/ListWithHeaders.java b/core/tests/coretests/src/android/widget/listview/ListWithHeaders.java
index aea091a..6030582 100644
--- a/core/tests/coretests/src/android/widget/listview/ListWithHeaders.java
+++ b/core/tests/coretests/src/android/widget/listview/ListWithHeaders.java
@@ -16,9 +16,8 @@
package android.widget.listview;
-import android.util.ListScenario;
-
import android.os.Bundle;
+import android.util.ListScenario;
import android.widget.Button;
import android.widget.ListAdapter;
import android.widget.ListView;
diff --git a/core/tests/coretests/src/android/widget/listview/ListWithOnItemSelectedAction.java b/core/tests/coretests/src/android/widget/listview/ListWithOnItemSelectedAction.java
index 26e1d5d..13e770c 100644
--- a/core/tests/coretests/src/android/widget/listview/ListWithOnItemSelectedAction.java
+++ b/core/tests/coretests/src/android/widget/listview/ListWithOnItemSelectedAction.java
@@ -16,8 +16,8 @@
package android.widget.listview;
-import android.widget.TextView;
import android.util.ListScenario;
+import android.widget.TextView;
/**
* The header text view echos the value of the selected item by using (indirectly)
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListInterleaveFocusablesTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListInterleaveFocusablesTest.java
index ec8ab7e..22c28c2 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListInterleaveFocusablesTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListInterleaveFocusablesTest.java
@@ -17,13 +17,14 @@
package android.widget.listview.arrowscroll;
import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.MediumTest;
import android.util.ListUtil;
import android.view.KeyEvent;
import android.view.View;
import android.widget.ListView;
import android.widget.listview.ListInterleaveFocusables;
+import androidx.test.filters.MediumTest;
+
public class ListInterleaveFocusablesTest extends ActivityInstrumentationTestCase2<ListInterleaveFocusables> {
private ListView mListView;
private ListUtil mListUtil;
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemFocusableAboveUnfocusableTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemFocusableAboveUnfocusableTest.java
index 82f48801..c645b7c 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemFocusableAboveUnfocusableTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemFocusableAboveUnfocusableTest.java
@@ -17,11 +17,12 @@
package android.widget.listview.arrowscroll;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.widget.ListView;
import android.view.KeyEvent;
+import android.widget.ListView;
import android.widget.listview.ListItemFocusableAboveUnfocusable;
+import androidx.test.filters.MediumTest;
+
public class ListItemFocusableAboveUnfocusableTest extends ActivityInstrumentationTestCase<ListItemFocusableAboveUnfocusable> {
private ListView mListView;
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemFocusablesCloseTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemFocusablesCloseTest.java
index 3b30ebe..c7525b3 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemFocusablesCloseTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemFocusablesCloseTest.java
@@ -17,12 +17,13 @@
package android.widget.listview.arrowscroll;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
import android.view.KeyEvent;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.listview.ListItemFocusablesClose;
+import androidx.test.filters.MediumTest;
+
public class ListItemFocusablesCloseTest extends ActivityInstrumentationTestCase<ListItemFocusablesClose> {
private ListView mListView;
private int mListTop;
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemFocusablesFarApartTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemFocusablesFarApartTest.java
index 475930d..4bb2206 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemFocusablesFarApartTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemFocusablesFarApartTest.java
@@ -17,7 +17,6 @@
package android.widget.listview.arrowscroll;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
@@ -25,6 +24,8 @@
import android.widget.ListView;
import android.widget.listview.ListItemFocusablesFarApart;
+import androidx.test.filters.MediumTest;
+
public class ListItemFocusablesFarApartTest extends ActivityInstrumentationTestCase<ListItemFocusablesFarApart> {
private ListView mListView;
private int mListTop;
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemsExpandOnSelectionTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemsExpandOnSelectionTest.java
index 91a1eba..7605291 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemsExpandOnSelectionTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemsExpandOnSelectionTest.java
@@ -17,13 +17,14 @@
package android.widget.listview.arrowscroll;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
-import android.widget.ListView;
import android.view.KeyEvent;
+import android.widget.ListView;
import android.widget.listview.ListItemsExpandOnSelection;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
public class ListItemsExpandOnSelectionTest extends ActivityInstrumentationTestCase<ListItemsExpandOnSelection> {
private ListView mListView;
private int mListTop;
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListLastItemPartiallyVisibleTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListLastItemPartiallyVisibleTest.java
index 5bc121a..fdae483 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListLastItemPartiallyVisibleTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListLastItemPartiallyVisibleTest.java
@@ -17,12 +17,13 @@
package android.widget.listview.arrowscroll;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.widget.ListView;
-import android.view.View;
import android.view.KeyEvent;
+import android.view.View;
+import android.widget.ListView;
import android.widget.listview.ListLastItemPartiallyVisible;
+import androidx.test.filters.MediumTest;
+
public class ListLastItemPartiallyVisibleTest extends ActivityInstrumentationTestCase<ListLastItemPartiallyVisible> {
private ListView mListView;
private int mListBottom;
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfItemsShorterThanScreenTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfItemsShorterThanScreenTest.java
index bda71d0..d44b130 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfItemsShorterThanScreenTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfItemsShorterThanScreenTest.java
@@ -17,14 +17,15 @@
package android.widget.listview.arrowscroll;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
import android.view.KeyEvent;
import android.view.View;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.listview.ListOfItemsShorterThanScreen;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
public class ListOfItemsShorterThanScreenTest
extends ActivityInstrumentationTestCase<ListOfItemsShorterThanScreen> {
private ListView mListView;
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfItemsTallerThanScreenTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfItemsTallerThanScreenTest.java
index 2135445..1decdad 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfItemsTallerThanScreenTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfItemsTallerThanScreenTest.java
@@ -17,13 +17,14 @@
package android.widget.listview.arrowscroll;
import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
import android.view.KeyEvent;
import android.view.View;
import android.widget.ListView;
import android.widget.listview.ListOfItemsTallerThanScreen;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
public class ListOfItemsTallerThanScreenTest
extends ActivityInstrumentationTestCase2<ListOfItemsTallerThanScreen> {
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfShortShortTallShortShortTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfShortShortTallShortShortTest.java
index ef70b5a..67808f1 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfShortShortTallShortShortTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfShortShortTallShortShortTest.java
@@ -17,13 +17,14 @@
package android.widget.listview.arrowscroll;
import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
import android.util.ListUtil;
import android.view.KeyEvent;
import android.widget.ListView;
import android.widget.listview.ListOfShortShortTallShortShort;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
public class ListOfShortShortTallShortShortTest extends ActivityInstrumentationTestCase2<ListOfShortShortTallShortShort> {
private ListView mListView;
private ListUtil mListUtil;
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfShortTallShortTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfShortTallShortTest.java
index c958591..f9aa6dc 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfShortTallShortTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfShortTallShortTest.java
@@ -17,11 +17,12 @@
package android.widget.listview.arrowscroll;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.widget.ListView;
import android.view.KeyEvent;
+import android.widget.ListView;
import android.widget.listview.ListOfShortTallShort;
+import androidx.test.filters.MediumTest;
+
public class ListOfShortTallShortTest extends ActivityInstrumentationTestCase<ListOfShortTallShort> {
private ListView mListView;
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfThinItemsTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfThinItemsTest.java
index c191d71..6bd1cb5 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfThinItemsTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfThinItemsTest.java
@@ -17,14 +17,15 @@
package android.widget.listview.arrowscroll;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
import android.view.KeyEvent;
import android.view.View;
import android.widget.ListView;
import android.widget.listview.ListOfThinItems;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
public class ListOfThinItemsTest extends ActivityInstrumentationTestCase<ListOfThinItems> {
private ListView mListView;
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithFirstScreenUnSelectableTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithFirstScreenUnSelectableTest.java
index 9a8e634..60bc115 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithFirstScreenUnSelectableTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithFirstScreenUnSelectableTest.java
@@ -16,12 +16,13 @@
package android.widget.listview.arrowscroll;
-import android.support.test.filters.LargeTest;
import android.test.ActivityInstrumentationTestCase2;
import android.view.KeyEvent;
+import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.listview.ListWithFirstScreenUnSelectable;
-import android.widget.AdapterView;
+
+import androidx.test.filters.LargeTest;
@LargeTest
public class ListWithFirstScreenUnSelectableTest
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithNoFadingEdgeTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithNoFadingEdgeTest.java
index 56ca009..a60054e 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithNoFadingEdgeTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithNoFadingEdgeTest.java
@@ -17,12 +17,13 @@
package android.widget.listview.arrowscroll;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
import android.view.KeyEvent;
import android.widget.ListView;
import android.widget.listview.ListWithNoFadingEdge;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
public class ListWithNoFadingEdgeTest extends ActivityInstrumentationTestCase<ListWithNoFadingEdge> {
private ListView mListView;
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithOffScreenNextSelectableTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithOffScreenNextSelectableTest.java
index cf319d1..80e70c6 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithOffScreenNextSelectableTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithOffScreenNextSelectableTest.java
@@ -17,14 +17,15 @@
package android.widget.listview.arrowscroll;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
import android.view.KeyEvent;
import android.view.View;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.listview.ListWithOffScreenNextSelectable;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
@Suppress // Failing.
public class ListWithOffScreenNextSelectableTest
extends ActivityInstrumentationTestCase<ListWithOffScreenNextSelectable> {
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithOnItemSelectedActionTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithOnItemSelectedActionTest.java
index feea9b2..819b739 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithOnItemSelectedActionTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithOnItemSelectedActionTest.java
@@ -17,12 +17,13 @@
package android.widget.listview.arrowscroll;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
import android.widget.ListView;
import android.widget.TextView;
-import android.view.KeyEvent;
import android.widget.listview.ListWithOnItemSelectedAction;
+import androidx.test.filters.MediumTest;
+
public class ListWithOnItemSelectedActionTest extends ActivityInstrumentationTestCase<ListWithOnItemSelectedAction> {
private ListView mListView;
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithScreenOfNoSelectablesTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithScreenOfNoSelectablesTest.java
index 211c8c8..9bbdc2a 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithScreenOfNoSelectablesTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithScreenOfNoSelectablesTest.java
@@ -17,13 +17,14 @@
package android.widget.listview.arrowscroll;
import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
import android.view.KeyEvent;
import android.view.View;
import android.widget.ListView;
import android.widget.listview.ListWithScreenOfNoSelectables;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
public class ListWithScreenOfNoSelectablesTest extends ActivityInstrumentationTestCase2<ListWithScreenOfNoSelectables> {
private ListView mListView;
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithSeparatorsTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithSeparatorsTest.java
index 42058f0..21fa51d 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithSeparatorsTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithSeparatorsTest.java
@@ -17,11 +17,12 @@
package android.widget.listview.arrowscroll;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.widget.ListView;
import android.view.KeyEvent;
+import android.widget.ListView;
import android.widget.listview.ListWithSeparators;
+import androidx.test.filters.MediumTest;
+
public class ListWithSeparatorsTest extends ActivityInstrumentationTestCase<ListWithSeparators> {
private ListWithSeparators mActivity;
private ListView mListView;
diff --git a/core/tests/coretests/src/android/widget/listview/focus/AdjacentListsWithAdjacentISVsInsideTest.java b/core/tests/coretests/src/android/widget/listview/focus/AdjacentListsWithAdjacentISVsInsideTest.java
index 6a7466b..e9baabf 100644
--- a/core/tests/coretests/src/android/widget/listview/focus/AdjacentListsWithAdjacentISVsInsideTest.java
+++ b/core/tests/coretests/src/android/widget/listview/focus/AdjacentListsWithAdjacentISVsInsideTest.java
@@ -16,14 +16,14 @@
package android.widget.listview.focus;
-import android.test.suitebuilder.annotation.Suppress;
-import android.widget.listview.AdjacentListsWithAdjacentISVsInside;
-import android.util.InternalSelectionView;
-
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.util.InternalSelectionView;
import android.view.KeyEvent;
import android.widget.ListView;
+import android.widget.listview.AdjacentListsWithAdjacentISVsInside;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
public class AdjacentListsWithAdjacentISVsInsideTest extends ActivityInstrumentationTestCase<AdjacentListsWithAdjacentISVsInside> {
diff --git a/core/tests/coretests/src/android/widget/listview/focus/ListButtonsDiagonalAcrossItemsTest.java b/core/tests/coretests/src/android/widget/listview/focus/ListButtonsDiagonalAcrossItemsTest.java
index 5540d65..3fbdacc 100644
--- a/core/tests/coretests/src/android/widget/listview/focus/ListButtonsDiagonalAcrossItemsTest.java
+++ b/core/tests/coretests/src/android/widget/listview/focus/ListButtonsDiagonalAcrossItemsTest.java
@@ -16,15 +16,15 @@
package android.widget.listview.focus;
-import android.widget.listview.ListButtonsDiagonalAcrossItems;
-
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
import android.view.FocusFinder;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Button;
import android.widget.ListView;
+import android.widget.listview.ListButtonsDiagonalAcrossItems;
+
+import androidx.test.filters.MediumTest;
/**
* Test that ListView will override default behavior of focus searching to
diff --git a/core/tests/coretests/src/android/widget/listview/focus/ListHorizontalFocusWithinItemWinsTest.java b/core/tests/coretests/src/android/widget/listview/focus/ListHorizontalFocusWithinItemWinsTest.java
index edc60b5..5448952 100644
--- a/core/tests/coretests/src/android/widget/listview/focus/ListHorizontalFocusWithinItemWinsTest.java
+++ b/core/tests/coretests/src/android/widget/listview/focus/ListHorizontalFocusWithinItemWinsTest.java
@@ -17,12 +17,13 @@
package android.widget.listview.focus;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
import android.view.KeyEvent;
import android.widget.Button;
import android.widget.ListView;
import android.widget.listview.ListHorizontalFocusWithinItemWins;
+import androidx.test.filters.MediumTest;
+
public class ListHorizontalFocusWithinItemWinsTest extends ActivityInstrumentationTestCase<ListHorizontalFocusWithinItemWins> {
private ListView mListView;
diff --git a/core/tests/coretests/src/android/widget/listview/focus/ListWithEditTextHeaderTest.java b/core/tests/coretests/src/android/widget/listview/focus/ListWithEditTextHeaderTest.java
index b449b61..0b17aaf 100644
--- a/core/tests/coretests/src/android/widget/listview/focus/ListWithEditTextHeaderTest.java
+++ b/core/tests/coretests/src/android/widget/listview/focus/ListWithEditTextHeaderTest.java
@@ -17,17 +17,18 @@
package android.widget.listview.focus;
import android.test.ActivityInstrumentationTestCase2;
-import android.test.FlakyTest;
import android.test.TouchUtils;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
import android.view.KeyEvent;
import android.view.View;
import android.widget.AbsListView;
import android.widget.ListView;
import android.widget.listview.ListWithEditTextHeader;
+import androidx.test.filters.FlakyTest;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
public class ListWithEditTextHeaderTest extends ActivityInstrumentationTestCase2<ListWithEditTextHeader> {
private ListView mListView;
@@ -49,7 +50,7 @@
assertTrue("header does not have focus", mListView.getChildAt(0).isFocused());
}
- @FlakyTest(tolerance=2)
+ @FlakyTest
@LargeTest
public void testClickingHeaderKeepsFocus() {
TouchUtils.clickView(this, mListView.getChildAt(0));
diff --git a/core/tests/coretests/src/android/widget/listview/touch/ListGetSelectedViewTest.java b/core/tests/coretests/src/android/widget/listview/touch/ListGetSelectedViewTest.java
index 28f899e..262d0f4 100644
--- a/core/tests/coretests/src/android/widget/listview/touch/ListGetSelectedViewTest.java
+++ b/core/tests/coretests/src/android/widget/listview/touch/ListGetSelectedViewTest.java
@@ -17,14 +17,14 @@
package android.widget.listview.touch;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
import android.test.TouchUtils;
-import android.widget.ListView;
import android.view.View;
-
+import android.widget.ListView;
import android.widget.listview.ListGetSelectedView;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
/**
* This test is made to check that getSelectedView() will return
* null in touch mode.
diff --git a/core/tests/coretests/src/android/widget/listview/touch/ListOfTouchablesTest.java b/core/tests/coretests/src/android/widget/listview/touch/ListOfTouchablesTest.java
index ffa9a5e..48e8c5e 100644
--- a/core/tests/coretests/src/android/widget/listview/touch/ListOfTouchablesTest.java
+++ b/core/tests/coretests/src/android/widget/listview/touch/ListOfTouchablesTest.java
@@ -17,15 +17,14 @@
package android.widget.listview.touch;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.test.TouchUtils;
import android.view.Gravity;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.ListView;
-
import android.widget.listview.ListOfTouchables;
-import android.test.TouchUtils;
+
+import androidx.test.filters.MediumTest;
/**
* Touch tests for a list where all of the items fit on the screen.
diff --git a/core/tests/coretests/src/android/widget/listview/touch/ListSetSelectionTest.java b/core/tests/coretests/src/android/widget/listview/touch/ListSetSelectionTest.java
index aed513a..716683a 100644
--- a/core/tests/coretests/src/android/widget/listview/touch/ListSetSelectionTest.java
+++ b/core/tests/coretests/src/android/widget/listview/touch/ListSetSelectionTest.java
@@ -17,15 +17,15 @@
package android.widget.listview.touch;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
import android.test.TouchUtils;
-import android.test.suitebuilder.annotation.Suppress;
import android.view.View;
import android.widget.ListView;
-
import android.widget.listview.ListSimple;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
/**
* Tests setting the selection in touch mode
*/
diff --git a/core/tests/coretests/src/android/widget/listview/touch/ListTouchBottomGravityManyTest.java b/core/tests/coretests/src/android/widget/listview/touch/ListTouchBottomGravityManyTest.java
index 7daf64e..6a1f076 100644
--- a/core/tests/coretests/src/android/widget/listview/touch/ListTouchBottomGravityManyTest.java
+++ b/core/tests/coretests/src/android/widget/listview/touch/ListTouchBottomGravityManyTest.java
@@ -17,16 +17,16 @@
package android.widget.listview.touch;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
import android.test.TouchUtils;
import android.view.Gravity;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.ListView;
-
import android.widget.listview.ListBottomGravityMany;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
/**
* Touch tests for a list where all of the items do not fit on the screen, and the list
* stacks from the bottom.
diff --git a/core/tests/coretests/src/android/widget/listview/touch/ListTouchBottomGravityTest.java b/core/tests/coretests/src/android/widget/listview/touch/ListTouchBottomGravityTest.java
index 4086cf0..89498d66 100644
--- a/core/tests/coretests/src/android/widget/listview/touch/ListTouchBottomGravityTest.java
+++ b/core/tests/coretests/src/android/widget/listview/touch/ListTouchBottomGravityTest.java
@@ -17,13 +17,13 @@
package android.widget.listview.touch;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
import android.test.TouchUtils;
import android.view.View;
import android.widget.ListView;
-
import android.widget.listview.ListBottomGravity;
+import androidx.test.filters.MediumTest;
+
/**
* Touch tests for a list where all of the items fit on the screen, and the list
* stacks from the bottom.
diff --git a/core/tests/coretests/src/android/widget/listview/touch/ListTouchManyTest.java b/core/tests/coretests/src/android/widget/listview/touch/ListTouchManyTest.java
index 30d56ca..c7f2371 100644
--- a/core/tests/coretests/src/android/widget/listview/touch/ListTouchManyTest.java
+++ b/core/tests/coretests/src/android/widget/listview/touch/ListTouchManyTest.java
@@ -17,16 +17,16 @@
package android.widget.listview.touch;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
import android.test.TouchUtils;
import android.view.Gravity;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.ListView;
-
import android.widget.listview.ListTopGravityMany;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
/**
* Touch tests for a list where all of the items do not fit on the screen.
*/
diff --git a/core/tests/coretests/src/android/widget/listview/touch/ListTouchTest.java b/core/tests/coretests/src/android/widget/listview/touch/ListTouchTest.java
index 5b064b3..8a557ab 100644
--- a/core/tests/coretests/src/android/widget/listview/touch/ListTouchTest.java
+++ b/core/tests/coretests/src/android/widget/listview/touch/ListTouchTest.java
@@ -17,13 +17,13 @@
package android.widget.listview.touch;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
import android.test.TouchUtils;
import android.view.View;
import android.widget.ListView;
-
import android.widget.listview.ListTopGravity;
+import androidx.test.filters.MediumTest;
+
/**
* Touch tests for a list where all of the items fit on the screen.
*/
diff --git a/core/tests/coretests/src/android/widget/scroll/ButtonAboveTallInternalSelectionView.java b/core/tests/coretests/src/android/widget/scroll/ButtonAboveTallInternalSelectionView.java
index a7f5c05..a30985b 100644
--- a/core/tests/coretests/src/android/widget/scroll/ButtonAboveTallInternalSelectionView.java
+++ b/core/tests/coretests/src/android/widget/scroll/ButtonAboveTallInternalSelectionView.java
@@ -18,7 +18,6 @@
import android.util.InternalSelectionView;
import android.util.ScrollViewScenario;
-
import android.widget.Button;
/**
diff --git a/core/tests/coretests/src/android/widget/scroll/ButtonAboveTallInternalSelectionViewTest.java b/core/tests/coretests/src/android/widget/scroll/ButtonAboveTallInternalSelectionViewTest.java
index 8123228..825aa1a 100644
--- a/core/tests/coretests/src/android/widget/scroll/ButtonAboveTallInternalSelectionViewTest.java
+++ b/core/tests/coretests/src/android/widget/scroll/ButtonAboveTallInternalSelectionViewTest.java
@@ -16,14 +16,13 @@
package android.widget.scroll;
-import android.test.suitebuilder.annotation.Suppress;
-import android.widget.scroll.ButtonAboveTallInternalSelectionView;
-import android.util.InternalSelectionView;
-
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.util.InternalSelectionView;
import android.view.KeyEvent;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
@Suppress // Failing.
public class ButtonAboveTallInternalSelectionViewTest extends
ActivityInstrumentationTestCase<ButtonAboveTallInternalSelectionView> {
diff --git a/core/tests/coretests/src/android/widget/scroll/ButtonsWithTallTextViewInBetween.java b/core/tests/coretests/src/android/widget/scroll/ButtonsWithTallTextViewInBetween.java
index 3d5f86d..47d36dd 100644
--- a/core/tests/coretests/src/android/widget/scroll/ButtonsWithTallTextViewInBetween.java
+++ b/core/tests/coretests/src/android/widget/scroll/ButtonsWithTallTextViewInBetween.java
@@ -17,7 +17,6 @@
package android.widget.scroll;
import android.util.ScrollViewScenario;
-
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
diff --git a/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisible.java b/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisible.java
index afc275f..dba07a0 100644
--- a/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisible.java
+++ b/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisible.java
@@ -16,15 +16,15 @@
package android.widget.scroll;
-import com.android.frameworks.coretests.R;
-
import android.app.Activity;
-import android.os.Bundle;
import android.graphics.Rect;
+import android.os.Bundle;
import android.view.View;
import android.widget.ScrollView;
import android.widget.TextView;
+import com.android.frameworks.coretests.R;
+
/**
* A screen with some scenarios that exercise {@link ScrollView}'s implementation
* of {@link android.view.ViewGroup#requestChildRectangleOnScreen}:
diff --git a/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisibleTest.java b/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisibleTest.java
index f8abdb2..7c3df91 100644
--- a/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisibleTest.java
+++ b/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisibleTest.java
@@ -16,19 +16,19 @@
package android.widget.scroll;
-import android.test.suitebuilder.annotation.Suppress;
-import android.widget.scroll.RequestRectangleVisible;
-import com.android.frameworks.coretests.R;
-
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
import android.test.ViewAsserts;
+import android.view.KeyEvent;
+import android.view.View;
import android.widget.Button;
import android.widget.ScrollView;
import android.widget.TextView;
-import android.view.View;
-import android.view.KeyEvent;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
+import com.android.frameworks.coretests.R;
/**
* {@link RequestRectangleVisible} is set up to exercise the cases of moving a
diff --git a/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisibleWithInternalScroll.java b/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisibleWithInternalScroll.java
index 731b25a..105686a 100644
--- a/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisibleWithInternalScroll.java
+++ b/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisibleWithInternalScroll.java
@@ -16,15 +16,14 @@
package android.widget.scroll;
-import com.android.frameworks.coretests.R;
-
import android.app.Activity;
-import android.os.Bundle;
-import android.widget.EditText;
-import android.widget.TextView;
-import android.widget.Button;
-import android.view.View;
import android.graphics.Rect;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+
+import com.android.frameworks.coretests.R;
public class RequestRectangleVisibleWithInternalScroll extends Activity {
diff --git a/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisibleWithInternalScrollTest.java b/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisibleWithInternalScrollTest.java
index 5e9b520..1a221ff 100644
--- a/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisibleWithInternalScrollTest.java
+++ b/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisibleWithInternalScrollTest.java
@@ -16,16 +16,17 @@
package android.widget.scroll;
-import com.android.frameworks.coretests.R;
-
import android.test.ActivityInstrumentationTestCase;
import android.test.ViewAsserts;
-import android.test.suitebuilder.annotation.Suppress;
import android.view.KeyEvent;
import android.widget.Button;
import android.widget.ScrollView;
import android.widget.TextView;
+import androidx.test.filters.Suppress;
+
+import com.android.frameworks.coretests.R;
+
/**
* This is suppressed because {@link TextView#scrollBy} isn't working.
*/
diff --git a/core/tests/coretests/src/android/widget/scroll/ScrollViewButtonsAndLabels.java b/core/tests/coretests/src/android/widget/scroll/ScrollViewButtonsAndLabels.java
index 027ea0f..92a3152 100644
--- a/core/tests/coretests/src/android/widget/scroll/ScrollViewButtonsAndLabels.java
+++ b/core/tests/coretests/src/android/widget/scroll/ScrollViewButtonsAndLabels.java
@@ -16,15 +16,14 @@
package android.widget.scroll;
-import com.android.frameworks.coretests.R;
-
import android.app.Activity;
import android.os.Bundle;
+import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
-import android.widget.Button;
+import com.android.frameworks.coretests.R;
/**
* Basic scroll view example
diff --git a/core/tests/coretests/src/android/widget/scroll/ScrollViewButtonsAndLabelsTest.java b/core/tests/coretests/src/android/widget/scroll/ScrollViewButtonsAndLabelsTest.java
index 3fd17ee..8d71f84 100644
--- a/core/tests/coretests/src/android/widget/scroll/ScrollViewButtonsAndLabelsTest.java
+++ b/core/tests/coretests/src/android/widget/scroll/ScrollViewButtonsAndLabelsTest.java
@@ -17,14 +17,14 @@
package android.widget.scroll;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
import android.view.KeyEvent;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ScrollView;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
public class ScrollViewButtonsAndLabelsTest
extends ActivityInstrumentationTestCase<ScrollViewButtonsAndLabels> {
diff --git a/core/tests/coretests/src/android/widget/scroll/ShortButtons.java b/core/tests/coretests/src/android/widget/scroll/ShortButtons.java
index 3a0f29a..90ede7d 100644
--- a/core/tests/coretests/src/android/widget/scroll/ShortButtons.java
+++ b/core/tests/coretests/src/android/widget/scroll/ShortButtons.java
@@ -17,7 +17,6 @@
package android.widget.scroll;
import android.util.ScrollViewScenario;
-
import android.widget.Button;
import android.widget.LinearLayout;
diff --git a/core/tests/coretests/src/android/widget/scroll/arrowscroll/ButtonsWithTallTextViewInBetweenTest.java b/core/tests/coretests/src/android/widget/scroll/arrowscroll/ButtonsWithTallTextViewInBetweenTest.java
index 56d7ed2..04f5ac8 100644
--- a/core/tests/coretests/src/android/widget/scroll/arrowscroll/ButtonsWithTallTextViewInBetweenTest.java
+++ b/core/tests/coretests/src/android/widget/scroll/arrowscroll/ButtonsWithTallTextViewInBetweenTest.java
@@ -16,16 +16,16 @@
package android.widget.scroll.arrowscroll;
-import android.widget.scroll.ButtonsWithTallTextViewInBetween;
-
import android.graphics.Rect;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Button;
import android.widget.ScrollView;
import android.widget.TextView;
+import android.widget.scroll.ButtonsWithTallTextViewInBetween;
+
+import androidx.test.filters.MediumTest;
public class ButtonsWithTallTextViewInBetweenTest
extends ActivityInstrumentationTestCase<ButtonsWithTallTextViewInBetween> {
diff --git a/core/tests/coretests/src/android/widget/scroll/arrowscroll/MultiPageTextWithPaddingTest.java b/core/tests/coretests/src/android/widget/scroll/arrowscroll/MultiPageTextWithPaddingTest.java
index 6ce4c15..2f45098 100644
--- a/core/tests/coretests/src/android/widget/scroll/arrowscroll/MultiPageTextWithPaddingTest.java
+++ b/core/tests/coretests/src/android/widget/scroll/arrowscroll/MultiPageTextWithPaddingTest.java
@@ -16,14 +16,14 @@
package android.widget.scroll.arrowscroll;
-import android.test.suitebuilder.annotation.Suppress;
-import android.widget.scroll.arrowscroll.MultiPageTextWithPadding;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
import android.view.KeyEvent;
-import android.widget.TextView;
import android.widget.ScrollView;
+import android.widget.TextView;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
@Suppress // Flaky
public class MultiPageTextWithPaddingTest extends
diff --git a/core/tests/coretests/src/android/widget/scroll/arrowscroll/ShortButtonsTest.java b/core/tests/coretests/src/android/widget/scroll/arrowscroll/ShortButtonsTest.java
index 267d8ee..a2928cb 100644
--- a/core/tests/coretests/src/android/widget/scroll/arrowscroll/ShortButtonsTest.java
+++ b/core/tests/coretests/src/android/widget/scroll/arrowscroll/ShortButtonsTest.java
@@ -16,15 +16,15 @@
package android.widget.scroll.arrowscroll;
-import android.widget.scroll.ShortButtons;
-
import android.graphics.Rect;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
import android.view.KeyEvent;
import android.widget.Button;
import android.widget.ScrollView;
+import android.widget.scroll.ShortButtons;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
public class ShortButtonsTest extends ActivityInstrumentationTestCase<ShortButtons> {
diff --git a/core/tests/coretests/src/android/widget/scroll/arrowscroll/TallTextAboveButtonTest.java b/core/tests/coretests/src/android/widget/scroll/arrowscroll/TallTextAboveButtonTest.java
index 5351839..0681081 100644
--- a/core/tests/coretests/src/android/widget/scroll/arrowscroll/TallTextAboveButtonTest.java
+++ b/core/tests/coretests/src/android/widget/scroll/arrowscroll/TallTextAboveButtonTest.java
@@ -16,13 +16,13 @@
package android.widget.scroll.arrowscroll;
-import android.widget.scroll.TallTextAboveButton;
-
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
import android.view.KeyEvent;
import android.widget.ScrollView;
import android.widget.TextView;
+import android.widget.scroll.TallTextAboveButton;
+
+import androidx.test.filters.MediumTest;
public class TallTextAboveButtonTest extends ActivityInstrumentationTestCase<TallTextAboveButton> {
private ScrollView mScrollView;
diff --git a/core/tests/coretests/src/android/widget/touchmode/ChangeTouchModeTest.java b/core/tests/coretests/src/android/widget/touchmode/ChangeTouchModeTest.java
index 449c95c..aa20c9b 100644
--- a/core/tests/coretests/src/android/widget/touchmode/ChangeTouchModeTest.java
+++ b/core/tests/coretests/src/android/widget/touchmode/ChangeTouchModeTest.java
@@ -16,16 +16,17 @@
package android.widget.touchmode;
-import android.widget.layout.linear.LLOfButtons1;
-import android.widget.layout.linear.LLOfButtons2;
import static android.util.TouchModeFlexibleAsserts.assertInTouchModeAfterClick;
-import static android.util.TouchModeFlexibleAsserts.assertNotInTouchModeAfterKey;
import static android.util.TouchModeFlexibleAsserts.assertInTouchModeAfterTap;
+import static android.util.TouchModeFlexibleAsserts.assertNotInTouchModeAfterKey;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
import android.view.KeyEvent;
+import android.widget.layout.linear.LLOfButtons1;
+import android.widget.layout.linear.LLOfButtons2;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
/**
* Tests that the touch mode changes from various events, and that the state
diff --git a/core/tests/coretests/src/android/widget/touchmode/FocusableInTouchModeClickTest.java b/core/tests/coretests/src/android/widget/touchmode/FocusableInTouchModeClickTest.java
index 691b25a..97c982f 100644
--- a/core/tests/coretests/src/android/widget/touchmode/FocusableInTouchModeClickTest.java
+++ b/core/tests/coretests/src/android/widget/touchmode/FocusableInTouchModeClickTest.java
@@ -16,12 +16,12 @@
package android.widget.touchmode;
-import android.widget.layout.linear.LLOfTwoFocusableInTouchMode;
-
import android.test.ActivityInstrumentationTestCase2;
import android.test.TouchUtils;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.layout.linear.LLOfTwoFocusableInTouchMode;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
public class FocusableInTouchModeClickTest extends ActivityInstrumentationTestCase2<LLOfTwoFocusableInTouchMode> {
diff --git a/core/tests/coretests/src/android/widget/touchmode/StartInTouchWithViewInFocusTest.java b/core/tests/coretests/src/android/widget/touchmode/StartInTouchWithViewInFocusTest.java
index 5339188..88aa9ca 100644
--- a/core/tests/coretests/src/android/widget/touchmode/StartInTouchWithViewInFocusTest.java
+++ b/core/tests/coretests/src/android/widget/touchmode/StartInTouchWithViewInFocusTest.java
@@ -16,14 +16,15 @@
package android.widget.touchmode;
-import android.widget.layout.linear.LLEditTextThenButton;
import static android.util.TouchModeFlexibleAsserts.assertNotInTouchModeAfterKey;
import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.MediumTest;
import android.view.KeyEvent;
import android.widget.Button;
import android.widget.EditText;
+import android.widget.layout.linear.LLEditTextThenButton;
+
+import androidx.test.filters.MediumTest;
public class StartInTouchWithViewInFocusTest extends
ActivityInstrumentationTestCase2<LLEditTextThenButton> {
diff --git a/core/tests/coretests/src/android/widget/touchmode/TouchModeFocusChangeTest.java b/core/tests/coretests/src/android/widget/touchmode/TouchModeFocusChangeTest.java
index 5a6110c..f192f68 100644
--- a/core/tests/coretests/src/android/widget/touchmode/TouchModeFocusChangeTest.java
+++ b/core/tests/coretests/src/android/widget/touchmode/TouchModeFocusChangeTest.java
@@ -21,11 +21,11 @@
import static android.util.TouchModeFlexibleAsserts.assertNotInTouchModeAfterKey;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
import android.view.KeyEvent;
import android.widget.Button;
import android.widget.layout.linear.LLOfButtons1;
+import androidx.test.filters.MediumTest;
/**
* Make sure focus isn't kept by buttons when entering touch mode.
diff --git a/core/tests/coretests/src/android/widget/touchmode/TouchModeFocusableTest.java b/core/tests/coretests/src/android/widget/touchmode/TouchModeFocusableTest.java
index 3ddeef0..87f33a4c 100644
--- a/core/tests/coretests/src/android/widget/touchmode/TouchModeFocusableTest.java
+++ b/core/tests/coretests/src/android/widget/touchmode/TouchModeFocusableTest.java
@@ -20,12 +20,13 @@
import static android.util.TouchModeFlexibleAsserts.assertInTouchModeAfterTap;
import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
import android.widget.Button;
import android.widget.EditText;
import android.widget.layout.linear.LLEditTextThenButton;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
/**
* Some views, like edit texts, can keep and gain focus even when in touch mode.
*/
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
index a302657..aadfcbc 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
@@ -57,7 +57,6 @@
import android.provider.Settings;
import android.speech.tts.TextToSpeech;
import android.speech.tts.Voice;
-import android.support.test.runner.AndroidJUnit4;
import android.test.mock.MockContentResolver;
import android.text.TextUtils;
import android.view.Window;
@@ -66,6 +65,8 @@
import android.view.accessibility.IAccessibilityManager;
import android.widget.Toast;
+import androidx.test.runner.AndroidJUnit4;
+
import com.android.internal.R;
import com.android.internal.accessibility.AccessibilityShortcutController.FrameworkObjectProvider;
import com.android.internal.util.test.FakeSettingsProvider;
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
index 1859378..aaa624e 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -16,6 +16,30 @@
package com.android.internal.app;
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.action.ViewActions.click;
+import static android.support.test.espresso.assertion.ViewAssertions.matches;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static android.support.test.espresso.matcher.ViewMatchers.withText;
+
+import static com.android.internal.app.ChooserWrapperActivity.sOverrides;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.usage.UsageStatsManager;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
import com.android.internal.R;
import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
@@ -25,32 +49,8 @@
import org.junit.runner.RunWith;
import org.mockito.Mockito;
-import android.app.usage.UsageStats;
-import android.app.usage.UsageStatsManager;
-import android.content.Intent;
-import android.content.pm.ResolveInfo;
-import android.os.UserHandle;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
-
import java.util.ArrayList;
import java.util.List;
-import java.util.Map;
-
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.action.ViewActions.click;
-import static android.support.test.espresso.assertion.ViewAssertions.matches;
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-import static android.support.test.espresso.matcher.ViewMatchers.withText;
-import static com.android.internal.app.ChooserWrapperActivity.sOverrides;
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.not;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.mockito.Mockito.when;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.times;
/**
* Chooser activity instrumentation tests
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
index c446f3c..60529f6 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
@@ -16,14 +16,14 @@
package com.android.internal.app;
+import static org.mockito.Mockito.mock;
+
import android.app.usage.UsageStatsManager;
import android.content.Context;
import android.content.pm.PackageManager;
import java.util.function.Function;
-import static org.mockito.Mockito.mock;
-
public class ChooserWrapperActivity extends ChooserActivity {
/*
* Simple wrapper around chooser activity to be able to initiate it under test
diff --git a/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java b/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java
index cfb6bdd..9b13af2 100644
--- a/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java
@@ -46,9 +46,10 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Rule;
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
index 404c99c..fe2fb85 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
@@ -16,6 +16,29 @@
package com.android.internal.app;
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.action.ViewActions.click;
+import static android.support.test.espresso.assertion.ViewAssertions.matches;
+import static android.support.test.espresso.matcher.ViewMatchers.isEnabled;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static android.support.test.espresso.matcher.ViewMatchers.withText;
+
+import static com.android.internal.app.ResolverWrapperActivity.sOverrides;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.Mockito.when;
+
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.view.View;
+import android.widget.RelativeLayout;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
import com.android.internal.R;
import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
import com.android.internal.widget.ResolverDrawerLayout;
@@ -26,37 +49,8 @@
import org.junit.runner.RunWith;
import org.mockito.Mockito;
-import android.app.usage.UsageStats;
-import android.app.usage.UsageStatsManager;
-import android.content.Intent;
-import android.content.pm.ResolveInfo;
-import android.os.UserHandle;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
-import android.view.View;
-import android.widget.RelativeLayout;
-
import java.util.ArrayList;
import java.util.List;
-import java.util.Map;
-
-import static android.os.SystemClock.sleep;
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.action.ViewActions.click;
-import static android.support.test.espresso.assertion.ViewAssertions.matches;
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
-import static android.support.test.espresso.matcher.ViewMatchers.isEnabled;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-import static android.support.test.espresso.matcher.ViewMatchers.withText;
-import static com.android.internal.app.ResolverWrapperActivity.sOverrides;
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.not;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
/**
* Resolver activity instrumentation tests
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverDataProvider.java b/core/tests/coretests/src/com/android/internal/app/ResolverDataProvider.java
index c710b9a..850b466 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverDataProvider.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverDataProvider.java
@@ -23,10 +23,6 @@
import android.content.pm.ResolveInfo;
import android.os.UserHandle;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicInteger;
-
/**
* Utility class used by resolver tests to create mock data
*/
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverListControllerTest.java b/core/tests/coretests/src/com/android/internal/app/ResolverListControllerTest.java
index 284ab60..fcec00e 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverListControllerTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverListControllerTest.java
@@ -25,34 +25,31 @@
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.when;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-import org.mockito.stubbing.Answer;
-
import android.app.usage.IUsageStatsManager;
import android.app.usage.UsageStats;
import android.app.usage.UsageStatsManager;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.content.Intent;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.support.test.runner.AndroidJUnit4;
import android.util.ArrayMap;
-import java.io.File;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java
index 163211e..83f6bc2 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java
@@ -16,17 +16,12 @@
package com.android.internal.app;
-import android.app.usage.UsageStatsManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.os.RemoteException;
-
-import java.util.function.Function;
-
import static org.mockito.Mockito.mock;
+import android.app.usage.UsageStatsManager;
+import android.content.pm.PackageManager;
+
+import java.util.function.Function;
/*
* Simple wrapper around chooser activity to be able to initiate it under test
diff --git a/core/tests/coretests/src/com/android/internal/app/WindowDecorActionBarTest.java b/core/tests/coretests/src/com/android/internal/app/WindowDecorActionBarTest.java
index 472958a..87ad124 100644
--- a/core/tests/coretests/src/com/android/internal/app/WindowDecorActionBarTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/WindowDecorActionBarTest.java
@@ -17,12 +17,13 @@
package com.android.internal.app;
import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.test.suitebuilder.annotation.SmallTest;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuItem;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.SmallTest;
+
/**
* Tests for {@link WindowDecorActionBar}.
*/
diff --git a/core/tests/coretests/src/com/android/internal/app/procstats/SparseMappingTableTest.java b/core/tests/coretests/src/com/android/internal/app/procstats/SparseMappingTableTest.java
index 115af5e..f7fea3b 100644
--- a/core/tests/coretests/src/com/android/internal/app/procstats/SparseMappingTableTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/procstats/SparseMappingTableTest.java
@@ -16,20 +16,14 @@
package com.android.internal.app.procstats;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.ArrayList;
-
-import android.os.BatteryStats;
import android.os.Parcel;
-import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
+import androidx.test.filters.SmallTest;
+
import junit.framework.Assert;
import junit.framework.TestCase;
-import org.mockito.Mockito;
-
/**
* Provides test cases for SparseMappingTable.
*/
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodDebugTest.java b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodDebugTest.java
index 629f7b6..222e494 100644
--- a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodDebugTest.java
+++ b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodDebugTest.java
@@ -18,10 +18,11 @@
import static org.junit.Assert.assertEquals;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.view.WindowManager.LayoutParams;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/SubtypeLocaleUtilsTest.java b/core/tests/coretests/src/com/android/internal/inputmethod/SubtypeLocaleUtilsTest.java
index 8179328..ba63908 100644
--- a/core/tests/coretests/src/com/android/internal/inputmethod/SubtypeLocaleUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/inputmethod/SubtypeLocaleUtilsTest.java
@@ -18,8 +18,8 @@
import static org.junit.Assert.assertEquals;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsBackgroundStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsBackgroundStatsTest.java
index 992b46f..b687801 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsBackgroundStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsBackgroundStatsTest.java
@@ -13,6 +13,7 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
+
package com.android.internal.os;
import static android.os.BatteryStats.STATS_SINCE_CHARGED;
@@ -20,10 +21,11 @@
import android.app.ActivityManager;
import android.os.BatteryStats;
import android.os.WorkSource;
-import android.support.test.filters.SmallTest;
import android.util.ArrayMap;
import android.view.Display;
+import androidx.test.filters.SmallTest;
+
import junit.framework.TestCase;
/**
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCounterTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCounterTest.java
index 08f8dd1..37f818a 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCounterTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCounterTest.java
@@ -13,11 +13,13 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
+
package com.android.internal.os;
import android.os.BatteryStats;
import android.os.Parcel;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
import junit.framework.TestCase;
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
index ee8d508..0179ead 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package com.android.internal.os;
import static android.os.BatteryStats.STATS_SINCE_CHARGED;
@@ -36,11 +37,12 @@
import android.os.BatteryStats;
import android.os.UserHandle;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.util.SparseLongArray;
import android.view.Display;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import com.android.internal.util.ArrayUtils;
import org.junit.Before;
@@ -64,7 +66,7 @@
* Install: adb install -r \
* ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
* Run: adb shell am instrument -e class com.android.internal.os.BatteryStatsCpuTimesTest -w \
- * com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
+ * com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner
*
* or
*
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsDualTimerTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsDualTimerTest.java
index 3a5a9f5..efb8710 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsDualTimerTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsDualTimerTest.java
@@ -13,10 +13,12 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
+
package com.android.internal.os;
import android.os.BatteryStats;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
import junit.framework.TestCase;
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsDurationTimerTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsDurationTimerTest.java
index 19dab79..a42286f 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsDurationTimerTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsDurationTimerTest.java
@@ -13,11 +13,13 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
+
package com.android.internal.os;
import android.os.BatteryStats;
import android.os.Parcel;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
import junit.framework.TestCase;
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java
index 7467114..355601c 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java
@@ -17,7 +17,6 @@
package com.android.internal.os;
-
import static android.os.BatteryStats.Uid.PROCESS_STATE_TOP;
import static com.google.common.truth.Truth.assertThat;
@@ -37,12 +36,13 @@
import android.content.pm.PackageManager;
import android.os.BatteryStats;
import android.os.Process;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.text.format.DateUtils;
import android.util.StatsLog;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import junit.framework.TestCase;
import org.junit.Before;
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsHistoryTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsHistoryTest.java
index 10a3189..cc0ddb7 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsHistoryTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsHistoryTest.java
@@ -13,18 +13,18 @@
* 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.assertFalse;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.assertEquals;
-
import android.content.Context;
import android.os.Parcel;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java
index 613de45..dc93675 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package com.android.internal.os;
import static android.os.BatteryStats.STATS_SINCE_CHARGED;
@@ -31,12 +32,13 @@
import static org.mockito.Mockito.when;
import android.os.BatteryStats;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.view.Display;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
import com.android.internal.util.ArrayUtils;
import org.junit.Before;
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
index 8cbe5d6..3e33273 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
@@ -13,6 +13,7 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
+
package com.android.internal.os;
import static android.os.BatteryStats.STATS_CURRENT;
@@ -20,21 +21,20 @@
import static android.os.BatteryStats.WAKE_TYPE_PARTIAL;
import android.app.ActivityManager;
-import android.os.BatteryManager;
import android.os.BatteryStats;
import android.os.BatteryStats.HistoryItem;
import android.os.BatteryStats.Uid.Sensor;
import android.os.WorkSource;
-import android.support.test.filters.SmallTest;
import android.view.Display;
+import androidx.test.filters.SmallTest;
+
import com.android.internal.os.BatteryStatsImpl.DualTimer;
import com.android.internal.os.BatteryStatsImpl.Uid;
+
import junit.framework.TestCase;
-import java.util.ArrayList;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
/**
@@ -47,7 +47,7 @@
* Install: adb install -r \
* ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
* Run: adb shell am instrument -e class com.android.internal.os.BatteryStatsNoteTest -w \
- * com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
+ * com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner
*/
public class BatteryStatsNoteTest extends TestCase {
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSamplingTimerTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSamplingTimerTest.java
index 251ceb0..61d20df 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSamplingTimerTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSamplingTimerTest.java
@@ -13,11 +13,13 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
+
package com.android.internal.os;
import android.os.BatteryStats;
import android.os.Parcel;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
import junit.framework.TestCase;
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java
index a751f90..b851f0a 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java
@@ -13,13 +13,15 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
+
package com.android.internal.os;
import android.app.ActivityManager;
import android.os.BatteryStats;
-import android.support.test.filters.SmallTest;
import android.view.Display;
+import androidx.test.filters.SmallTest;
+
import junit.framework.TestCase;
/**
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsServTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsServTest.java
index 5fd8225..b9995c4 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsServTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsServTest.java
@@ -18,7 +18,8 @@
import android.os.BatteryStats;
import android.os.Parcel;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
import junit.framework.Assert;
import junit.framework.TestCase;
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsStopwatchTimerTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsStopwatchTimerTest.java
index 015314e..f76f316 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsStopwatchTimerTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsStopwatchTimerTest.java
@@ -13,10 +13,12 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
+
package com.android.internal.os;
import android.os.BatteryStats;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
import junit.framework.TestCase;
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
index 225515e..d69e1d1 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package com.android.internal.os;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimeBaseTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimeBaseTest.java
index 3190d9e..bce8b40 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimeBaseTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimeBaseTest.java
@@ -16,19 +16,20 @@
package com.android.internal.os;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-
import android.os.BatteryStats;
import android.os.Parcel;
-import android.support.test.filters.SmallTest;
import android.util.Log;
+import androidx.test.filters.SmallTest;
+
import junit.framework.Assert;
import junit.framework.TestCase;
import org.mockito.Mockito;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
/**
* Provides test cases for android.os.BatteryStats.
*/
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimerTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimerTest.java
index 98d0f7f..87dc2f3 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimerTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimerTest.java
@@ -18,16 +18,17 @@
import android.os.BatteryStats;
import android.os.Parcel;
-import android.support.test.filters.SmallTest;
import android.util.StringBuilderPrinter;
-import junit.framework.Assert;
-import junit.framework.TestCase;
+import androidx.test.filters.SmallTest;
import com.android.internal.os.BatteryStatsImpl.Clocks;
import com.android.internal.os.BatteryStatsImpl.TimeBase;
import com.android.internal.os.BatteryStatsImpl.Timer;
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
/**
* Provides test cases for android.os.BatteryStats.
*/
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsUidTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsUidTest.java
index a7e75a2..4df3190 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsUidTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsUidTest.java
@@ -16,22 +16,10 @@
package com.android.internal.os;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.ArrayList;
+import androidx.test.filters.SmallTest;
-import android.os.BatteryStats;
-import android.os.Parcel;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
-
-import junit.framework.Assert;
import junit.framework.TestCase;
-import com.android.internal.os.BatteryStatsImpl;
-
-import org.mockito.Mockito;
-
/**
* Provides test cases for android.os.BatteryStats.
*/
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsUserLifecycleTests.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsUserLifecycleTests.java
index 450473d..e7a1bca 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsUserLifecycleTests.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsUserLifecycleTests.java
@@ -28,12 +28,13 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
import android.support.test.uiautomator.UiDevice;
import android.util.ArraySet;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
diff --git a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
index dc3a12f..1d35143 100644
--- a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
@@ -22,11 +22,12 @@
import android.os.Binder;
import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.util.ArrayMap;
import android.util.SparseArray;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import com.android.internal.os.BinderInternal.CallSession;
import org.junit.Assert;
diff --git a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
index 42c9139..01515bd 100644
--- a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package com.android.internal.os;
import static android.os.BatteryStats.UID_TIMES_TYPE_ALL;
@@ -33,9 +34,6 @@
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
-import com.android.frameworks.coretests.aidl.ICmdCallback;
-import com.android.frameworks.coretests.aidl.ICmdReceiver;
-
import android.app.ActivityManager;
import android.app.KeyguardManager;
import android.content.ComponentName;
@@ -52,14 +50,18 @@
import android.os.Process;
import android.os.SystemClock;
import android.provider.Settings;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
import android.support.test.uiautomator.UiDevice;
import android.text.TextUtils;
import android.util.DebugUtils;
import android.util.Log;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.frameworks.coretests.aidl.ICmdCallback;
+import com.android.frameworks.coretests.aidl.ICmdReceiver;
+
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Rule;
diff --git a/core/tests/coretests/src/com/android/internal/os/DebugTest.java b/core/tests/coretests/src/com/android/internal/os/DebugTest.java
index efb78d7..2a8a857 100644
--- a/core/tests/coretests/src/com/android/internal/os/DebugTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/DebugTest.java
@@ -18,7 +18,8 @@
import android.os.Debug;
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.SmallTest;
+
import junit.framework.TestCase;
@SmallTest
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuProcReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuProcReaderTest.java
index 8360126..a25a7489 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuProcReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuProcReaderTest.java
@@ -24,9 +24,10 @@
import android.content.Context;
import android.os.FileUtils;
import android.os.SystemClock;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Before;
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuProcStringReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuProcStringReaderTest.java
index 2663f2b..7a31605 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuProcStringReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuProcStringReaderTest.java
@@ -24,9 +24,10 @@
import android.content.Context;
import android.os.FileUtils;
import android.os.SystemClock;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Before;
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java
index b242a34..0c56b8a 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java
@@ -23,9 +23,10 @@
import android.content.Context;
import android.os.FileUtils;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Before;
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidActiveTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidActiveTimeReaderTest.java
index adafda0..1b13a99 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidActiveTimeReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidActiveTimeReaderTest.java
@@ -13,6 +13,7 @@
* 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;
@@ -20,11 +21,12 @@
import android.content.Context;
import android.os.FileUtils;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.util.SparseLongArray;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidActiveTimeReader;
import org.junit.After;
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidClusterTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidClusterTimeReaderTest.java
index ad20d84..2ea80da 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidClusterTimeReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidClusterTimeReaderTest.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package com.android.internal.os;
import static org.junit.Assert.assertArrayEquals;
@@ -22,11 +23,12 @@
import android.content.Context;
import android.os.FileUtils;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.util.SparseArray;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidClusterTimeReader;
import org.junit.After;
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidFreqTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidFreqTimeReaderTest.java
index 1d3a98a..0b6fed3 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidFreqTimeReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidFreqTimeReaderTest.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package com.android.internal.os;
import static org.junit.Assert.assertArrayEquals;
@@ -24,11 +25,12 @@
import android.content.Context;
import android.os.FileUtils;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.util.SparseArray;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidFreqTimeReader;
import org.junit.After;
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidUserSysTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidUserSysTimeReaderTest.java
index 9b4512b..8f81ea2 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidUserSysTimeReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidUserSysTimeReaderTest.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package com.android.internal.os;
import static org.junit.Assert.assertArrayEquals;
@@ -23,11 +24,12 @@
import android.content.Context;
import android.os.FileUtils;
import android.os.SystemClock;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.util.SparseArray;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidUserSysTimeReader;
import org.junit.After;
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelMemoryBandwidthStatsTest.java b/core/tests/coretests/src/com/android/internal/os/KernelMemoryBandwidthStatsTest.java
index 32317ee..60dac85 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelMemoryBandwidthStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelMemoryBandwidthStatsTest.java
@@ -1,11 +1,27 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.internal.os;
-import android.support.test.filters.SmallTest;
import android.util.LongSparseLongArray;
+import androidx.test.filters.SmallTest;
+
import junit.framework.TestCase;
-import org.junit.Assert;
import org.mockito.Mockito;
import java.io.BufferedReader;
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelSingleUidTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelSingleUidTimeReaderTest.java
index 29227f9..479e19e 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelSingleUidTimeReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelSingleUidTimeReaderTest.java
@@ -21,10 +21,11 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.util.SparseArray;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import com.android.internal.os.KernelSingleUidTimeReader.Injector;
import org.junit.Before;
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelUidCpuActiveTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelUidCpuActiveTimeReaderTest.java
index 28570e8..12f6c18 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelUidCpuActiveTimeReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelUidCpuActiveTimeReaderTest.java
@@ -20,8 +20,8 @@
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelUidCpuClusterTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelUidCpuClusterTimeReaderTest.java
index 85dce02..532f337 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelUidCpuClusterTimeReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelUidCpuClusterTimeReaderTest.java
@@ -21,10 +21,11 @@
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.when;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.util.SparseArray;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelUidCpuFreqTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelUidCpuFreqTimeReaderTest.java
index 67c4e61..6d2980b 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelUidCpuFreqTimeReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelUidCpuFreqTimeReaderTest.java
@@ -24,10 +24,11 @@
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.util.SparseArray;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -53,7 +54,7 @@
* Install: adb install -r \
* ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
* Run: adb shell am instrument -e class com.android.internal.os.KernelUidCpuFreqTimeReaderTest -w \
- * com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
+ * com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner
*
* or
*
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelWakelockReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelWakelockReaderTest.java
index 4e4bb3507..78b6843 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelWakelockReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelWakelockReaderTest.java
@@ -13,9 +13,10 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
+
package com.android.internal.os;
-import android.support.test.filters.SmallTest;
+import androidx.test.filters.SmallTest;
import junit.framework.TestCase;
diff --git a/core/tests/coretests/src/com/android/internal/os/LoggingPrintStreamTest.java b/core/tests/coretests/src/com/android/internal/os/LoggingPrintStreamTest.java
index fe62764..cb8a62c 100644
--- a/core/tests/coretests/src/com/android/internal/os/LoggingPrintStreamTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LoggingPrintStreamTest.java
@@ -16,7 +16,9 @@
package com.android.internal.os;
-import android.test.suitebuilder.annotation.Suppress;
+import androidx.test.filters.Suppress;
+
+import junit.framework.TestCase;
import java.io.PrintWriter;
import java.io.StringWriter;
@@ -25,8 +27,6 @@
import java.util.Collections;
import java.util.List;
-import junit.framework.TestCase;
-
// this test causes a IllegalAccessError: superclass not accessible
@Suppress
public class LoggingPrintStreamTest extends TestCase {
diff --git a/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterArrayTest.java b/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterArrayTest.java
index 37b4e41a..0516bb7 100644
--- a/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterArrayTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterArrayTest.java
@@ -30,8 +30,9 @@
import static org.mockito.Mockito.when;
import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
@@ -55,7 +56,7 @@
* Install: adb install -r \
* ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
* Run: adb shell am instrument -e class com.android.internal.os.LongSamplingCounterArrayTest -w \
- * com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
+ * com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner
*/
@SmallTest
@RunWith(AndroidJUnit4.class)
diff --git a/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterTest.java b/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterTest.java
index 853bf8a..d2f5735 100644
--- a/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterTest.java
@@ -28,8 +28,9 @@
import static org.mockito.Mockito.when;
import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
diff --git a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
index b65c1e6..2c597b1 100644
--- a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
@@ -23,8 +23,9 @@
import android.os.Looper;
import android.os.Message;
import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Assert;
diff --git a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
index b68f6b1..c18445e 100644
--- a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
+++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
@@ -21,6 +21,7 @@
import android.util.SparseIntArray;
import com.android.internal.location.gnssmetrics.GnssMetrics;
+
import java.util.ArrayList;
import java.util.Queue;
import java.util.concurrent.Future;
diff --git a/core/tests/coretests/src/com/android/internal/os/PowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/PowerCalculatorTest.java
index 14d62e0..c592ab6 100644
--- a/core/tests/coretests/src/com/android/internal/os/PowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/PowerCalculatorTest.java
@@ -17,13 +17,13 @@
package com.android.internal.os;
-
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.os.BatteryStats;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import junit.framework.TestCase;
diff --git a/core/tests/coretests/src/com/android/internal/os/PowerProfileTest.java b/core/tests/coretests/src/com/android/internal/os/PowerProfileTest.java
index 2853c96..5862368 100644
--- a/core/tests/coretests/src/com/android/internal/os/PowerProfileTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/PowerProfileTest.java
@@ -17,8 +17,8 @@
package com.android.internal.os;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
import junit.framework.TestCase;
diff --git a/core/tests/coretests/src/com/android/internal/os/ProcStatsUtilTest.java b/core/tests/coretests/src/com/android/internal/os/ProcStatsUtilTest.java
index 489e164..e97caf8 100644
--- a/core/tests/coretests/src/com/android/internal/os/ProcStatsUtilTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/ProcStatsUtilTest.java
@@ -20,9 +20,10 @@
import android.content.Context;
import android.os.FileUtils;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Before;
diff --git a/core/tests/coretests/src/com/android/internal/os/ProcTimeInStateReaderTest.java b/core/tests/coretests/src/com/android/internal/os/ProcTimeInStateReaderTest.java
index 2893066..9db3f8a 100644
--- a/core/tests/coretests/src/com/android/internal/os/ProcTimeInStateReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/ProcTimeInStateReaderTest.java
@@ -22,9 +22,10 @@
import android.content.Context;
import android.os.FileUtils;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Before;
diff --git a/core/tests/coretests/src/com/android/internal/os/StoragedUidIoStatsReaderTest.java b/core/tests/coretests/src/com/android/internal/os/StoragedUidIoStatsReaderTest.java
index c051a1c..85eafc5 100644
--- a/core/tests/coretests/src/com/android/internal/os/StoragedUidIoStatsReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/StoragedUidIoStatsReaderTest.java
@@ -15,15 +15,17 @@
*/
package com.android.internal.os;
+
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import android.content.Context;
import android.os.FileUtils;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Before;
@@ -36,7 +38,6 @@
import java.io.File;
import java.nio.file.Files;
-
/**
* Test class for {@link StoragedUidIoStatsReader}.
*
diff --git a/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java
index 2a24881..8e0c1fe 100644
--- a/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java
+++ b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java
@@ -17,8 +17,6 @@
package com.android.internal.policy;
import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.test.suitebuilder.annotation.SmallTest;
import android.view.ActionMode;
import android.view.ActionMode.Callback;
import android.view.KeyEvent;
@@ -32,7 +30,8 @@
import android.view.WindowManager.LayoutParams;
import android.view.accessibility.AccessibilityEvent;
-import java.util.List;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.SmallTest;
/**
* Tests {@link PhoneWindow}'s {@link ActionMode} related methods.
diff --git a/core/tests/coretests/src/com/android/internal/policy/PhoneWindowTest.java b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowTest.java
index d4b8566..6c2d630 100644
--- a/core/tests/coretests/src/com/android/internal/policy/PhoneWindowTest.java
+++ b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowTest.java
@@ -28,12 +28,13 @@
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.platform.test.annotations.Presubmit;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.view.ActionMode;
import android.view.ContextThemeWrapper;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import com.android.frameworks.coretests.R;
import org.junit.Before;
diff --git a/core/tests/coretests/src/com/android/internal/util/ArrayUtilsTest.java b/core/tests/coretests/src/com/android/internal/util/ArrayUtilsTest.java
index b3897ce..d026735 100644
--- a/core/tests/coretests/src/com/android/internal/util/ArrayUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/ArrayUtilsTest.java
@@ -13,9 +13,11 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
+
package com.android.internal.util;
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.SmallTest;
+
import junit.framework.TestCase;
import java.util.ArrayList;
diff --git a/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java b/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java
index a44b860..4716312 100644
--- a/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package com.android.internal.util;
import static com.android.internal.util.DumpUtils.CRITICAL_SECTION_COMPONENTS;
diff --git a/core/tests/coretests/src/com/android/internal/util/LineBreakBufferedWriterTest.java b/core/tests/coretests/src/com/android/internal/util/LineBreakBufferedWriterTest.java
index 4845c4e..b2a2265 100644
--- a/core/tests/coretests/src/com/android/internal/util/LineBreakBufferedWriterTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/LineBreakBufferedWriterTest.java
@@ -19,11 +19,8 @@
import junit.framework.TestCase;
import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.PrintWriter;
import java.io.Writer;
import java.util.ArrayList;
-import java.util.LinkedList;
import java.util.List;
/**
diff --git a/core/tests/coretests/src/com/android/internal/util/ParseUtilsTest.java b/core/tests/coretests/src/com/android/internal/util/ParseUtilsTest.java
index f00c48c..867152e 100644
--- a/core/tests/coretests/src/com/android/internal/util/ParseUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/ParseUtilsTest.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package com.android.internal.util;
import junit.framework.TestCase;
diff --git a/core/tests/coretests/src/android/util/TokenBucketTest.java b/core/tests/coretests/src/com/android/internal/util/TokenBucketTest.java
similarity index 90%
rename from core/tests/coretests/src/android/util/TokenBucketTest.java
rename to core/tests/coretests/src/com/android/internal/util/TokenBucketTest.java
index f7ac20c..6c50bce 100644
--- a/core/tests/coretests/src/android/util/TokenBucketTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/TokenBucketTest.java
@@ -18,6 +18,7 @@
import android.os.SystemClock;
import android.text.format.DateUtils;
+
import junit.framework.TestCase;
public class TokenBucketTest extends TestCase {
@@ -54,9 +55,9 @@
drain(new TokenBucket(FILL_DELTA_VERY_LONG, 10, 100), 10);
- drain(new TokenBucket((int)DateUtils.MINUTE_IN_MILLIS, 50), 50);
- drain(new TokenBucket((int)DateUtils.HOUR_IN_MILLIS, 10), 10);
- drain(new TokenBucket((int)DateUtils.DAY_IN_MILLIS, 200), 200);
+ drain(new TokenBucket((int) DateUtils.MINUTE_IN_MILLIS, 50), 50);
+ drain(new TokenBucket((int) DateUtils.HOUR_IN_MILLIS, 10), 10);
+ drain(new TokenBucket((int) DateUtils.DAY_IN_MILLIS, 200), 200);
}
public void testReset() {
@@ -163,16 +164,16 @@
void assertDuration(long expected, long elapsed) {
String msg = String.format(
- "expected elapsed time at least %d ms, but was %d ms", expected, elapsed);
+ "expected elapsed time at least %d ms, but was %d ms", expected, elapsed);
elapsed += 1; // one millisecond extra guard
assertTrue(msg, elapsed >= expected);
}
- void assertThrow(Fn fn) {
- try {
- fn.call();
- fail("expected n exception to be thrown.");
- } catch (Throwable t) {}
+ void assertThrow(Fn fn) {
+ try {
+ fn.call();
+ fail("expected n exception to be thrown.");
+ } catch (Throwable t) { }
}
interface Fn { void call(); }
diff --git a/core/tests/coretests/src/com/android/internal/widget/ActionBarContainerTest.java b/core/tests/coretests/src/com/android/internal/widget/ActionBarContainerTest.java
index 912b7ec..b372366 100644
--- a/core/tests/coretests/src/com/android/internal/widget/ActionBarContainerTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/ActionBarContainerTest.java
@@ -18,11 +18,12 @@
import android.content.Context;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
import android.view.ActionMode;
import android.view.View;
import android.view.ViewGroup;
+import androidx.test.filters.SmallTest;
+
/**
* Tests for {@link ActionBarContainer}.
*/
diff --git a/core/tests/coretests/src/com/android/internal/widget/ActionBarOverlayLayoutTest.java b/core/tests/coretests/src/com/android/internal/widget/ActionBarOverlayLayoutTest.java
index d782c0c..d10f173 100644
--- a/core/tests/coretests/src/com/android/internal/widget/ActionBarOverlayLayoutTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/ActionBarOverlayLayoutTest.java
@@ -29,9 +29,6 @@
import android.content.Context;
import android.graphics.Insets;
import android.graphics.Rect;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.view.DisplayCutout;
import android.view.View;
import android.view.View.OnApplyWindowInsetsListener;
@@ -40,6 +37,10 @@
import android.widget.FrameLayout;
import android.widget.Toolbar;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/com/android/internal/widget/BackgroundFallbackTest.java b/core/tests/coretests/src/com/android/internal/widget/BackgroundFallbackTest.java
index e21143d..0fada06 100644
--- a/core/tests/coretests/src/com/android/internal/widget/BackgroundFallbackTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/BackgroundFallbackTest.java
@@ -32,10 +32,11 @@
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
-import android.support.test.InstrumentationRegistry;
import android.view.ViewGroup;
import android.widget.FrameLayout;
+import androidx.test.InstrumentationRegistry;
+
import org.junit.Before;
import org.junit.Test;
diff --git a/core/tests/coretests/src/com/android/internal/widget/ImageFloatingTextViewTest.java b/core/tests/coretests/src/com/android/internal/widget/ImageFloatingTextViewTest.java
index 1806b22..2e0dbb4 100644
--- a/core/tests/coretests/src/com/android/internal/widget/ImageFloatingTextViewTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/ImageFloatingTextViewTest.java
@@ -19,12 +19,13 @@
import static org.junit.Assert.assertTrue;
import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
import android.text.Layout;
import android.view.View.MeasureSpec;
import android.widget.TextView;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
diff --git a/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java b/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java
index f73950a..6167c4b 100644
--- a/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java
@@ -20,8 +20,9 @@
import static org.junit.Assert.assertTrue;
import android.os.UserHandle;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/com/android/internal/widget/MessagingLinearLayoutTest.java b/core/tests/coretests/src/com/android/internal/widget/MessagingLinearLayoutTest.java
index 41082b7..6af7c88 100644
--- a/core/tests/coretests/src/com/android/internal/widget/MessagingLinearLayoutTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/MessagingLinearLayoutTest.java
@@ -21,12 +21,12 @@
import static org.junit.Assert.assertTrue;
import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.text.Layout;
import android.view.LayoutInflater;
import android.view.View.MeasureSpec;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+
import com.android.frameworks.coretests.R;
import org.junit.Before;
diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
index 0dd9d09..28a8afe 100644
--- a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
+++ b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
@@ -318,6 +318,27 @@
mMaxVolume = maxVolume;
mIsMute = isMute;
}
+
+ @Override
+ public void setSystemAudioModeOnForAudioOnlySource() {
+ }
+
+ @Override
+ public int getPhysicalAddress() {
+ return 0x0000;
+ }
+
+ @Override
+ public void powerOffRemoteDevice(int logicalAddress, int powerStatus) {
+ }
+
+ @Override
+ public void powerOnRemoteDevice(int logicalAddress, int powerStatus) {
+ }
+
+ @Override
+ public void askRemoteDeviceToBecomeActiveSource(int physicalAddress) {
+ }
}
}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/Android.mk
index f3d98a8..afbcd46 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/Android.mk
@@ -23,7 +23,7 @@
LOCAL_PACKAGE_NAME := MultiDexLegacyTestServicesTests2
LOCAL_JAVA_LIBRARIES := android-support-multidex
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules
LOCAL_SDK_VERSION := 9
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/AndroidManifest.xml b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/AndroidManifest.xml
index 0ab2959..01285e7 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/AndroidManifest.xml
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/AndroidManifest.xml
@@ -7,7 +7,7 @@
<uses-sdk android:minSdkVersion="9" />
<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"/>
<instrumentation
- android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.framework.multidexlegacytestservices" />
<application
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/src/com/android/framework/multidexlegacytestservices/test2/ServicesTests.java b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/src/com/android/framework/multidexlegacytestservices/test2/ServicesTests.java
index 900f203..f2c72f0 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/src/com/android/framework/multidexlegacytestservices/test2/ServicesTests.java
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/src/com/android/framework/multidexlegacytestservices/test2/ServicesTests.java
@@ -19,22 +19,26 @@
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import junit.framework.Assert;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.concurrent.TimeoutException;
-import junit.framework.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
/**
* Run the tests with: <code>adb shell am instrument -w
- * com.android.framework.multidexlegacytestservices.test2/android.support.test.runner.AndroidJUnitRunner
+ * com.android.framework.multidexlegacytestservices.test2/androidx.test.runner.AndroidJUnitRunner
* </code>
*/
@RunWith(AndroidJUnit4.class)
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index 6ce8148..035ee10 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -39,9 +39,6 @@
name: "privapp-permissions-platform.xml",
sub_dir: "permissions",
src: "privapp-permissions-platform.xml",
- required: [
- "privapp_whitelist_com.android.settings.intelligence",
- ],
}
prebuilt_etc {
@@ -86,6 +83,7 @@
prebuilt_etc {
name: "privapp_whitelist_com.android.settings.intelligence",
+ product_specific: true,
sub_dir: "permissions",
src: "com.android.settings.intelligence.xml",
filename_from_src: true,
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 4a2db0a..fb43e41 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -223,12 +223,12 @@
code to link against. -->
<library name="android.test.base"
- file="/system/framework/android.test.base.impl.jar" />
+ file="/system/framework/android.test.base.jar" />
<library name="android.test.mock"
- file="/system/framework/android.test.mock.impl.jar"
+ file="/system/framework/android.test.mock.jar"
dependency="android.test.base" />
<library name="android.test.runner"
- file="/system/framework/android.test.runner.impl.jar"
+ file="/system/framework/android.test.runner.jar"
dependency="android.test.base:android.test.mock" />
<!-- In BOOT_JARS historically, and now added to legacy applications. -->
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 790b37e..30f0bfa 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -18,9 +18,11 @@
import android.annotation.CheckResult;
import android.annotation.ColorInt;
+import android.annotation.ColorLong;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Size;
+import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
import android.annotation.WorkerThread;
import android.content.res.ResourcesImpl;
@@ -1780,6 +1782,30 @@
}
/**
+ * Fills the bitmap's pixels with the specified {@link Color}.
+ *
+ * @throws IllegalStateException if the bitmap is not mutable.
+ * @throws IllegalArgumentException if the color space encoded in the long
+ * is invalid or unknown.
+ *
+ * @hide pending API approval
+ */
+ @TestApi
+ public void eraseColor(@ColorLong long c) {
+ checkRecycled("Can't erase a recycled bitmap");
+ if (!isMutable()) {
+ throw new IllegalStateException("cannot erase immutable bitmaps");
+ }
+
+ ColorSpace cs = Color.colorSpace(c);
+ float r = Color.red(c);
+ float g = Color.green(c);
+ float b = Color.blue(c);
+ float a = Color.alpha(c);
+ nativeErase(mNativePtr, cs, r, g, b, a);
+ }
+
+ /**
* Returns the {@link Color} at the specified location. Throws an exception
* if x or y are out of bounds (negative or >= to the width or height
* respectively). The returned color is a non-premultiplied ARGB value in
@@ -2123,6 +2149,8 @@
int quality, OutputStream stream,
byte[] tempStorage);
private static native void nativeErase(long nativeBitmap, int color);
+ private static native void nativeErase(long nativeBitmap, ColorSpace cs,
+ float r, float g, float b, float a);
private static native int nativeRowBytes(long nativeBitmap);
private static native int nativeConfig(long nativeBitmap);
diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java
index 95317a4..9fa70a5 100644
--- a/graphics/java/android/graphics/ColorSpace.java
+++ b/graphics/java/android/graphics/ColorSpace.java
@@ -1661,10 +1661,12 @@
* @param rhs 3x3 matrix, as a non-null array of 9 floats
* @return A new array of 9 floats containing the result of the multiplication
* of rhs by lhs
+ *
+ * @hide
*/
@NonNull
@Size(9)
- private static float[] mul3x3(@NonNull @Size(9) float[] lhs, @NonNull @Size(9) float[] rhs) {
+ public static float[] mul3x3(@NonNull @Size(9) float[] lhs, @NonNull @Size(9) float[] rhs) {
float[] r = new float[9];
r[0] = lhs[0] * rhs[0] + lhs[3] * rhs[1] + lhs[6] * rhs[2];
r[1] = lhs[1] * rhs[0] + lhs[4] * rhs[1] + lhs[7] * rhs[2];
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 3342fd2..cbb780d 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -17,12 +17,14 @@
package android.graphics;
import android.annotation.ColorInt;
+import android.annotation.ColorLong;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Px;
import android.annotation.Size;
+import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
import android.graphics.fonts.FontVariationAxis;
import android.os.Build;
@@ -972,6 +974,31 @@
}
/**
+ * Set the paint's color with a {@link ColorLong}. Note that the color is
+ * a long with an encoded {@link ColorSpace} as well as alpha and r,g,b.
+ * These values are not premultiplied, meaning that alpha can be any value,
+ * regardless of the values of r,g,b. See the {@link Color} class for more
+ * details.
+ *
+ * @param color The new color (including alpha and {@link ColorSpace})
+ * to set in the paint.
+ * @throws IllegalArgumentException if the color space encoded in the long
+ * is invalid or unknown.
+ *
+ * @hide pending API approval
+ */
+ @TestApi
+ public void setColor(@ColorLong long color) {
+ ColorSpace cs = Color.colorSpace(color);
+ float r = Color.red(color);
+ float g = Color.green(color);
+ float b = Color.blue(color);
+ float a = Color.alpha(color);
+
+ nSetColor(mNativePaint, cs, r, g, b, a);
+ }
+
+ /**
* Helper to getColor() that just returns the color's alpha value. This is
* the same as calling getColor() >>> 24. It always returns a value between
* 0 (completely transparent) and 255 (completely opaque).
@@ -1370,12 +1397,45 @@
* The alpha of the shadow will be the paint's alpha if the shadow color is
* opaque, or the alpha from the shadow color if not.
*/
- public void setShadowLayer(float radius, float dx, float dy, int shadowColor) {
- mShadowLayerRadius = radius;
- mShadowLayerDx = dx;
- mShadowLayerDy = dy;
- mShadowLayerColor = shadowColor;
- nSetShadowLayer(mNativePaint, radius, dx, dy, shadowColor);
+ public void setShadowLayer(float radius, float dx, float dy, @ColorInt int shadowColor) {
+ mShadowLayerRadius = radius;
+ mShadowLayerDx = dx;
+ mShadowLayerDy = dy;
+ mShadowLayerColor = shadowColor;
+ // FIXME: Share a single native method with the ColorLong version.
+ nSetShadowLayer(mNativePaint, radius, dx, dy, shadowColor);
+ }
+
+ /**
+ * This draws a shadow layer below the main layer, with the specified
+ * offset and color, and blur radius. If radius is 0, then the shadow
+ * layer is removed.
+ * <p>
+ * Can be used to create a blurred shadow underneath text. Support for use
+ * with other drawing operations is constrained to the software rendering
+ * pipeline.
+ * <p>
+ * The alpha of the shadow will be the paint's alpha if the shadow color is
+ * opaque, or the alpha from the shadow color if not.
+ *
+ * @throws IllegalArgumentException if the color space encoded in the long
+ * is invalid or unknown.
+ *
+ * @hide pending API approval
+ */
+ @TestApi
+ public void setShadowLayer(float radius, float dx, float dy, @ColorLong long shadowColor) {
+ ColorSpace cs = Color.colorSpace(shadowColor);
+ float r = Color.red(shadowColor);
+ float g = Color.green(shadowColor);
+ float b = Color.blue(shadowColor);
+ float a = Color.alpha(shadowColor);
+ nSetShadowLayer(mNativePaint, radius, dx, dy, cs, r, g, b, a);
+
+ mShadowLayerRadius = radius;
+ mShadowLayerDx = dx;
+ mShadowLayerDy = dy;
+ mShadowLayerColor = Color.toArgb(shadowColor);
}
/**
@@ -2906,6 +2966,11 @@
int contextStart, int contextEnd, boolean isRtl, int offset);
private static native int nGetOffsetForAdvance(long paintPtr, char[] text, int start, int end,
int contextStart, int contextEnd, boolean isRtl, float advance);
+ private static native void nSetColor(long paintPtr, ColorSpace cs,
+ float r, float g, float b, float a);
+ private static native void nSetShadowLayer(long paintPtr,
+ float radius, float dx, float dy, ColorSpace cs,
+ float r, float g, float b, float a);
// ---------------- @FastNative ------------------------
@@ -2961,7 +3026,7 @@
int mMinikinLocaleListId);
@CriticalNative
private static native void nSetShadowLayer(long paintPtr,
- float radius, float dx, float dy, int color);
+ float radius, float dx, float dy, @ColorInt int color);
@CriticalNative
private static native boolean nHasShadowLayer(long paintPtr);
@CriticalNative
diff --git a/libs/androidfw/AttributeResolution.cpp b/libs/androidfw/AttributeResolution.cpp
index 3dc1f2c..18d74ef 100644
--- a/libs/androidfw/AttributeResolution.cpp
+++ b/libs/androidfw/AttributeResolution.cpp
@@ -286,6 +286,7 @@
value.dataType = Res_value::TYPE_NULL;
value.data = Res_value::DATA_NULL_UNDEFINED;
config.density = 0;
+ uint32_t source_style_resid = 0;
// Try to find a value for this attribute... we prioritize values
// coming from, first XML attributes, then XML style, then default
@@ -309,6 +310,7 @@
cookie = entry->cookie;
type_set_flags = style_flags;
value = entry->value;
+ source_style_resid = entry->style;
if (kDebugStyles) {
ALOGI("-> From style: type=0x%x, data=0x%08x, style=0x%08x", value.dataType, value.data,
entry->style);
@@ -325,8 +327,10 @@
type_set_flags = def_style_flags;
value = entry->value;
if (kDebugStyles) {
- ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
+ ALOGI("-> From def style: type=0x%x, data=0x%08x, style=0x%08x", value.dataType, value.data,
+ entry->style);
}
+ source_style_resid = entry->style;
}
}
@@ -382,6 +386,7 @@
out_values[STYLE_RESOURCE_ID] = resid;
out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
out_values[STYLE_DENSITY] = config.density;
+ out_values[SYTLE_SOURCE_STYLE] = source_style_resid;
if (value.dataType != Res_value::TYPE_NULL || value.data == Res_value::DATA_NULL_EMPTY) {
indices_idx++;
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp
index 5a26780..70ce9bc 100644
--- a/libs/androidfw/LoadedArsc.cpp
+++ b/libs/androidfw/LoadedArsc.cpp
@@ -593,7 +593,12 @@
return {};
}
- // Iterate over the overlayable policy chunks
+ std::string name;
+ util::ReadUtf16StringFromDevice(header->name, arraysize(header->name), &name);
+ std::string actor;
+ util::ReadUtf16StringFromDevice(header->actor, arraysize(header->actor), &actor);
+
+ // Iterate over the overlayable policy chunks contained within the overlayable chunk data
ChunkIterator overlayable_iter(child_chunk.data_ptr(), child_chunk.data_size());
while (overlayable_iter.HasNext()) {
const Chunk overlayable_child_chunk = overlayable_iter.Next();
@@ -613,7 +618,7 @@
return {};
}
- // Retrieve all the ids belonging to this policy
+ // Retrieve all the resource ids belonging to this policy chunk
std::unordered_set<uint32_t> ids;
const auto ids_begin =
reinterpret_cast<const ResTable_ref*>(overlayable_child_chunk.data_ptr());
@@ -622,8 +627,10 @@
ids.insert(dtohl(id_iter->ident));
}
- // Add the pairing of overlayable properties to resource ids to the package
+ // Add the pairing of overlayable properties and resource ids to the package
OverlayableInfo overlayable_info{};
+ overlayable_info.name = name;
+ overlayable_info.actor = actor;
overlayable_info.policy_flags = policy_header->policy_flags;
loaded_package->overlayable_infos_.push_back(std::make_pair(overlayable_info, ids));
break;
@@ -636,7 +643,7 @@
}
if (overlayable_iter.HadError()) {
- LOG(ERROR) << StringPrintf("Error parsing RES_TABLE_OVERLAYABLE_POLICY_TYPE: %s",
+ LOG(ERROR) << StringPrintf("Error parsing RES_TABLE_OVERLAYABLE_TYPE: %s",
overlayable_iter.GetLastError().c_str());
if (overlayable_iter.HadFatalError()) {
return {};
diff --git a/libs/androidfw/include/androidfw/AttributeResolution.h b/libs/androidfw/include/androidfw/AttributeResolution.h
index 35ef98d..c88004c 100644
--- a/libs/androidfw/include/androidfw/AttributeResolution.h
+++ b/libs/androidfw/include/androidfw/AttributeResolution.h
@@ -23,15 +23,17 @@
namespace android {
// Offsets into the outValues array populated by the methods below. outValues is a uint32_t
-// array, but each logical element takes up 6 uint32_t-sized physical elements.
+// array, but each logical element takes up 7 uint32_t-sized physical elements.
+// Keep these in sync with android.content.res.TypedArray java class
enum {
- STYLE_NUM_ENTRIES = 6,
+ STYLE_NUM_ENTRIES = 7,
STYLE_TYPE = 0,
STYLE_DATA = 1,
STYLE_ASSET_COOKIE = 2,
STYLE_RESOURCE_ID = 3,
STYLE_CHANGING_CONFIGURATIONS = 4,
- STYLE_DENSITY = 5
+ STYLE_DENSITY = 5,
+ SYTLE_SOURCE_STYLE = 6
};
// These are all variations of the same method. They each perform the exact same operation,
diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h
index 8c5c3b7..be62f30 100644
--- a/libs/androidfw/include/androidfw/LoadedArsc.h
+++ b/libs/androidfw/include/androidfw/LoadedArsc.h
@@ -78,6 +78,8 @@
using TypeSpecPtr = util::unique_cptr<TypeSpec>;
struct OverlayableInfo {
+ std::string name;
+ std::string actor;
uint32_t policy_flags;
};
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index 9b05d1f..6b9ebd3 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -1611,6 +1611,12 @@
struct ResTable_overlayable_header
{
struct ResChunk_header header;
+
+ // The name of the overlayable set of resources that overlays target.
+ uint16_t name[256];
+
+ // The component responsible for enabling and disabling overlays targeting this chunk.
+ uint16_t actor[256];
};
/**
diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp
index 22d587a..2e386a0 100644
--- a/libs/androidfw/tests/LoadedArsc_test.cpp
+++ b/libs/androidfw/tests/LoadedArsc_test.cpp
@@ -294,22 +294,30 @@
info = package->GetOverlayableInfo(overlayable::R::string::overlayable1);
ASSERT_THAT(info, NotNull());
+ EXPECT_THAT(info->name, Eq("OverlayableResources1"));
+ EXPECT_THAT(info->actor, Eq("overlay://theme"));
EXPECT_THAT(info->policy_flags, Eq(ResTable_overlayable_policy_header::POLICY_PUBLIC));
info = package->GetOverlayableInfo(overlayable::R::string::overlayable2);
ASSERT_THAT(info, NotNull());
+ EXPECT_THAT(info->name, Eq("OverlayableResources1"));
+ EXPECT_THAT(info->actor, Eq("overlay://theme"));
EXPECT_THAT(info->policy_flags,
Eq(ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION
| ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION));
info = package->GetOverlayableInfo(overlayable::R::string::overlayable3);
ASSERT_THAT(info, NotNull());
+ EXPECT_THAT(info->name, Eq("OverlayableResources2"));
+ EXPECT_THAT(info->actor, Eq("overlay://com.android.overlayable"));
EXPECT_THAT(info->policy_flags,
Eq(ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION
| ResTable_overlayable_policy_header::POLICY_PRODUCT_SERVICES_PARTITION
| ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION));
info = package->GetOverlayableInfo(overlayable::R::string::overlayable4);
+ EXPECT_THAT(info->name, Eq("OverlayableResources1"));
+ EXPECT_THAT(info->actor, Eq("overlay://theme"));
ASSERT_THAT(info, NotNull());
EXPECT_THAT(info->policy_flags, Eq(ResTable_overlayable_policy_header::POLICY_PUBLIC));
}
diff --git a/libs/androidfw/tests/data/overlayable/overlayable.apk b/libs/androidfw/tests/data/overlayable/overlayable.apk
index 85ab4be..8634747 100644
--- a/libs/androidfw/tests/data/overlayable/overlayable.apk
+++ b/libs/androidfw/tests/data/overlayable/overlayable.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml b/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml
index 11aa735..dba7b08 100644
--- a/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml
+++ b/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml
@@ -15,7 +15,7 @@
-->
<resources>
-<overlayable>
+<overlayable name="OverlayableResources1" actor="overlay://theme">
<!-- Any overlay can overlay the value of @string/overlayable1 -->
<item type="string" name="overlayable1" />
@@ -31,9 +31,9 @@
</policy>
</overlayable>
-<overlayable>
+<overlayable name="OverlayableResources2" actor="overlay://com.android.overlayable">
<!-- Any overlay on the product_services, vendor, or product partition can overlay the value of
- @string/overlayable3 -->
+ @string/overlayable3 -->
<policy type="product_services|vendor|product">
<item type="string" name="overlayable3" />
</policy>
diff --git a/libs/hwui/WebViewFunctorManager.cpp b/libs/hwui/WebViewFunctorManager.cpp
index 9170d6d..68541b4 100644
--- a/libs/hwui/WebViewFunctorManager.cpp
+++ b/libs/hwui/WebViewFunctorManager.cpp
@@ -86,6 +86,26 @@
mCallbacks.gles.draw(mFunctor, mData, drawInfo);
}
+void WebViewFunctor::initVk(const VkFunctorInitParams& params) {
+ ATRACE_NAME("WebViewFunctor::initVk");
+ if (!mHasContext) {
+ mHasContext = true;
+ } else {
+ return;
+ }
+ mCallbacks.vk.initialize(mFunctor, mData, params);
+}
+
+void WebViewFunctor::drawVk(const VkFunctorDrawParams& params) {
+ ATRACE_NAME("WebViewFunctor::drawVk");
+ mCallbacks.vk.draw(mFunctor, mData, params);
+}
+
+void WebViewFunctor::postDrawVk() {
+ ATRACE_NAME("WebViewFunctor::postDrawVk");
+ mCallbacks.vk.postDraw(mFunctor, mData);
+}
+
void WebViewFunctor::destroyContext() {
if (mHasContext) {
mHasContext = false;
diff --git a/libs/hwui/WebViewFunctorManager.h b/libs/hwui/WebViewFunctorManager.h
index 1719ce7..2846cb1 100644
--- a/libs/hwui/WebViewFunctorManager.h
+++ b/libs/hwui/WebViewFunctorManager.h
@@ -42,6 +42,12 @@
void drawGl(const DrawGlInfo& drawInfo) const { mReference.drawGl(drawInfo); }
+ void initVk(const VkFunctorInitParams& params) { mReference.initVk(params); }
+
+ void drawVk(const VkFunctorDrawParams& params) { mReference.drawVk(params); }
+
+ void postDrawVk() { mReference.postDrawVk(); }
+
private:
friend class WebViewFunctor;
@@ -53,6 +59,9 @@
int id() const { return mFunctor; }
void sync(const WebViewSyncData& syncData) const;
void drawGl(const DrawGlInfo& drawInfo);
+ void initVk(const VkFunctorInitParams& params);
+ void drawVk(const VkFunctorDrawParams& params);
+ void postDrawVk();
void destroyContext();
sp<Handle> createHandle() {
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index 4338b1c..e6e6b0e 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -96,7 +96,7 @@
SkASSERT(mRenderThread.getGrContext() != nullptr);
sk_sp<SkSurface> surface(SkSurface::MakeFromBackendRenderTarget(
- mRenderThread.getGrContext(), backendRT, kBottomLeft_GrSurfaceOrigin, colorType,
+ mRenderThread.getGrContext(), backendRT, this->getSurfaceOrigin(), colorType,
mSurfaceColorSpace, &props));
SkiaPipeline::updateLighting(lightGeometry, lightInfo);
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
index 47991069..6692922 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
@@ -39,6 +39,7 @@
const Rect& contentDrawBounds, bool opaque, const LightInfo& lightInfo,
const std::vector<sp<RenderNode> >& renderNodes,
FrameInfoVisualizer* profiler) override;
+ GrSurfaceOrigin getSurfaceOrigin() override { return kBottomLeft_GrSurfaceOrigin; }
bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty,
FrameInfo* currentFrameInfo, bool* requireSwap) override;
DeferredLayerUpdater* createTextureLayer() override;
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 2e7850d..d7faaf7 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -174,7 +174,8 @@
SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
SkASSERT(mRenderThread.getGrContext() != nullptr);
node->setLayerSurface(SkSurface::MakeRenderTarget(mRenderThread.getGrContext(),
- SkBudgeted::kYes, info, 0, &props));
+ SkBudgeted::kYes, info, 0,
+ this->getSurfaceOrigin(), &props));
if (node->getLayerSurface()) {
// update the transform in window of the layer to reset its origin wrt light source
// position
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
index ff87313..94a699b 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -48,7 +48,7 @@
bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator,
ErrorHandler* errorHandler) override;
- SkColorType getSurfaceColorType() const { return mSurfaceColorType; }
+ SkColorType getSurfaceColorType() const override { return mSurfaceColorType; }
sk_sp<SkColorSpace> getSurfaceColorSpace() override { return mSurfaceColorSpace; }
void renderFrame(const LayerUpdateQueue& layers, const SkRect& clip,
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 6eefed9..d54275f 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -125,8 +125,6 @@
uirenderer::GlFunctorLifecycleListener* listener) {
FunctorDrawable* functorDrawable;
if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
- // TODO(cblume) use VkFunctorDrawable instead of VkInteropFunctorDrawable here when the
- // interop is disabled/moved.
functorDrawable = mDisplayList->allocateDrawable<VkInteropFunctorDrawable>(
functor, listener, asSkCanvas());
} else {
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
index 53ffc44..9343076 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
@@ -35,6 +35,7 @@
const Rect& contentDrawBounds, bool opaque, const LightInfo& lightInfo,
const std::vector<sp<RenderNode> >& renderNodes,
FrameInfoVisualizer* profiler) override;
+ GrSurfaceOrigin getSurfaceOrigin() override { return kTopLeft_GrSurfaceOrigin; }
bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty,
FrameInfo* currentFrameInfo, bool* requireSwap) override;
DeferredLayerUpdater* createTextureLayer() override;
diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
index 156f74a..2f8d381 100644
--- a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
@@ -17,6 +17,8 @@
#include "VkFunctorDrawable.h"
#include <private/hwui/DrawVkInfo.h>
+#include "renderthread/VulkanManager.h"
+#include "renderthread/RenderThread.h"
#include <GrBackendDrawableInfo.h>
#include <SkImage.h>
#include <utils/Color.h>
@@ -31,34 +33,58 @@
namespace uirenderer {
namespace skiapipeline {
-VkFunctorDrawHandler::VkFunctorDrawHandler(Functor* functor) : INHERITED(), mFunctor(functor) {}
+VkFunctorDrawHandler::VkFunctorDrawHandler(sp<WebViewFunctor::Handle> functor_handle,
+ const SkMatrix& matrix, const SkIRect& clip,
+ const SkImageInfo& image_info)
+ : INHERITED()
+ , mFunctorHandle(functor_handle)
+ , mMatrix(matrix)
+ , mClip(clip)
+ , mImageInfo(image_info) {}
VkFunctorDrawHandler::~VkFunctorDrawHandler() {
- // TODO(cblume) Fill in the DrawVkInfo parameters.
- (*mFunctor)(DrawVkInfo::kModePostComposite, nullptr);
+ mFunctorHandle->postDrawVk();
}
void VkFunctorDrawHandler::draw(const GrBackendDrawableInfo& info) {
ATRACE_CALL();
+ if (!renderthread::RenderThread::isCurrent())
+ LOG_ALWAYS_FATAL("VkFunctorDrawHandler::draw not called on render thread");
GrVkDrawableInfo vulkan_info;
if (!info.getVkDrawableInfo(&vulkan_info)) {
return;
}
+ renderthread::VulkanManager& vk_manager =
+ renderthread::RenderThread::getInstance().vulkanManager();
+ mFunctorHandle->initVk(vk_manager.getVkFunctorInitParams());
- DrawVkInfo draw_vk_info;
- // TODO(cblume) Fill in the rest of the parameters and test the actual call.
- draw_vk_info.isLayer = true;
+ SkMatrix44 mat4(mMatrix);
+ VkFunctorDrawParams params{
+ .width = mImageInfo.width(),
+ .height = mImageInfo.height(),
+ .is_layer = false, // TODO(boliu): Populate is_layer.
+ .color_space_ptr = mImageInfo.colorSpace(),
+ .clip_left = mClip.fLeft,
+ .clip_top = mClip.fTop,
+ .clip_right = mClip.fRight,
+ .clip_bottom = mClip.fBottom,
+ };
+ mat4.asColMajorf(¶ms.transform[0]);
+ params.secondary_command_buffer = vulkan_info.fSecondaryCommandBuffer;
+ params.color_attachment_index = vulkan_info.fColorAttachmentIndex;
+ params.compatible_render_pass = vulkan_info.fCompatibleRenderPass;
+ params.format = vulkan_info.fFormat;
- (*mFunctor)(DrawVkInfo::kModeComposite, &draw_vk_info);
+ mFunctorHandle->drawVk(params);
+
+ vulkan_info.fDrawBounds->offset.x = mClip.fLeft;
+ vulkan_info.fDrawBounds->offset.y = mClip.fTop;
+ vulkan_info.fDrawBounds->extent.width = mClip.fRight - mClip.fLeft;
+ vulkan_info.fDrawBounds->extent.height = mClip.fBottom - mClip.fTop;
}
VkFunctorDrawable::~VkFunctorDrawable() {
- if (auto lp = std::get_if<LegacyFunctor>(&mAnyFunctor)) {
- if (lp->listener) {
- lp->listener->onGlFunctorReleased(lp->functor);
- }
- }
}
void VkFunctorDrawable::onDraw(SkCanvas* /*canvas*/) {
@@ -67,16 +93,17 @@
}
std::unique_ptr<FunctorDrawable::GpuDrawHandler> VkFunctorDrawable::onSnapGpuDrawHandler(
- GrBackendApi backendApi, const SkMatrix& matrix) {
+ GrBackendApi backendApi, const SkMatrix& matrix, const SkIRect& clip,
+ const SkImageInfo& image_info) {
if (backendApi != GrBackendApi::kVulkan) {
return nullptr;
}
std::unique_ptr<VkFunctorDrawHandler> draw;
if (mAnyFunctor.index() == 0) {
- LOG_ALWAYS_FATAL("Not implemented");
- return nullptr;
+ return std::make_unique<VkFunctorDrawHandler>(std::get<0>(mAnyFunctor).handle, matrix, clip,
+ image_info);
} else {
- return std::make_unique<VkFunctorDrawHandler>(std::get<1>(mAnyFunctor).functor);
+ LOG_ALWAYS_FATAL("Not implemented");
}
}
diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.h b/libs/hwui/pipeline/skia/VkFunctorDrawable.h
index d6fefc1..1a53c8f 100644
--- a/libs/hwui/pipeline/skia/VkFunctorDrawable.h
+++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.h
@@ -32,15 +32,18 @@
*/
class VkFunctorDrawHandler : public FunctorDrawable::GpuDrawHandler {
public:
- explicit VkFunctorDrawHandler(Functor* functor);
+ VkFunctorDrawHandler(sp<WebViewFunctor::Handle> functor_handle, const SkMatrix& matrix,
+ const SkIRect& clip, const SkImageInfo& image_info);
~VkFunctorDrawHandler() override;
void draw(const GrBackendDrawableInfo& info) override;
private:
typedef GpuDrawHandler INHERITED;
-
- Functor* mFunctor;
+ sp<WebViewFunctor::Handle> mFunctorHandle;
+ const SkMatrix mMatrix;
+ const SkIRect mClip;
+ const SkImageInfo mImageInfo;
};
/**
@@ -57,7 +60,8 @@
// SkDrawable functions:
void onDraw(SkCanvas* canvas) override;
std::unique_ptr<FunctorDrawable::GpuDrawHandler> onSnapGpuDrawHandler(
- GrBackendApi backendApi, const SkMatrix& matrix) override;
+ GrBackendApi backendApi, const SkMatrix& matrix, const SkIRect& clip,
+ const SkImageInfo& image_info) override;
};
} // namespace skiapipeline
diff --git a/libs/hwui/private/hwui/DrawVkInfo.h b/libs/hwui/private/hwui/DrawVkInfo.h
index fd824bd..abc4dbf 100644
--- a/libs/hwui/private/hwui/DrawVkInfo.h
+++ b/libs/hwui/private/hwui/DrawVkInfo.h
@@ -17,80 +17,61 @@
#ifndef ANDROID_HWUI_DRAW_VK_INFO_H
#define ANDROID_HWUI_DRAW_VK_INFO_H
+#include <SkColorSpace.h>
#include <vulkan/vulkan.h>
namespace android {
namespace uirenderer {
-/**
- * Structure used by VulkanRenderer::callDrawVKFunction() to pass and receive data from Vulkan
- * functors.
- */
-struct DrawVkInfo {
- // Input: current width/height of destination surface
- int width;
- int height;
+struct VkFunctorInitParams {
+ VkInstance instance;
+ VkPhysicalDevice physical_device;
+ VkDevice device;
+ VkQueue queue;
+ uint32_t graphics_queue_index;
+ uint32_t instance_version;
+ const char* const* enabled_instance_extension_names;
+ uint32_t enabled_instance_extension_names_length;
+ const char* const* enabled_device_extension_names;
+ uint32_t enabled_device_extension_names_length;
+ const VkPhysicalDeviceFeatures2* device_features_2;
+};
- // Input: is the render target an FBO
- bool isLayer;
+struct VkFunctorDrawParams {
+ // Input: current width/height of destination surface.
+ int width;
+ int height;
- // Input: current transform matrix, in OpenGL format
- float transform[16];
+ // Input: is the render target a FBO
+ bool is_layer;
- // Input: WebView should do its main compositing draws into this. It cannot do anything that
- // would require stopping the render pass.
- VkCommandBuffer secondaryCommandBuffer;
+ // Input: current transform matrix
+ float transform[16];
- // Input: The main color attachment index where secondaryCommandBuffer will eventually be
- // submitted.
- uint32_t colorAttachmentIndex;
+ // Input WebView should do its main compositing draws into this. It cannot do
+ // anything that would require stopping the render pass.
+ VkCommandBuffer secondary_command_buffer;
- // Input: A render pass which will be compatible to the one which the secondaryCommandBuffer
- // will be submitted into.
- VkRenderPass compatibleRenderPass;
+ // Input: The main color attachment index where secondary_command_buffer will
+ // eventually be submitted.
+ uint32_t color_attachment_index;
- // Input: Format of the destination surface.
- VkFormat format;
+ // Input: A render pass which will be compatible to the one which the
+ // secondary_command_buffer will be submitted into.
+ VkRenderPass compatible_render_pass;
- // Input: Color space
- const SkColorSpace* colorSpaceInfo;
+ // Input: Format of the destination surface.
+ VkFormat format;
- // Input: current clip rect
- int clipLeft;
- int clipTop;
- int clipRight;
- int clipBottom;
+ // Input: Color space.
+ const SkColorSpace* color_space_ptr;
- /**
- * Values used as the "what" parameter of the functor.
- */
- enum Mode {
- // Called once at WebView start
- kModeInit,
- // Called when things need to be re-created
- kModeReInit,
- // Notifies the app that the composite functor will be called soon. This allows WebView to
- // begin work early.
- kModePreComposite,
- // Do the actual composite work
- kModeComposite,
- // This allows WebView to begin using the previously submitted objects in future work.
- kModePostComposite,
- // Invoked every time the UI thread pushes over a frame to the render thread and the owning
- // view has a dirty display list*. This is a signal to sync any data that needs to be
- // shared between the UI thread and the render thread. During this time the UI thread is
- // blocked.
- kModeSync
- };
-
- /**
- * Values used by Vulkan functors to tell the framework what to do next.
- */
- enum Status {
- // The functor is done
- kStatusDone = 0x0,
- };
-}; // struct DrawVkInfo
+ // Input: current clip rect
+ int clip_left;
+ int clip_top;
+ int clip_right;
+ int clip_bottom;
+};
} // namespace uirenderer
} // namespace android
diff --git a/libs/hwui/private/hwui/WebViewFunctor.h b/libs/hwui/private/hwui/WebViewFunctor.h
index da3d06a..96da947 100644
--- a/libs/hwui/private/hwui/WebViewFunctor.h
+++ b/libs/hwui/private/hwui/WebViewFunctor.h
@@ -19,6 +19,7 @@
#include <cutils/compiler.h>
#include <private/hwui/DrawGlInfo.h>
+#include <private/hwui/DrawVkInfo.h>
namespace android::uirenderer {
@@ -52,18 +53,12 @@
// Called on RenderThread. initialize is guaranteed to happen before this call
void (*draw)(int functor, void* data, const DrawGlInfo& params);
} gles;
- // TODO: VK support. The current DrawVkInfo is monolithic and needs to be split up for
- // what params are valid on what callbacks
struct {
// Called either the first time the functor is used or the first time it's used after
// a call to onContextDestroyed.
- // void (*initialize)(int functor, const InitParams& params);
- // void (*frameStart)(int functor, /* todo: what params are actually needed for this to
- // be useful? Is this useful? */)
- // void (*draw)(int functor, const CompositeParams& params /* todo: rename - composite
- // almost always means something else, and we aren't compositing */);
- // void (*frameEnd)(int functor, const PostCompositeParams& params /* todo: same as
- // CompositeParams - rename */);
+ void (*initialize)(int functor, void* data, const VkFunctorInitParams& params);
+ void (*draw)(int functor, void* data, const VkFunctorDrawParams& params);
+ void (*postDraw)(int functor, void*);
} vk;
};
};
diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h
index 42e17b273..d4dd629 100644
--- a/libs/hwui/renderthread/IRenderPipeline.h
+++ b/libs/hwui/renderthread/IRenderPipeline.h
@@ -84,6 +84,7 @@
virtual void onPrepareTree() = 0;
virtual SkColorType getSurfaceColorType() const = 0;
virtual sk_sp<SkColorSpace> getSurfaceColorSpace() = 0;
+ virtual GrSurfaceOrigin getSurfaceOrigin() = 0;
virtual ~IRenderPipeline() {}
};
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index c06fadd..8bef359 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -171,6 +171,9 @@
mRenderState = new RenderState(*this);
mVkManager = new VulkanManager(*this);
mCacheManager = new CacheManager(mDisplayInfo);
+ if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
+ mVkManager->initialize();
+ }
}
void RenderThread::requireGlContext() {
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index 5272227..1ef83fb 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -47,6 +47,10 @@
class RenderState;
class TestUtils;
+namespace skiapipeline {
+class VkFunctorDrawHandler;
+}
+
namespace renderthread {
class CanvasContext;
@@ -124,6 +128,7 @@
friend class DummyVsyncSource;
friend class android::uirenderer::TestUtils;
friend class android::uirenderer::WebViewFunctor;
+ friend class android::uirenderer::skiapipeline::VkFunctorDrawHandler;
RenderThread();
virtual ~RenderThread();
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index aa7a141..6c540f6 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -34,6 +34,23 @@
namespace uirenderer {
namespace renderthread {
+static void free_features_extensions_structs(const VkPhysicalDeviceFeatures2& features) {
+ // All Vulkan structs that could be part of the features chain will start with the
+ // structure type followed by the pNext pointer. We cast to the CommonVulkanHeader
+ // so we can get access to the pNext for the next struct.
+ struct CommonVulkanHeader {
+ VkStructureType sType;
+ void* pNext;
+ };
+
+ void* pNext = features.pNext;
+ while (pNext) {
+ void* current = pNext;
+ pNext = static_cast<CommonVulkanHeader*>(current)->pNext;
+ free(current);
+ }
+}
+
#define GET_PROC(F) m##F = (PFN_vk##F)vkGetInstanceProcAddr(VK_NULL_HANDLE, "vk" #F)
#define GET_INST_PROC(F) m##F = (PFN_vk##F)vkGetInstanceProcAddr(mInstance, "vk" #F)
#define GET_DEV_PROC(F) m##F = (PFN_vk##F)vkGetDeviceProcAddr(mDevice, "vk" #F)
@@ -66,6 +83,11 @@
mDevice = VK_NULL_HANDLE;
mPhysicalDevice = VK_NULL_HANDLE;
mInstance = VK_NULL_HANDLE;
+ mInstanceVersion = 0u;
+ mInstanceExtensions.clear();
+ mDeviceExtensions.clear();
+ free_features_extensions_structs(mPhysicalDeviceFeatures2);
+ mPhysicalDeviceFeatures2 = {};
}
bool VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFeatures2& features) {
@@ -81,7 +103,6 @@
VK_MAKE_VERSION(1, 1, 0), // apiVersion
};
- std::vector<const char*> instanceExtensions;
{
GET_PROC(EnumerateInstanceExtensionProperties);
@@ -99,7 +120,7 @@
bool hasKHRSurfaceExtension = false;
bool hasKHRAndroidSurfaceExtension = false;
for (uint32_t i = 0; i < extensionCount; ++i) {
- instanceExtensions.push_back(extensions[i].extensionName);
+ mInstanceExtensions.push_back(extensions[i].extensionName);
if (!strcmp(extensions[i].extensionName, VK_KHR_SURFACE_EXTENSION_NAME)) {
hasKHRSurfaceExtension = true;
}
@@ -120,8 +141,8 @@
&app_info, // pApplicationInfo
0, // enabledLayerNameCount
nullptr, // ppEnabledLayerNames
- (uint32_t) instanceExtensions.size(), // enabledExtensionNameCount
- instanceExtensions.data(), // ppEnabledExtensionNames
+ (uint32_t) mInstanceExtensions.size(), // enabledExtensionNameCount
+ mInstanceExtensions.data(), // ppEnabledExtensionNames
};
GET_PROC(CreateInstance);
@@ -201,7 +222,6 @@
// presentation with any native window. So just use the first one.
mPresentQueueIndex = 0;
- std::vector<const char*> deviceExtensions;
{
uint32_t extensionCount = 0;
err = mEnumerateDeviceExtensionProperties(mPhysicalDevice, nullptr, &extensionCount,
@@ -220,7 +240,7 @@
}
bool hasKHRSwapchainExtension = false;
for (uint32_t i = 0; i < extensionCount; ++i) {
- deviceExtensions.push_back(extensions[i].extensionName);
+ mDeviceExtensions.push_back(extensions[i].extensionName);
if (!strcmp(extensions[i].extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME)) {
hasKHRSwapchainExtension = true;
}
@@ -237,8 +257,8 @@
}
return vkGetInstanceProcAddr(instance, proc_name);
};
- grExtensions.init(getProc, mInstance, mPhysicalDevice, instanceExtensions.size(),
- instanceExtensions.data(), deviceExtensions.size(), deviceExtensions.data());
+ grExtensions.init(getProc, mInstance, mPhysicalDevice, mInstanceExtensions.size(),
+ mInstanceExtensions.data(), mDeviceExtensions.size(), mDeviceExtensions.data());
if (!grExtensions.hasExtension(VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, 1)) {
this->destroy();
@@ -308,8 +328,8 @@
queueInfo, // pQueueCreateInfos
0, // layerCount
nullptr, // ppEnabledLayerNames
- (uint32_t) deviceExtensions.size(), // extensionCount
- deviceExtensions.data(), // ppEnabledExtensionNames
+ (uint32_t) mDeviceExtensions.size(), // extensionCount
+ mDeviceExtensions.data(), // ppEnabledExtensionNames
nullptr, // ppEnabledFeatures
};
@@ -351,36 +371,17 @@
return true;
}
-static void free_features_extensions_structs(const VkPhysicalDeviceFeatures2& features) {
- // All Vulkan structs that could be part of the features chain will start with the
- // structure type followed by the pNext pointer. We cast to the CommonVulkanHeader
- // so we can get access to the pNext for the next struct.
- struct CommonVulkanHeader {
- VkStructureType sType;
- void* pNext;
- };
-
- void* pNext = features.pNext;
- while (pNext) {
- void* current = pNext;
- pNext = static_cast<CommonVulkanHeader*>(current)->pNext;
- free(current);
- }
-}
-
void VulkanManager::initialize() {
if (mDevice != VK_NULL_HANDLE) {
return;
}
GET_PROC(EnumerateInstanceVersion);
- uint32_t instanceVersion = 0;
- LOG_ALWAYS_FATAL_IF(mEnumerateInstanceVersion(&instanceVersion));
- LOG_ALWAYS_FATAL_IF(instanceVersion < VK_MAKE_VERSION(1, 1, 0));
+ LOG_ALWAYS_FATAL_IF(mEnumerateInstanceVersion(&mInstanceVersion));
+ LOG_ALWAYS_FATAL_IF(mInstanceVersion < VK_MAKE_VERSION(1, 1, 0));
GrVkExtensions extensions;
- VkPhysicalDeviceFeatures2 features;
- LOG_ALWAYS_FATAL_IF(!this->setupDevice(extensions, features));
+ LOG_ALWAYS_FATAL_IF(!this->setupDevice(extensions, mPhysicalDeviceFeatures2));
mGetDeviceQueue(mDevice, mGraphicsQueueIndex, 0, &mGraphicsQueue);
@@ -397,9 +398,9 @@
backendContext.fDevice = mDevice;
backendContext.fQueue = mGraphicsQueue;
backendContext.fGraphicsQueueIndex = mGraphicsQueueIndex;
- backendContext.fInstanceVersion = instanceVersion;
+ backendContext.fInstanceVersion = mInstanceVersion;
backendContext.fVkExtensions = &extensions;
- backendContext.fDeviceFeatures2 = &features;
+ backendContext.fDeviceFeatures2 = &mPhysicalDeviceFeatures2;
backendContext.fGetProc = std::move(getProc);
// create the command pool for the command buffers
@@ -433,13 +434,29 @@
LOG_ALWAYS_FATAL_IF(!grContext.get());
mRenderThread.setGrContext(grContext);
- free_features_extensions_structs(features);
-
if (Properties::enablePartialUpdates && Properties::useBufferAge) {
mSwapBehavior = SwapBehavior::BufferAge;
}
}
+VkFunctorInitParams VulkanManager::getVkFunctorInitParams() const {
+ return VkFunctorInitParams{
+ .instance = mInstance,
+ .physical_device = mPhysicalDevice,
+ .device = mDevice,
+ .queue = mGraphicsQueue,
+ .graphics_queue_index = mGraphicsQueueIndex,
+ .instance_version = mInstanceVersion,
+ .enabled_instance_extension_names = mInstanceExtensions.data(),
+ .enabled_instance_extension_names_length =
+ static_cast<uint32_t>(mInstanceExtensions.size()),
+ .enabled_device_extension_names = mDeviceExtensions.data(),
+ .enabled_device_extension_names_length =
+ static_cast<uint32_t>(mDeviceExtensions.size()),
+ .device_features_2 = &mPhysicalDeviceFeatures2,
+ };
+}
+
// Returns the next BackbufferInfo to use for the next draw. The function will make sure all
// previous uses have finished before returning.
VulkanSurface::BackbufferInfo* VulkanManager::getAvailableBackbuffer(VulkanSurface* surface) {
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index 9eb942c..105ee09 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -132,6 +132,9 @@
// Creates a fence that is signaled, when all the pending Vulkan commands are flushed.
status_t createReleaseFence(sp<Fence>& nativeFence);
+ // Returned pointers are owned by VulkanManager.
+ VkFunctorInitParams getVkFunctorInitParams() const;
+
private:
friend class RenderThread;
@@ -234,6 +237,12 @@
VkCommandBuffer mDummyCB = VK_NULL_HANDLE;
+ // Variables saved to populate VkFunctorInitParams.
+ uint32_t mInstanceVersion = 0u;
+ std::vector<const char*> mInstanceExtensions;
+ std::vector<const char*> mDeviceExtensions;
+ VkPhysicalDeviceFeatures2 mPhysicalDeviceFeatures2{};
+
enum class SwapBehavior {
Discard,
BufferAge,
diff --git a/libs/services/include/android/os/DropBoxManager.h b/libs/services/include/android/os/DropBoxManager.h
index 75b26c6..0747243 100644
--- a/libs/services/include/android/os/DropBoxManager.h
+++ b/libs/services/include/android/os/DropBoxManager.h
@@ -62,7 +62,7 @@
// file descriptor.
Status addFile(const String16& tag, int fd, int flags);
- class Entry : public virtual RefBase, public Parcelable {
+ class Entry : public Parcelable {
public:
Entry();
virtual ~Entry();
@@ -89,9 +89,6 @@
friend class DropBoxManager;
};
- // Get the next entry from the drop box after the specified time.
- Status getNextEntry(const String16& tag, long msec, Entry* entry);
-
private:
enum {
HAS_BYTE_ARRAY = 8
diff --git a/libs/services/src/os/DropBoxManager.cpp b/libs/services/src/os/DropBoxManager.cpp
index 8282518..681d5f7 100644
--- a/libs/services/src/os/DropBoxManager.cpp
+++ b/libs/services/src/os/DropBoxManager.cpp
@@ -228,15 +228,4 @@
return service->add(entry);
}
-Status
-DropBoxManager::getNextEntry(const String16& tag, long msec, Entry* entry)
-{
- sp<IDropBoxManagerService> service = interface_cast<IDropBoxManagerService>(
- defaultServiceManager()->getService(android::String16("dropbox")));
- if (service == NULL) {
- return Status::fromExceptionCode(Status::EX_NULL_POINTER, "can't find dropbox service");
- }
- return service->getNextEntry(tag, msec, android::String16("android"), entry);
-}
-
}} // namespace android::os
diff --git a/location/java/android/location/GnssMeasurement.java b/location/java/android/location/GnssMeasurement.java
index f179bc3..602cc3e 100644
--- a/location/java/android/location/GnssMeasurement.java
+++ b/location/java/android/location/GnssMeasurement.java
@@ -48,6 +48,7 @@
private int mMultipathIndicator;
private double mSnrInDb;
private double mAutomaticGainControlLevelInDb;
+ private int mCodeType;
// The following enumerations must be in sync with the values declared in gps.h
@@ -58,6 +59,7 @@
private static final int HAS_CARRIER_PHASE = (1<<11);
private static final int HAS_CARRIER_PHASE_UNCERTAINTY = (1<<12);
private static final int HAS_AUTOMATIC_GAIN_CONTROL = (1<<13);
+ private static final int HAS_CODE_TYPE = (1 << 14);
/**
* The status of the multipath indicator.
@@ -202,6 +204,104 @@
public static final int ADR_STATE_HALF_CYCLE_REPORTED = (1<<4);
/**
+ * GNSS measurement code type.
+ * @hide
+ */
+ @IntDef(prefix = { "CODE_TYPE_" }, value = {
+ CODE_TYPE_UNKNOWN, CODE_TYPE_A, CODE_TYPE_B, CODE_TYPE_C, CODE_TYPE_I, CODE_TYPE_L,
+ CODE_TYPE_M, CODE_TYPE_P, CODE_TYPE_Q, CODE_TYPE_S, CODE_TYPE_W, CODE_TYPE_X,
+ CODE_TYPE_Y, CODE_TYPE_Z, CODE_TYPE_CODELESS
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface CodeType {}
+
+ /** The GNSS Measurement's code type is unknown. */
+ public static final int CODE_TYPE_UNKNOWN = -1;
+
+ /**
+ * The GNSS Measurement's code type is one of the following: GALILEO E1A, GALILEO E6A, IRNSS
+ * L5A, IRNSS SA.
+ */
+ public static final int CODE_TYPE_A = 0;
+
+ /**
+ * The GNSS Measurement's code type is one of the following: GALILEO E1B, GALILEO E6B, IRNSS
+ * L5B, IRNSS SB.
+ */
+ public static final int CODE_TYPE_B = 1;
+
+ /**
+ * The GNSS Measurement's code type is one of the following: GPS L1 C/A, GPS L2 C/A, GLONASS G1
+ * C/A, GLONASS G2 C/A, GALILEO E1C, GALILEO E6C, SBAS L1 C/A, QZSS L1 C/A, IRNSS L5C.
+ */
+ public static final int CODE_TYPE_C = 2;
+
+ /**
+ * The GNSS Measurement's code type is one of the following: GPS L5 I, GLONASS G3 I, GALILEO E5a
+ * I, GALILEO E5b I, GALILEO E5a+b I, SBAS L5 I, QZSS L5 I, BDS B1 I, BDS B2 I, BDS B3 I.
+ */
+ public static final int CODE_TYPE_I = 3;
+
+ /**
+ * The GNSS Measurement's code type is one of the following: GPS L1C (P), GPS L2C (L), QZSS L1C
+ * (P), QZSS L2C (L), LEX(6) L.
+ */
+ public static final int CODE_TYPE_L = 4;
+
+ /**
+ * The GNSS Measurement's code type is one of the following: GPS L1M, GPS L2M.
+ */
+ public static final int CODE_TYPE_M = 5;
+
+ /**
+ * The GNSS Measurement's code type is one of the following: GPS L1P, GPS L2P, GLONASS G1P,
+ * GLONASS G2P.
+ */
+ public static final int CODE_TYPE_P = 6;
+
+ /**
+ * The GNSS Measurement's code type is one of the following: GPS L5 Q, GLONASS G3 Q, GALILEO E5a
+ * Q, GALILEO E5b Q, GALILEO E5a+b Q, SBAS L5 Q, QZSS L5 Q, BDS B1 Q, BDS B2 Q, BDS B3 Q.
+ */
+ public static final int CODE_TYPE_Q = 7;
+
+ /**
+ * The GNSS Measurement's code type is one of the following: GPS L1C (D), GPS L2C (M), QZSS L1C
+ * (D), QZSS L2C (M), LEX(6) S.
+ */
+ public static final int CODE_TYPE_S = 8;
+
+ /**
+ * The GNSS Measurement's code type is one of the following: GPS L1 Z-tracking, GPS L2
+ * Z-tracking.
+ */
+ public static final int CODE_TYPE_W = 9;
+
+ /**
+ * The GNSS Measurement's code type is one of the following: GPS L1C (D+P), GPS L2C (M+L), GPS
+ * L5 (I+Q), GLONASS G3 (I+Q), GALILEO E1 (B+C), GALILEO E5a (I+Q), GALILEO E5b (I+Q), GALILEO
+ * E5a+b(I+Q), GALILEO E6 (B+C), SBAS L5 (I+Q), QZSS L1C (D+P), QZSS L2C (M+L), QZSS L5 (I+Q),
+ * LEX(6) (S+L), BDS B1 (I+Q), BDS B2 (I+Q), BDS B3 (I+Q), IRNSS L5 (B+C).
+ */
+ public static final int CODE_TYPE_X = 10;
+
+ /**
+ * The GNSS Measurement's code type is one of the following: GPS L1Y, GPS L2Y.
+ */
+ public static final int CODE_TYPE_Y = 11;
+
+ /**
+ * The GNSS Measurement's code type is one of the following: GALILEO E1 (A+B+C), GALILEO E6
+ * (A+B+C), QZSS L1-SAIF.
+ */
+ public static final int CODE_TYPE_Z = 12;
+
+ /**
+ * The GNSS Measurement's code type is one of the following: GPS L1 codeless, GPS L2 codeless.
+ */
+ public static final int CODE_TYPE_CODELESS = 13;
+
+ /**
* All the 'Accumulated Delta Range' flags.
* @hide
*/
@@ -248,6 +348,7 @@
mMultipathIndicator = measurement.mMultipathIndicator;
mSnrInDb = measurement.mSnrInDb;
mAutomaticGainControlLevelInDb = measurement.mAutomaticGainControlLevelInDb;
+ mCodeType = measurement.mCodeType;
}
/**
@@ -967,7 +1068,7 @@
* <p>For internal and logging use only.
*/
private String getMultipathIndicatorString() {
- switch(mMultipathIndicator) {
+ switch (mMultipathIndicator) {
case MULTIPATH_INDICATOR_UNKNOWN:
return "Unknown";
case MULTIPATH_INDICATOR_DETECTED:
@@ -1063,6 +1164,89 @@
mAutomaticGainControlLevelInDb = Double.NaN;
}
+ /**
+ * Returns {@code true} if {@link #getCodeType()} is available,
+ * {@code false} otherwise.
+ */
+ public boolean hasCodeType() {
+ return isFlagSet(HAS_CODE_TYPE);
+ }
+
+ /**
+ * Gets the GNSS measurement's code type.
+ *
+ * <p>Similar to the Attribute field described in Rinex 3.03, e.g., in Tables 4-10, and Table
+ * A2 at the Rinex 3.03 Update 1 Document.
+ */
+ @CodeType
+ public int getCodeType() {
+ return mCodeType;
+ }
+
+ /**
+ * Sets the GNSS measurement's code type.
+ *
+ * @hide
+ */
+ @TestApi
+ public void setCodeType(@CodeType int codeType) {
+ setFlag(HAS_CODE_TYPE);
+ mCodeType = codeType;
+ }
+
+ /**
+ * Resets the GNSS measurement's code type.
+ *
+ * @hide
+ */
+ @TestApi
+ public void resetCodeType() {
+ resetFlag(HAS_CODE_TYPE);
+ mCodeType = CODE_TYPE_UNKNOWN;
+ }
+
+ /**
+ * Gets a string representation of the 'code type'.
+ *
+ * <p>For internal and logging use only.
+ */
+ private String getCodeTypeString() {
+ switch (mCodeType) {
+ case CODE_TYPE_UNKNOWN:
+ return "CODE_TYPE_UNKNOWN";
+ case CODE_TYPE_A:
+ return "CODE_TYPE_A";
+ case CODE_TYPE_B:
+ return "CODE_TYPE_B";
+ case CODE_TYPE_C:
+ return "CODE_TYPE_C";
+ case CODE_TYPE_I:
+ return "CODE_TYPE_I";
+ case CODE_TYPE_L:
+ return "CODE_TYPE_L";
+ case CODE_TYPE_M:
+ return "CODE_TYPE_M";
+ case CODE_TYPE_P:
+ return "CODE_TYPE_P";
+ case CODE_TYPE_Q:
+ return "CODE_TYPE_Q";
+ case CODE_TYPE_S:
+ return "CODE_TYPE_S";
+ case CODE_TYPE_W:
+ return "CODE_TYPE_W";
+ case CODE_TYPE_X:
+ return "CODE_TYPE_X";
+ case CODE_TYPE_Y:
+ return "CODE_TYPE_Y";
+ case CODE_TYPE_Z:
+ return "CODE_TYPE_Z";
+ case CODE_TYPE_CODELESS:
+ return "CODE_TYPE_CODELESS";
+ default:
+ return "<Invalid: " + mCodeType + ">";
+ }
+ }
+
public static final Creator<GnssMeasurement> CREATOR = new Creator<GnssMeasurement>() {
@Override
public GnssMeasurement createFromParcel(Parcel parcel) {
@@ -1088,6 +1272,7 @@
gnssMeasurement.mMultipathIndicator = parcel.readInt();
gnssMeasurement.mSnrInDb = parcel.readDouble();
gnssMeasurement.mAutomaticGainControlLevelInDb = parcel.readDouble();
+ gnssMeasurement.mCodeType = parcel.readInt();
return gnssMeasurement;
}
@@ -1120,6 +1305,7 @@
parcel.writeInt(mMultipathIndicator);
parcel.writeDouble(mSnrInDb);
parcel.writeDouble(mAutomaticGainControlLevelInDb);
+ parcel.writeInt(mCodeType);
}
@Override
@@ -1191,9 +1377,13 @@
"SnrInDb",
hasSnrInDb() ? mSnrInDb : null));
builder.append(String.format(
- format,
- "AgcLevelDb",
- hasAutomaticGainControlLevelDb() ? mAutomaticGainControlLevelInDb : null));
+ format,
+ "AgcLevelDb",
+ hasAutomaticGainControlLevelDb() ? mAutomaticGainControlLevelInDb : null));
+ builder.append(String.format(
+ format,
+ "CodeType",
+ hasCodeType() ? getCodeTypeString() : null));
return builder.toString();
}
@@ -1218,6 +1408,7 @@
setMultipathIndicator(MULTIPATH_INDICATOR_UNKNOWN);
resetSnrInDb();
resetAutomaticGainControlLevel();
+ resetCodeType();
}
private void setFlag(int flag) {
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index 4f23cca..f5a6f86 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -736,8 +736,9 @@
* @param preset one of {@link MediaRecorder.AudioSource#DEFAULT},
* {@link MediaRecorder.AudioSource#MIC}, {@link MediaRecorder.AudioSource#CAMCORDER},
* {@link MediaRecorder.AudioSource#VOICE_RECOGNITION},
- * {@link MediaRecorder.AudioSource#VOICE_COMMUNICATION} or
- * {@link MediaRecorder.AudioSource#UNPROCESSED}
+ * {@link MediaRecorder.AudioSource#VOICE_COMMUNICATION},
+ * {@link MediaRecorder.AudioSource#UNPROCESSED} or
+ * {@link MediaRecorder.AudioSource#VOICE_PERFORMANCE}
* @return the same Builder instance.
*/
@SystemApi
@@ -749,6 +750,7 @@
case MediaRecorder.AudioSource.VOICE_RECOGNITION:
case MediaRecorder.AudioSource.VOICE_COMMUNICATION:
case MediaRecorder.AudioSource.UNPROCESSED:
+ case MediaRecorder.AudioSource.VOICE_PERFORMANCE:
mSource = preset;
break;
default:
@@ -760,7 +762,7 @@
/**
* @hide
* Same as {@link #setCapturePreset(int)} but authorizes the use of HOTWORD,
- * REMOTE_SUBMIX, RADIO_TUNER, VOICE_DOWNLINK, VOICE_UPLINK and VOICE_CALL.
+ * REMOTE_SUBMIX, RADIO_TUNER, VOICE_DOWNLINK, VOICE_UPLINK, VOICE_CALL and ECHO_REFERENCE.
* @param preset
* @return the same Builder instance.
*/
@@ -771,7 +773,8 @@
|| (preset == MediaRecorder.AudioSource.RADIO_TUNER)
|| (preset == MediaRecorder.AudioSource.VOICE_DOWNLINK)
|| (preset == MediaRecorder.AudioSource.VOICE_UPLINK)
- || (preset == MediaRecorder.AudioSource.VOICE_CALL)) {
+ || (preset == MediaRecorder.AudioSource.VOICE_CALL)
+ || (preset == MediaRecorder.AudioSource.ECHO_REFERENCE)) {
mSource = preset;
} else {
setCapturePreset(preset);
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index 793aa27..5516086 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -17,6 +17,7 @@
package android.media;
import android.annotation.IntDef;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
@@ -816,7 +817,7 @@
*
* @return The audio frame size in bytes corresponding to the encoding and the channel mask.
*/
- public int getFrameSizeInBytes() {
+ public @IntRange(from = 1) int getFrameSizeInBytes() {
return mFrameSizeInBytes;
}
diff --git a/media/java/android/media/AudioRecordingConfiguration.java b/media/java/android/media/AudioRecordingConfiguration.java
index de76aef..52771e4 100644
--- a/media/java/android/media/AudioRecordingConfiguration.java
+++ b/media/java/android/media/AudioRecordingConfiguration.java
@@ -172,7 +172,8 @@
MediaRecorder.AudioSource.CAMCORDER,
MediaRecorder.AudioSource.VOICE_RECOGNITION,
MediaRecorder.AudioSource.VOICE_COMMUNICATION,
- MediaRecorder.AudioSource.UNPROCESSED
+ MediaRecorder.AudioSource.UNPROCESSED,
+ MediaRecorder.AudioSource.VOICE_PERFORMANCE
})
@Retention(RetentionPolicy.SOURCE)
public @interface AudioSource {}
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 45cde0f..de73649 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -541,6 +541,8 @@
public static final int DEVICE_IN_BUS = DEVICE_BIT_IN | 0x100000;
public static final int DEVICE_IN_PROXY = DEVICE_BIT_IN | 0x1000000;
public static final int DEVICE_IN_USB_HEADSET = DEVICE_BIT_IN | 0x2000000;
+ public static final int DEVICE_IN_BLUETOOTH_BLE = DEVICE_BIT_IN | 0x4000000;
+ public static final int DEVICE_IN_ECHO_REFERENCE = DEVICE_BIT_IN | 0x10000000;
@UnsupportedAppUsage
public static final int DEVICE_IN_DEFAULT = DEVICE_BIT_IN | DEVICE_BIT_DEFAULT;
@@ -567,6 +569,8 @@
DEVICE_IN_BUS |
DEVICE_IN_PROXY |
DEVICE_IN_USB_HEADSET |
+ DEVICE_IN_BLUETOOTH_BLE |
+ DEVICE_IN_ECHO_REFERENCE |
DEVICE_IN_DEFAULT);
public static final int DEVICE_IN_ALL_SCO = DEVICE_IN_BLUETOOTH_SCO_HEADSET;
public static final int DEVICE_IN_ALL_USB = (DEVICE_IN_USB_ACCESSORY |
@@ -641,6 +645,8 @@
public static final String DEVICE_IN_BUS_NAME = "bus";
public static final String DEVICE_IN_PROXY_NAME = "proxy";
public static final String DEVICE_IN_USB_HEADSET_NAME = "usb_headset";
+ public static final String DEVICE_IN_BLUETOOTH_BLE_NAME = "bt_ble";
+ public static final String DEVICE_IN_ECHO_REFERENCE_NAME = "echo_reference";
@UnsupportedAppUsage
public static String getOutputDeviceName(int device)
@@ -757,6 +763,10 @@
return DEVICE_IN_PROXY_NAME;
case DEVICE_IN_USB_HEADSET:
return DEVICE_IN_USB_HEADSET_NAME;
+ case DEVICE_IN_BLUETOOTH_BLE:
+ return DEVICE_IN_BLUETOOTH_BLE_NAME;
+ case DEVICE_IN_ECHO_REFERENCE:
+ return DEVICE_IN_ECHO_REFERENCE_NAME;
case DEVICE_IN_DEFAULT:
default:
return Integer.toString(device);
diff --git a/media/java/android/media/IMediaSession2Service.aidl b/media/java/android/media/IMediaSession2Service.aidl
new file mode 100644
index 0000000..10ac1be
--- /dev/null
+++ b/media/java/android/media/IMediaSession2Service.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.os.Bundle;
+import android.media.Controller2Link;
+
+/**
+ * Interface from MediaController2 to MediaSession2Service.
+ * <p>
+ * Keep this interface oneway. Otherwise a malicious app may implement fake version of this,
+ * and holds calls from controller to make controller owner(s) frozen.
+ * @hide
+ */
+oneway interface IMediaSession2Service {
+ void connect(in Controller2Link caller, int seq, in Bundle connectionRequest) = 0;
+ // Next Id : 1
+}
diff --git a/media/java/android/media/MediaController2.java b/media/java/android/media/MediaController2.java
index 774ea18..165ea41 100644
--- a/media/java/android/media/MediaController2.java
+++ b/media/java/android/media/MediaController2.java
@@ -26,12 +26,16 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+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;
import android.os.Process;
+import android.os.RemoteException;
import android.os.ResultReceiver;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -63,6 +67,7 @@
private final Executor mCallbackExecutor;
private final Controller2Link mControllerStub;
private final Handler mResultHandler;
+ private final SessionServiceConnection mServiceConnection;
private final Object mLock = new Object();
//@GuardedBy("mLock")
@@ -118,16 +123,25 @@
mPendingCommands = new ArrayMap<>();
mRequestedCommandSeqNumbers = new ArraySet<>();
+ boolean connectRequested;
if (token.getType() == TYPE_SESSION) {
- connectToSession();
+ mServiceConnection = null;
+ connectRequested = requestConnectToSession();
} else {
- // TODO: Handle connect to session service.
+ mServiceConnection = new SessionServiceConnection();
+ connectRequested = requestConnectToService();
+ }
+ if (!connectRequested) {
+ close();
}
}
@Override
public void close() {
synchronized (mLock) {
+ if (mServiceConnection != null) {
+ mContext.unbindService(mServiceConnection);
+ }
if (mSessionBinder != null) {
try {
mSessionBinder.disconnect(mControllerStub, getNextSeqNumber());
@@ -299,18 +313,55 @@
}
}
- private void connectToSession() {
- Session2Link sessionBinder = mSessionToken.getSessionLink();
+ private Bundle createConnectionRequest() {
Bundle connectionRequest = new Bundle();
connectionRequest.putString(KEY_PACKAGE_NAME, mContext.getPackageName());
connectionRequest.putInt(KEY_PID, Process.myPid());
+ return connectionRequest;
+ }
+ private boolean requestConnectToSession() {
+ Session2Link sessionBinder = mSessionToken.getSessionLink();
+ Bundle connectionRequest = createConnectionRequest();
try {
sessionBinder.connect(mControllerStub, getNextSeqNumber(), connectionRequest);
} catch (RuntimeException e) {
- Log.w(TAG, "Failed to call connection request. Framework will retry"
- + " automatically");
+ Log.w(TAG, "Failed to call connection request", e);
+ return false;
}
+ return true;
+ }
+
+ private boolean requestConnectToService() {
+ // Service. Needs to get fresh binder whenever connection is needed.
+ final Intent intent = new Intent(MediaSession2Service.SERVICE_INTERFACE);
+ intent.setClassName(mSessionToken.getPackageName(), mSessionToken.getServiceName());
+
+ // Use bindService() instead of startForegroundService() to start session service for three
+ // reasons.
+ // 1. Prevent session service owner's stopSelf() from destroying service.
+ // With the startForegroundService(), service's call of stopSelf() will trigger immediate
+ // onDestroy() calls on the main thread even when onConnect() is running in another
+ // thread.
+ // 2. Minimize APIs for developers to take care about.
+ // With bindService(), developers only need to take care about Service.onBind()
+ // but Service.onStartCommand() should be also taken care about with the
+ // startForegroundService().
+ // 3. Future support for UI-less playback
+ // If a service wants to keep running, it should be either foreground service or
+ // bound service. But there had been request for the feature for system apps
+ // and using bindService() will be better fit with it.
+ synchronized (mLock) {
+ boolean result = mContext.bindService(
+ intent, mServiceConnection, Context.BIND_AUTO_CREATE);
+ if (!result) {
+ Log.w(TAG, "bind to " + mSessionToken + " failed");
+ return false;
+ } else if (DEBUG) {
+ Log.d(TAG, "bind to " + mSessionToken + " succeeded");
+ }
+ }
+ return true;
}
/**
@@ -367,4 +418,59 @@
public void onCommandResult(@NonNull MediaController2 controller, @NonNull Object token,
@NonNull Session2Command command, @NonNull Session2Command.Result result) {}
}
+
+ // This will be called on the main thread.
+ private class SessionServiceConnection implements ServiceConnection {
+ SessionServiceConnection() {
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ // Note that it's always main-thread.
+ boolean connectRequested = false;
+ try {
+ if (DEBUG) {
+ Log.d(TAG, "onServiceConnected " + name + " " + this);
+ }
+ // Sanity check
+ if (!mSessionToken.getPackageName().equals(name.getPackageName())) {
+ Log.wtf(TAG, "Expected connection to " + mSessionToken.getPackageName()
+ + " but is connected to " + name);
+ return;
+ }
+ IMediaSession2Service iService = IMediaSession2Service.Stub.asInterface(service);
+ if (iService == null) {
+ Log.wtf(TAG, "Service interface is missing.");
+ return;
+ }
+ Bundle connectionRequest = createConnectionRequest();
+ iService.connect(mControllerStub, getNextSeqNumber(), connectionRequest);
+ connectRequested = true;
+ } catch (RemoteException e) {
+ Log.w(TAG, "Service " + name + " has died prematurely", e);
+ } finally {
+ if (!connectRequested) {
+ close();
+ }
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ // Temporal lose of the binding because of the service crash. System will automatically
+ // rebind, so just no-op.
+ if (DEBUG) {
+ Log.w(TAG, "Session service " + name + " is disconnected.");
+ }
+ close();
+ }
+
+ @Override
+ public void onBindingDied(ComponentName name) {
+ // Permanent lose of the binding because of the service package update or removed.
+ // This SessionServiceRecord will be removed accordingly, but forget session binder here
+ // for sure.
+ close();
+ }
+ }
}
diff --git a/media/java/android/media/MediaPlayer2.java b/media/java/android/media/MediaPlayer2.java
index df96994..aa79c41 100644
--- a/media/java/android/media/MediaPlayer2.java
+++ b/media/java/android/media/MediaPlayer2.java
@@ -60,6 +60,7 @@
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
@@ -67,6 +68,7 @@
import java.util.Map;
import java.util.Queue;
import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
@@ -399,8 +401,7 @@
clearSourceInfos();
// Modular DRM clean up
- mOnDrmConfigHelper = null;
- synchronized (mDrmEventCbLock) {
+ synchronized (mDrmEventCallbackLock) {
mDrmEventCallbackRecords.clear();
}
@@ -775,7 +776,7 @@
}
boolean hasError = false;
for (DataSourceDesc dsd : dsds) {
- if (dsd != null) {
+ if (dsd == null) {
hasError = true;
continue;
}
@@ -2889,7 +2890,7 @@
}
private void sendDrmEvent(final DrmEventNotifier notifier) {
- synchronized (mDrmEventCbLock) {
+ synchronized (mDrmEventCallbackLock) {
try {
for (Pair<Executor, DrmEventCallback> cb : mDrmEventCallbackRecords) {
cb.first.execute(() -> notifier.notify(cb.second));
@@ -2901,12 +2902,28 @@
}
}
+ private <T> T sendDrmEventWait(final DrmEventNotifier<T> notifier)
+ throws InterruptedException, ExecutionException {
+ synchronized (mDrmEventCallbackLock) {
+ mDrmEventCallbackRecords.get(0);
+ for (Pair<Executor, DrmEventCallback> cb : mDrmEventCallbackRecords) {
+ CompletableFuture<T> ret = new CompletableFuture<>();
+ cb.first.execute(() -> ret.complete(notifier.notifyWait(cb.second)));
+ return ret.get();
+ }
+ }
+ return null;
+ }
+
private interface EventNotifier {
void notify(EventCallback callback);
}
- private interface DrmEventNotifier {
- void notify(DrmEventCallback callback);
+ private interface DrmEventNotifier<T> {
+ default void notify(DrmEventCallback callback) { }
+ default T notifyWait(DrmEventCallback callback) {
+ return null;
+ }
}
/* Do not change these values without updating their counterparts
@@ -3351,73 +3368,209 @@
// Modular DRM begin
/**
- * Interface definition of a callback to be invoked when the app
- * can do DRM configuration (get/set properties) before the session
- * is opened. This facilitates configuration of the properties, like
- * 'securityLevel', which has to be set after DRM scheme creation but
- * before the DRM session is opened.
+ * An immutable structure per {@link DataSourceDesc} with settings required to initiate a DRM
+ * protected playback session.
*
- * The only allowed DRM calls in this listener are
- * {@link MediaPlayer2#getDrmPropertyString(DataSourceDesc, String)}
- * and {@link MediaPlayer2#setDrmPropertyString(DataSourceDesc, String, String)}.
- * @hide
+ * @see DrmPreparationInfo.Builder
*/
- public interface OnDrmConfigHelper {
+ public static final class DrmPreparationInfo {
+
/**
- * Called to give the app the opportunity to configure DRM before the session is created
- *
- * @param mp the {@code MediaPlayer2} associated with this callback
- * @param dsd the DataSourceDesc of this data source
+ * Mutable builder to create a {@link MediaPlayer2.DrmPreparationInfo} object.
*/
- public void onDrmConfig(MediaPlayer2 mp, DataSourceDesc dsd);
- }
+ public static final class Builder {
- /**
- * Register a callback to be invoked for configuration of the DRM object before
- * the session is created.
- * The callback will be invoked synchronously during the execution
- * of {@link #prepareDrm}.
- *
- * @param listener the callback that will be run
- * @hide
- */
- // This is a synchronous call.
- public void setOnDrmConfigHelper(OnDrmConfigHelper listener) {
- mOnDrmConfigHelper = listener;
- }
+ private UUID mUUID;
+ private byte[] mKeySetId;
+ private byte[] mInitData;
+ private String mMimeType;
+ private int mKeyType;
+ private Map<String, String> mOptionalParameters;
- private OnDrmConfigHelper mOnDrmConfigHelper;
+ /**
+ * Set UUID of the crypto scheme selected to decrypt content. An UUID can be retrieved from
+ * the source listening to {@link MediaPlayer2.DrmEventCallback#onDrmInfo}.
+ *
+ * @param uuid of selected crypto scheme
+ * @return this
+ */
+ public Builder setUuid(@NonNull UUID uuid) {
+ this.mUUID = uuid;
+ return this;
+ }
+
+ /**
+ * Set identifier of a persisted offline key obtained from
+ * {@link MediaPlayer2.DrmEventCallback#onDrmPrepared(MediaPlayer2, DataSourceDesc, int, byte[])}.
+ *
+ * A {@code keySetId} can be used to restore persisted offline keys into a new playback
+ * session of a DRM protected data source. When {@code keySetId} is set, {@code initData},
+ * {@code mimeType}, {@code keyType}, {@code optionalParameters} are ignored.
+ *
+ * @param keySetId identifier of a persisted offline key
+ * @return this
+ */
+ public Builder setKeySetId(@Nullable byte[] keySetId) {
+ this.mKeySetId = keySetId;
+ return this;
+ }
+
+ /**
+ * Set container-specific DRM initialization data. Its meaning is interpreted based on
+ * {@code mimeType}. For example, it could contain the content ID, key ID or other data
+ * obtained from the content metadata that is required to generate a
+ * {@link MediaDrm.KeyRequest}.
+ *
+ * @param initData container-specific DRM initialization data
+ * @return this
+ */
+ public Builder setInitData(@Nullable byte[] initData) {
+ this.mInitData = initData;
+ return this;
+ }
+
+ /**
+ * Set mime type of the content
+ *
+ * @param mimeType mime type to the content
+ * @return this
+ */
+ public Builder setMimeType(@Nullable String mimeType) {
+ this.mMimeType = mimeType;
+ return this;
+ }
+
+ /**
+ * Set type of the key request. The request may be to acquire keys
+ * for streaming, {@link MediaDrm#KEY_TYPE_STREAMING}, or for offline content,
+ * {@link MediaDrm#KEY_TYPE_OFFLINE}. Releasing previously acquired keys
+ * ({@link MediaDrm#KEY_TYPE_RELEASE}) is not allowed.
+ *
+ * @param keyType type of the key request
+ * @return this
+ */
+ public Builder setKeyType(@MediaPlayer2.MediaDrmKeyType int keyType) {
+ this.mKeyType = keyType;
+ return this;
+ }
+
+ /**
+ * Set optional parameters to be included in a {@link MediaDrm.KeyRequest} message sent to
+ * the license server.
+ *
+ * @param optionalParameters optional parameters to be included in a key request
+ * @return this
+ */
+ public Builder setOptionalParameters(
+ @Nullable Map<String, String> optionalParameters) {
+ this.mOptionalParameters = optionalParameters;
+ return this;
+ }
+
+ /**
+ * @return an immutable {@link MediaPlayer2.DrmPreparationInfo} representing the settings of this builder
+ */
+ public MediaPlayer2.DrmPreparationInfo build() {
+ return new MediaPlayer2.DrmPreparationInfo(mUUID, mKeySetId, mInitData, mMimeType, mKeyType,
+ mOptionalParameters);
+ }
+
+ }
+
+ private final UUID mUUID;
+ private final byte[] mKeySetId;
+ private final byte[] mInitData;
+ private final String mMimeType;
+ private final int mKeyType;
+ private final Map<String, String> mOptionalParameters;
+
+ private DrmPreparationInfo(UUID mUUID, byte[] mKeySetId, byte[] mInitData, String mMimeType,
+ int mKeyType, Map<String, String> optionalParameters) {
+ this.mUUID = mUUID;
+ this.mKeySetId = mKeySetId;
+ this.mInitData = mInitData;
+ this.mMimeType = mMimeType;
+ this.mKeyType = mKeyType;
+ this.mOptionalParameters = optionalParameters;
+ }
+
+ }
/**
* Interface definition for callbacks to be invoked when the player has the corresponding
* DRM events.
- * @hide
*/
public static class DrmEventCallback {
/**
- * Called to indicate DRM info is available
+ * Called to indicate DRM info is available. Return a {@link DrmPreparationInfo} object that
+ * bundles DRM initialization parameters.
*
* @param mp the {@code MediaPlayer2} associated with this callback
- * @param dsd the DataSourceDesc of this data source
- * @param drmInfo DRM info of the source including PSSH, and subset
- * of crypto schemes supported by this device
+ * @param dsd the {@link DataSourceDesc} of this data source
+ * @param drmInfo DRM info of the source including PSSH, and subset of crypto schemes
+ * supported by this device
+ * @return a {@link DrmPreparationInfo} object to initialize DRM playback, or null to skip
+ * DRM initialization
*/
- public void onDrmInfo(MediaPlayer2 mp, DataSourceDesc dsd, DrmInfo drmInfo) { }
+ public DrmPreparationInfo onDrmInfo(MediaPlayer2 mp, DataSourceDesc dsd, DrmInfo drmInfo) {
+ return null;
+ }
/**
- * Called to notify the client that {@link MediaPlayer2#prepareDrm(DataSourceDesc, UUID)}
- * is finished and ready for key request/response.
+ * Called to notify the client that {@code mp} is ready to decrypt DRM protected data source
+ * {@code dsd}
*
* @param mp the {@code MediaPlayer2} associated with this callback
- * @param dsd the DataSourceDesc of this data source
+ * @param dsd the {@link DataSourceDesc} of this data source
* @param status the result of DRM preparation.
+ * @param keySetId optional identifier that can be used to restore DRM playback initiated
+ * with a {@link MediaDrm#KEY_TYPE_OFFLINE} key request.
+ *
+ * @see DrmPreparationInfo.Builder#setKeySetId(byte[])
*/
- public void onDrmPrepared(
- MediaPlayer2 mp, DataSourceDesc dsd, @PrepareDrmStatusCode int status) { }
+ public void onDrmPrepared(@NonNull MediaPlayer2 mp, @NonNull DataSourceDesc dsd,
+ @PrepareDrmStatusCode int status, @Nullable byte[] keySetId) { }
+
+ /**
+ * Called to give the app the opportunity to configure DRM before the session is created.
+ *
+ * This facilitates configuration of the properties, like 'securityLevel', which
+ * has to be set after DRM scheme creation but before the DRM session is opened.
+ *
+ * The only allowed DRM calls in this listener are
+ * {@link MediaDrm#getPropertyString(String)},
+ * {@link MediaDrm#getPropertyByteArray(String)},
+ * {@link MediaDrm#setPropertyString(String, String)},
+ * {@link MediaDrm#setPropertyByteArray(String, byte[])},
+ * {@link MediaDrm#setOnExpirationUpdateListener},
+ * and {@link MediaDrm#setOnKeyStatusChangeListener}.
+ *
+ * @param mp the {@code MediaPlayer2} associated with this callback
+ * @param dsd the {@link DataSourceDesc} of this data source
+ * @param drm handle to get/set DRM properties and listeners for this data source
+ */
+ public void onDrmConfig(@NonNull MediaPlayer2 mp, @NonNull DataSourceDesc dsd,
+ @NonNull MediaDrm drm) { }
+
+ /**
+ * Called to indicate the DRM session for {@code dsd} is ready for key request/response
+ *
+ * @param mp the {@code MediaPlayer2} associated with this callback
+ * @param dsd the {@link DataSourceDesc} of this data source
+ * @param request a {@link MediaDrm.KeyRequest} prepared using the
+ * {@link DrmPreparationInfo} returned from
+ * {@link #onDrmInfo(MediaPlayer2, DataSourceDesc, DrmInfo)}
+ * @return the response to {@code request} (from license server)
+ */
+ public byte[] onDrmKeyRequest(@NonNull MediaPlayer2 mp, @NonNull DataSourceDesc dsd,
+ @NonNull MediaDrm.KeyRequest request) {
+ return null;
+ }
+
}
- private final Object mDrmEventCbLock = new Object();
- private ArrayList<Pair<Executor, DrmEventCallback>> mDrmEventCallbackRecords =
+ private final Object mDrmEventCallbackLock = new Object();
+ private List<Pair<Executor, DrmEventCallback>> mDrmEventCallbackRecords =
new ArrayList<Pair<Executor, DrmEventCallback>>();
/**
@@ -3425,10 +3578,9 @@
*
* @param eventCallback the callback that will be run
* @param executor the executor through which the callback should be invoked
- * @hide
*/
// This is a synchronous call.
- public void registerDrmEventCallback(@NonNull @CallbackExecutor Executor executor,
+ public void setDrmEventCallback(@NonNull @CallbackExecutor Executor executor,
@NonNull DrmEventCallback eventCallback) {
if (eventCallback == null) {
throw new IllegalArgumentException("Illegal null EventCallback");
@@ -3437,8 +3589,9 @@
throw new IllegalArgumentException(
"Illegal null Executor for the EventCallback");
}
- synchronized (mDrmEventCbLock) {
- mDrmEventCallbackRecords.add(new Pair(executor, eventCallback));
+ synchronized (mDrmEventCallbackLock) {
+ mDrmEventCallbackRecords = Collections.singletonList(
+ new Pair<Executor, DrmEventCallback>(executor, eventCallback));
}
}
@@ -3450,7 +3603,7 @@
*/
// This is a synchronous call.
public void unregisterDrmEventCallback(DrmEventCallback eventCallback) {
- synchronized (mDrmEventCbLock) {
+ synchronized (mDrmEventCallbackLock) {
for (Pair<Executor, DrmEventCallback> cb : mDrmEventCallbackRecords) {
if (cb.second == eventCallback) {
mDrmEventCallbackRecords.remove(cb);
@@ -3564,7 +3717,7 @@
/**
* Prepares the DRM for the given data source
* <p>
- * If {@link OnDrmConfigHelper} is registered, it will be called during
+ * If {@link DrmEventCallback} is registered, it will be called during
* preparation to allow configuration of the DRM properties before opening the
* DRM session. It should be used only for a series of
* {@link #getDrmPropertyString(DataSourceDesc, String)} and
@@ -3587,8 +3740,7 @@
* @param dsd The DRM protected data source
*
* @param uuid The UUID of the crypto scheme. If not known beforehand, it can be retrieved
- * from the source through {@link #getDrmInfo(DataSourceDesc)} or registering a
- * {@link DrmEventCallback#onDrmInfo}.
+ * from the source listening to {@link DrmEventCallback#onDrmInfo}.
*
* @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
* @hide
@@ -3661,8 +3813,8 @@
sendDrmEvent(new DrmEventNotifier() {
@Override
public void notify(DrmEventCallback callback) {
- callback.onDrmPrepared(
- MediaPlayer2.this, dsd, prepareDrmStatus);
+ callback.onDrmPrepared(MediaPlayer2.this, dsd, prepareDrmStatus,
+ /* TODO: keySetId */ null);
}
});
@@ -3876,7 +4028,6 @@
/**
* Encapsulates the DRM properties of the source.
- * @hide
*/
public static final class DrmInfo {
private Map<UUID, byte[]> mMapPssh;
@@ -4013,10 +4164,8 @@
}; // DrmInfo
/**
- * Thrown when a DRM method is called before preparing a DRM scheme through
- * {@link MediaPlayer2#prepareDrm(DataSourceDesc, UUID)}.
+ * Thrown when a DRM method is called when there is no active DRM session.
* Extends MediaDrm.MediaDrmException
- * @hide
*/
public static final class NoDrmSchemeException extends MediaDrmException {
public NoDrmSchemeException(String detailMessage) {
@@ -4291,9 +4440,9 @@
}
void prepare(UUID uuid) throws UnsupportedSchemeException,
- ResourceBusyException, NotProvisionedException {
- final OnDrmConfigHelper onDrmConfigHelper = mOnDrmConfigHelper;
- Log.v(TAG, "prepareDrm: uuid: " + uuid + " mOnDrmConfigHelper: " + onDrmConfigHelper);
+ ResourceBusyException, NotProvisionedException, InterruptedException,
+ ExecutionException {
+ Log.v(TAG, "prepareDrm: uuid: " + uuid);
synchronized (this) {
if (mActiveDrmUUID != null) {
@@ -4334,9 +4483,13 @@
} // synchronized
// call the callback outside the lock
- if (onDrmConfigHelper != null) {
- onDrmConfigHelper.onDrmConfig(MediaPlayer2.this, mDSD);
- }
+ sendDrmEventWait(new DrmEventNotifier<Void>() {
+ @Override
+ public Void notifyWait(DrmEventCallback callback) {
+ callback.onDrmConfig(MediaPlayer2.this, mDSD, mDrmObj);
+ return null;
+ }
+ });
synchronized (this) {
mDrmConfigAllowed = false;
@@ -4506,7 +4659,7 @@
@Override
public void notify(DrmEventCallback callback) {
callback.onDrmPrepared(
- MediaPlayer2.this, mDSD, finalStatus);
+ MediaPlayer2.this, mDSD, finalStatus, /* TODO: keySetId */ null);
}
});
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 25b1df2..1304afe 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -302,6 +302,34 @@
* {@link #DEFAULT} otherwise. */
public static final int UNPROCESSED = 9;
+
+ /**
+ * Source for capturing audio meant to be processed in real time and played back for live
+ * performance (e.g karaoke).
+ * <p>
+ * The capture path will minimize latency and coupling with
+ * playback path.
+ * </p>
+ */
+ public static final int VOICE_PERFORMANCE = 10;
+
+ /**
+ * Source for an echo canceller to capture the reference signal to be cancelled.
+ * <p>
+ * The echo reference signal will be captured as close as possible to the DAC in order
+ * to include all post processing applied to the playback path.
+ * </p><p>
+ * Capturing the echo reference requires the
+ * {@link android.Manifest.permission#CAPTURE_AUDIO_OUTPUT} permission.
+ * This permission is reserved for use by system components and is not available to
+ * third-party applications.
+ * </p>
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.CAPTURE_AUDIO_OUTPUT)
+ public static final int ECHO_REFERENCE = 1997;
+
/**
* Audio source for capturing broadcast radio tuner output.
* @hide
@@ -343,6 +371,7 @@
case AudioSource.VOICE_COMMUNICATION:
//case REMOTE_SUBMIX: considered "system" as it requires system permissions
case AudioSource.UNPROCESSED:
+ case AudioSource.VOICE_PERFORMANCE:
return false;
default:
return true;
@@ -372,6 +401,10 @@
return "REMOTE_SUBMIX";
case AudioSource.UNPROCESSED:
return "UNPROCESSED";
+ case AudioSource.ECHO_REFERENCE:
+ return "ECHO_REFERENCE";
+ case AudioSource.VOICE_PERFORMANCE:
+ return "VOICE_PERFORMANCE";
case AudioSource.RADIO_TUNER:
return "RADIO_TUNER";
case AudioSource.HOTWORD:
@@ -524,7 +557,7 @@
* @see android.media.MediaRecorder.AudioSource
*/
public static final int getAudioSourceMax() {
- return AudioSource.UNPROCESSED;
+ return AudioSource.VOICE_PERFORMANCE;
}
/**
diff --git a/media/java/android/media/MediaSession2.java b/media/java/android/media/MediaSession2.java
index e008adf..dceef34 100644
--- a/media/java/android/media/MediaSession2.java
+++ b/media/java/android/media/MediaSession2.java
@@ -31,7 +31,6 @@
import android.content.Intent;
import android.media.session.MediaSessionManager;
import android.media.session.MediaSessionManager.RemoteUserInfo;
-import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.Process;
@@ -41,7 +40,6 @@
import android.util.Log;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -117,15 +115,19 @@
@Override
public void close() {
try {
+ List<ControllerInfo> controllerInfos;
+ synchronized (mLock) {
+ if (mClosed) {
+ return;
+ }
+ mClosed = true;
+ controllerInfos = getConnectedControllers();
+ mConnectedControllers.clear();
+ mCallback.onSessionClosed(this);
+ }
synchronized (MediaSession2.class) {
SESSION_ID_LIST.remove(mSessionId);
}
- Collection<ControllerInfo> controllerInfos;
- synchronized (mLock) {
- controllerInfos = mConnectedControllers.values();
- mConnectedControllers.clear();
- mClosed = true;
- }
for (ControllerInfo info : controllerInfos) {
info.notifyDisconnected();
}
@@ -160,10 +162,7 @@
if (command == null) {
throw new IllegalArgumentException("command shouldn't be null");
}
- Collection<ControllerInfo> controllerInfos;
- synchronized (mLock) {
- controllerInfos = mConnectedControllers.values();
- }
+ List<ControllerInfo> controllerInfos = getConnectedControllers();
for (ControllerInfo controller : controllerInfos) {
controller.sendSessionCommand(command, args, null);
}
@@ -222,23 +221,26 @@
}
}
- // Called by Session2Link.onConnect
- void onConnect(final Controller2Link controller, int seq, Bundle connectionRequest) {
- if (controller == null || connectionRequest == null) {
- return;
+ SessionCallback getCallback() {
+ return mCallback;
+ }
+
+ // Called by Session2Link.onConnect and MediaSession2Service.MediaSession2ServiceStub.connect
+ void onConnect(final Controller2Link controller, int callingPid, int callingUid, int seq,
+ Bundle connectionRequest) {
+ if (callingPid == 0) {
+ // The pid here is from Binder.getCallingPid(), which can be 0 for an oneway call from
+ // the remote process. If it's the case, use PID from the connectionRequest.
+ callingPid = connectionRequest.getInt(KEY_PID);
}
- final int uid = Binder.getCallingUid();
- final int callingPid = Binder.getCallingPid();
- final long token = Binder.clearCallingIdentity();
- // Binder.getCallingPid() can be 0 for an oneway call from the remote process.
- // If it's the case, use PID from the ConnectionRequest.
- final int pid = (callingPid != 0) ? callingPid : connectionRequest.getInt(KEY_PID);
- final String pkg = connectionRequest.getString(KEY_PACKAGE_NAME);
- try {
- RemoteUserInfo remoteUserInfo = new RemoteUserInfo(pkg, pid, uid);
- final ControllerInfo controllerInfo = new ControllerInfo(remoteUserInfo,
- mSessionManager.isTrustedForMediaControl(remoteUserInfo), controller);
- mCallbackExecutor.execute(() -> {
+ String callingPkg = connectionRequest.getString(KEY_PACKAGE_NAME);
+
+ RemoteUserInfo remoteUserInfo = new RemoteUserInfo(callingPkg, callingPid, callingUid);
+ final ControllerInfo controllerInfo = new ControllerInfo(remoteUserInfo,
+ mSessionManager.isTrustedForMediaControl(remoteUserInfo), controller);
+ mCallbackExecutor.execute(() -> {
+ boolean accept = false;
+ try {
if (isClosed()) {
return;
}
@@ -247,77 +249,67 @@
// Don't reject connection for the request from trusted app.
// Otherwise server will fail to retrieve session's information to dispatch
// media keys to.
- boolean accept =
- controllerInfo.mAllowedCommands != null || controllerInfo.isTrusted();
- if (accept) {
- if (controllerInfo.mAllowedCommands == null) {
- // For trusted apps, send non-null allowed commands to keep
- // connection.
- controllerInfo.mAllowedCommands =
- new Session2CommandGroup.Builder().build();
+ accept = controllerInfo.mAllowedCommands != null || controllerInfo.isTrusted();
+ if (!accept) {
+ return;
+ }
+ if (controllerInfo.mAllowedCommands == null) {
+ // For trusted apps, send non-null allowed commands to keep
+ // connection.
+ controllerInfo.mAllowedCommands =
+ new Session2CommandGroup.Builder().build();
+ }
+ if (DEBUG) {
+ Log.d(TAG, "Accepting connection: " + controllerInfo);
+ }
+ synchronized (mLock) {
+ if (mConnectedControllers.containsKey(controller)) {
+ Log.w(TAG, "Controller " + controllerInfo + " has sent connection"
+ + " request multiple times");
}
- if (DEBUG) {
- Log.d(TAG, "Accepting connection: " + controllerInfo);
- }
- synchronized (mLock) {
- if (mConnectedControllers.containsKey(controller)) {
- Log.w(TAG, "Controller " + controllerInfo + " has sent connection"
- + " request multiple times");
- }
- mConnectedControllers.put(controller, controllerInfo);
- }
- // If connection is accepted, notify the current state to the controller.
- // It's needed because we cannot call synchronous calls between
- // session/controller.
- Bundle connectionResult = new Bundle();
- connectionResult.putParcelable(KEY_SESSION2LINK, mSessionStub);
- connectionResult.putParcelable(KEY_ALLOWED_COMMANDS,
- controllerInfo.mAllowedCommands);
+ mConnectedControllers.put(controller, controllerInfo);
+ }
+ // If connection is accepted, notify the current state to the controller.
+ // It's needed because we cannot call synchronous calls between
+ // session/controller.
+ Bundle connectionResult = new Bundle();
+ connectionResult.putParcelable(KEY_SESSION2LINK, mSessionStub);
+ connectionResult.putParcelable(KEY_ALLOWED_COMMANDS,
+ controllerInfo.mAllowedCommands);
- // Double check if session is still there, because close() can be called in
- // another thread.
- if (isClosed()) {
- return;
- }
- controllerInfo.notifyConnected(connectionResult);
- } else {
+ // Double check if session is still there, because close() can be called in
+ // another thread.
+ if (isClosed()) {
+ return;
+ }
+ controllerInfo.notifyConnected(connectionResult);
+ } finally {
+ if (!accept) {
if (DEBUG) {
Log.d(TAG, "Rejecting connection, controllerInfo=" + controllerInfo);
}
- controllerInfo.notifyDisconnected();
}
- });
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ controllerInfo.notifyDisconnected();
+ }
+ });
}
// Called by Session2Link.onDisconnect
- void onDisconnect(final Controller2Link controller, int seq) {
- if (controller == null) {
- return;
- }
+ void onDisconnect(@NonNull final Controller2Link controller, int seq) {
final ControllerInfo controllerInfo;
synchronized (mLock) {
- controllerInfo = mConnectedControllers.get(controller);
+ controllerInfo = mConnectedControllers.remove(controller);
}
if (controllerInfo == null) {
return;
}
-
- final long token = Binder.clearCallingIdentity();
- try {
- mCallbackExecutor.execute(() -> {
- mCallback.onDisconnected(MediaSession2.this, controllerInfo);
- });
- mConnectedControllers.remove(controller);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ mCallbackExecutor.execute(() -> {
+ mCallback.onDisconnected(MediaSession2.this, controllerInfo);
+ });
}
// Called by Session2Link.onSessionCommand
- void onSessionCommand(final Controller2Link controller, final int seq,
+ void onSessionCommand(@NonNull final Controller2Link controller, final int seq,
final Session2Command command, final Bundle args,
@Nullable ResultReceiver resultReceiver) {
if (controller == null) {
@@ -332,34 +324,28 @@
}
// TODO: check allowed commands.
- final long token = Binder.clearCallingIdentity();
- try {
- synchronized (mLock) {
- controllerInfo.addRequestedCommandSeqNumber(seq);
- }
-
- mCallbackExecutor.execute(() -> {
- if (!controllerInfo.removeRequestedCommandSeqNumber(seq)) {
- resultReceiver.send(RESULT_INFO_SKIPPED, null);
- return;
- }
- Session2Command.Result result = mCallback.onSessionCommand(
- MediaSession2.this, controllerInfo, 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);
+ synchronized (mLock) {
+ controllerInfo.addRequestedCommandSeqNumber(seq);
}
+ mCallbackExecutor.execute(() -> {
+ if (!controllerInfo.removeRequestedCommandSeqNumber(seq)) {
+ resultReceiver.send(RESULT_INFO_SKIPPED, null);
+ return;
+ }
+ Session2Command.Result result = mCallback.onSessionCommand(
+ MediaSession2.this, controllerInfo, command, args);
+ if (resultReceiver != null) {
+ if (result == null) {
+ throw new RuntimeException("onSessionCommand shouldn't return null");
+ } else {
+ resultReceiver.send(result.getResultCode(), result.getResultData());
+ }
+ }
+ });
}
// Called by Session2Link.onCancelCommand
- void onCancelCommand(final Controller2Link controller, final int seq) {
+ void onCancelCommand(@NonNull final Controller2Link controller, final int seq) {
final ControllerInfo controllerInfo;
synchronized (mLock) {
controllerInfo = mConnectedControllers.get(controller);
@@ -367,13 +353,15 @@
if (controllerInfo == null) {
return;
}
+ controllerInfo.removeRequestedCommandSeqNumber(seq);
+ }
- final long token = Binder.clearCallingIdentity();
- try {
- controllerInfo.removeRequestedCommandSeqNumber(seq);
- } finally {
- Binder.restoreCallingIdentity(token);
+ private List<ControllerInfo> getConnectedControllers() {
+ List<ControllerInfo> controllers = new ArrayList<>();
+ synchronized (mLock) {
+ controllers.addAll(mConnectedControllers.values());
}
+ return controllers;
}
/**
@@ -660,6 +648,8 @@
* This API is not generally intended for third party application developers.
*/
public abstract static class SessionCallback {
+ ForegroundServiceEventCallback mForegroundServiceEventCallback;
+
/**
* Called when a controller is created for this session. Return allowed commands for
* controller. By default it returns {@code null}.
@@ -716,5 +706,19 @@
public void onCommandResult(@NonNull MediaSession2 session,
@NonNull ControllerInfo controller, @NonNull Object token,
@NonNull Session2Command command, @NonNull Session2Command.Result result) {}
+
+ final void onSessionClosed(MediaSession2 session) {
+ if (mForegroundServiceEventCallback != null) {
+ mForegroundServiceEventCallback.onSessionClosed(session);
+ }
+ }
+
+ void setForegroundServiceEventCallback(ForegroundServiceEventCallback callback) {
+ mForegroundServiceEventCallback = callback;
+ }
+
+ abstract static class ForegroundServiceEventCallback {
+ public void onSessionClosed(MediaSession2 session) {}
+ }
}
}
diff --git a/media/java/android/media/MediaSession2Service.java b/media/java/android/media/MediaSession2Service.java
new file mode 100644
index 0000000..8fb00fe
--- /dev/null
+++ b/media/java/android/media/MediaSession2Service.java
@@ -0,0 +1,288 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.annotation.CallSuper;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.Service;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Service containing {@link MediaSession2}.
+ * <p>
+ * This API is not generally intended for third party application developers.
+ * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+ * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
+ * for consistent behavior across all devices.
+ * @hide
+ */
+// TODO: Unhide
+// TODO: Add onUpdateNotification(), and calls it to get Notification for startForegroundService()
+// when a session's player state becomes playing.
+public abstract class MediaSession2Service extends Service {
+ /**
+ * The {@link Intent} that must be declared as handled by the service.
+ */
+ public static final String SERVICE_INTERFACE = "android.media.MediaSession2Service";
+
+ private static final String TAG = "MediaSession2Service";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ private final Object mLock = new Object();
+ @GuardedBy("mLock")
+ private Map<String, MediaSession2> mSessions = new ArrayMap<>();
+
+ private MediaSession2ServiceStub mStub;
+
+ /**
+ * Called by the system when the service is first created. Do not call this method directly.
+ * <p>
+ * Override this method if you need your own initialization. Derived classes MUST call through
+ * to the super class's implementation of this method.
+ */
+ @CallSuper
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ mStub = new MediaSession2ServiceStub(this);
+ }
+
+ @CallSuper
+ @Override
+ @Nullable
+ public IBinder onBind(@NonNull Intent intent) {
+ if (SERVICE_INTERFACE.equals(intent.getAction())) {
+ return mStub;
+ }
+ return null;
+ }
+
+ @CallSuper
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ // TODO: Dispatch media key events to the primary session.
+ return START_STICKY;
+ }
+
+ /**
+ * Called by the system to notify that it is no longer used and is being removed. Do not call
+ * this method directly.
+ * <p>
+ * Override this method if you need your own clean up. Derived classes MUST call through
+ * to the super class's implementation of this method.
+ */
+ @CallSuper
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ synchronized (mLock) {
+ for (MediaSession2 session : mSessions.values()) {
+ session.getCallback().setForegroundServiceEventCallback(null);
+ }
+ mSessions.clear();
+ }
+ mStub.close();
+ }
+
+ /**
+ * Called when a {@link MediaController2} is created with the this service's
+ * {@link Session2Token}. Return the primary session for telling the controller which session to
+ * connect.
+ * <p>
+ * Primary session is the highest priority session that this service manages. Here are some
+ * recommendations of the primary session.
+ * <ol>
+ * <li>When there's no {@link MediaSession2}, create and return a new session. Resume the
+ * playback that the app has the lastly played with the new session. The behavior is what
+ * framework expects when the framework sends key events to the service.</li>
+ * <li>When there's multiple {@link MediaSession2}s, pick the session that has the lastly
+ * started the playback. This is the same way as the framework prioritize sessions to receive
+ * media key events.</li>
+ * </ol>
+ * <p>
+ * Session returned here will be added to this service automatically. You don't need to call
+ * {@link #addSession(MediaSession2)} for that.
+ * <p>
+ * Session service will accept or reject the connection with the
+ * {@link MediaSession2.SessionCallback} in the session returned here.
+ * <p>
+ * This method is always called on the main thread.
+ *
+ * @return a new session
+ * @see MediaSession2.Builder
+ * @see #getSessions()
+ */
+ @NonNull
+ public abstract MediaSession2 onGetPrimarySession();
+
+ /**
+ * Adds a session to this service.
+ * <p>
+ * Added session will be removed automatically when it's closed, or removed when
+ * {@link #removeSession} is called.
+ *
+ * @param session a session to be added.
+ * @see #removeSession(MediaSession2)
+ */
+ public final void addSession(@NonNull MediaSession2 session) {
+ if (session == null) {
+ throw new IllegalArgumentException("session shouldn't be null");
+ }
+ if (session.isClosed()) {
+ throw new IllegalArgumentException("session is already closed");
+ }
+ synchronized (mLock) {
+ MediaSession2 previousSession = mSessions.get(session.getSessionId());
+ if (previousSession != session) {
+ if (previousSession != null) {
+ Log.w(TAG, "Session ID should be unique, ID=" + session.getSessionId()
+ + ", previous=" + previousSession + ", session=" + session);
+ }
+ return;
+ }
+ mSessions.put(session.getSessionId(), session);
+ session.getCallback().setForegroundServiceEventCallback(
+ new MediaSession2.SessionCallback.ForegroundServiceEventCallback() {
+ @Override
+ public void onSessionClosed(MediaSession2 session) {
+ removeSession(session);
+ }
+ });
+ }
+ }
+
+ /**
+ * Removes a session from this service.
+ *
+ * @param session a session to be removed.
+ * @see #addSession(MediaSession2)
+ */
+ public final void removeSession(@NonNull MediaSession2 session) {
+ if (session == null) {
+ throw new IllegalArgumentException("session shouldn't be null");
+ }
+ synchronized (mLock) {
+ mSessions.remove(session.getSessionId());
+ }
+ }
+
+ /**
+ * Gets the list of {@link MediaSession2}s that you've added to this service.
+ *
+ * @return sessions
+ */
+ public final @NonNull List<MediaSession2> getSessions() {
+ List<MediaSession2> list = new ArrayList<>();
+ synchronized (mLock) {
+ list.addAll(mSessions.values());
+ }
+ return list;
+ }
+
+ private static final class MediaSession2ServiceStub extends IMediaSession2Service.Stub
+ implements AutoCloseable {
+ final WeakReference<MediaSession2Service> mService;
+ final Handler mHandler;
+
+ MediaSession2ServiceStub(MediaSession2Service service) {
+ mService = new WeakReference<>(service);
+ mHandler = new Handler(service.getMainLooper());
+ }
+
+ @Override
+ public void connect(Controller2Link caller, int seq, Bundle connectionRequest) {
+ if (mService.get() == null) {
+ if (DEBUG) {
+ Log.d(TAG, "Service is already destroyed");
+ }
+ return;
+ }
+ if (caller == null || connectionRequest == null) {
+ if (DEBUG) {
+ Log.d(TAG, "Ignoring calls with illegal arguments, caller=" + caller
+ + ", connectionRequest=" + connectionRequest);
+ }
+ return;
+ }
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mHandler.post(() -> {
+ boolean shouldNotifyDisconnected = true;
+ try {
+ final MediaSession2Service service = mService.get();
+ if (service == null) {
+ if (DEBUG) {
+ Log.d(TAG, "Service isn't available");
+ }
+ return;
+ }
+ if (DEBUG) {
+ Log.d(TAG, "Handling incoming connection request from the"
+ + " controller, controller=" + caller + ", uid=" + uid);
+ }
+ final MediaSession2 session;
+ session = service.onGetPrimarySession();
+ service.addSession(session);
+ shouldNotifyDisconnected = false;
+ session.onConnect(caller, pid, uid, seq, connectionRequest);
+ } catch (Exception e) {
+ // Don't propagate exception in service to the controller.
+ Log.w(TAG, "Failed to add a session to session service", e);
+ } finally {
+ // Trick to call onDisconnected() in one place.
+ if (shouldNotifyDisconnected) {
+ if (DEBUG) {
+ Log.d(TAG, "Service has destroyed prematurely."
+ + " Rejecting connection");
+ }
+ try {
+ caller.notifyDisconnected(0);
+ } catch (RuntimeException e) {
+ // Controller may be died prematurely.
+ // Not an issue because we'll ignore it anyway.
+ }
+ }
+ }
+ });
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void close() {
+ mHandler.removeCallbacksAndMessages(null);
+ mService.clear();
+ }
+ }
+}
diff --git a/media/java/android/media/Session2Link.java b/media/java/android/media/Session2Link.java
index 5fe558d..08664aa 100644
--- a/media/java/android/media/Session2Link.java
+++ b/media/java/android/media/Session2Link.java
@@ -17,6 +17,7 @@
package android.media;
import android.annotation.NonNull;
+import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
@@ -145,8 +146,9 @@
}
/** Stub implementation for IMediaSession2.connect */
- public void onConnect(final Controller2Link caller, int seq, Bundle connectionRequest) {
- mSession.onConnect(caller, seq, connectionRequest);
+ public void onConnect(final Controller2Link caller, int pid, int uid, int seq,
+ Bundle connectionRequest) {
+ mSession.onConnect(caller, pid, uid, seq, connectionRequest);
}
/** Stub implementation for IMediaSession2.disconnect */
@@ -168,23 +170,57 @@
private class Session2Stub extends IMediaSession2.Stub {
@Override
public void connect(final Controller2Link caller, int seq, Bundle connectionRequest) {
- Session2Link.this.onConnect(caller, seq, connectionRequest);
+ if (caller == null || connectionRequest == null) {
+ return;
+ }
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ Session2Link.this.onConnect(caller, pid, uid, seq, connectionRequest);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
@Override
public void disconnect(final Controller2Link caller, int seq) {
- Session2Link.this.onDisconnect(caller, seq);
+ if (caller == null) {
+ return;
+ }
+ final long token = Binder.clearCallingIdentity();
+ try {
+ Session2Link.this.onDisconnect(caller, seq);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
@Override
public void sendSessionCommand(final Controller2Link caller, final int seq,
final Session2Command command, final Bundle args, ResultReceiver resultReceiver) {
- Session2Link.this.onSessionCommand(caller, seq, command, args, resultReceiver);
+ if (caller == null) {
+ return;
+ }
+ final long token = Binder.clearCallingIdentity();
+ try {
+ Session2Link.this.onSessionCommand(caller, seq, command, args, resultReceiver);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
@Override
public void cancelSessionCommand(final Controller2Link caller, final int seq) {
- Session2Link.this.onCancelCommand(caller, seq);
+ if (caller == null) {
+ return;
+ }
+ final long token = Binder.clearCallingIdentity();
+ try {
+ Session2Link.this.onCancelCommand(caller, seq);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
}
}
diff --git a/media/java/android/media/Session2Token.java b/media/java/android/media/Session2Token.java
index 95ee4c0..c7b8911 100644
--- a/media/java/android/media/Session2Token.java
+++ b/media/java/android/media/Session2Token.java
@@ -152,9 +152,7 @@
mType = in.readInt();
mPackageName = in.readString();
mServiceName = in.readString();
- // TODO: Uncomment below and stop hardcode mSessionLink
- mSessionLink = null;
- //mSessionLink = ISession.Stub.asInterface(in.readStrongBinder());
+ mSessionLink = Session2Link.CREATOR.createFromParcel(in);
mComponentName = ComponentName.unflattenFromString(in.readString());
}
@@ -164,8 +162,7 @@
dest.writeInt(mType);
dest.writeString(mPackageName);
dest.writeString(mServiceName);
- // TODO: Uncomment below
- //dest.writeStrongBinder(mSessionLink.getBinder());
+ mSessionLink.writeToParcel(dest, flags);
dest.writeString(mComponentName == null ? "" : mComponentName.flattenToString());
}
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index 452c6e1..0198470 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -84,7 +84,7 @@
}
cc_library_shared {
- name: "libmedia2_jni",
+ name: "libmediaplayer2_jni",
srcs: [
"android_media_DataSourceCallback.cpp",
@@ -116,7 +116,10 @@
"libz",
],
- header_libs: ["libhardware_headers"],
+ header_libs: [
+ "libhardware_headers",
+ "libnativewindow_headers",
+ ],
static_libs: [
"libbase",
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
new file mode 100644
index 0000000..1d7d6de
--- /dev/null
+++ b/media/jni/Android.mk
@@ -0,0 +1,30 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_CFLAGS := -Wall -Werror
+LOCAL_SRC_FILES := \
+ Media2Jni.cpp \
+
+# TODO: Move libmedia2_jni from system to media apex. Currently, libraries defined in
+# Android.mk is not visible in apex build.
+LOCAL_MODULE:= libmedia2_jni
+LOCAL_SHARED_LIBRARIES := libdl liblog
+
+sanitizer_runtime_libraries := $(call normalize-path-list,$(addsuffix .so,\
+ $(ADDRESS_SANITIZER_RUNTIME_LIBRARY) \
+ $(UBSAN_RUNTIME_LIBRARY) \
+ $(TSAN_RUNTIME_LIBRARY)))
+
+# $(info Sanitizer: $(sanitizer_runtime_libraries))
+
+ndk_libraries := $(call normalize-path-list,$(addprefix lib,$(addsuffix .so,\
+ $(NDK_PREBUILT_SHARED_LIBRARIES))))
+
+# $(info NDK: $(ndk_libraries))
+
+LOCAL_CFLAGS += -DLINKED_LIBRARIES='"$(sanitizer_runtime_libraries):$(ndk_libraries)"'
+
+sanitizer_runtime_libraries :=
+ndk_libraries :=
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/jni/Media2Jni.cpp b/media/jni/Media2Jni.cpp
new file mode 100644
index 0000000..6c0a65c
--- /dev/null
+++ b/media/jni/Media2Jni.cpp
@@ -0,0 +1,89 @@
+/*
+**
+** 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.
+*/
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaPlayer2-JNI"
+#include "utils/Log.h"
+
+#include "jni.h"
+#include <android/dlext.h>
+#include <dirent.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <string.h>
+
+extern "C" {
+ // Copied from GraphicsEnv.cpp
+ // TODO(b/37049319) Get this from a header once one exists
+ android_namespace_t* android_create_namespace(const char* name,
+ const char* ld_library_path,
+ const char* default_library_path,
+ uint64_t type,
+ const char* permitted_when_isolated_path,
+ android_namespace_t* parent);
+ bool android_link_namespaces(android_namespace_t* from,
+ android_namespace_t* to,
+ const char* shared_libs_sonames);
+ enum {
+ ANDROID_NAMESPACE_TYPE_ISOLATED = 1,
+ };
+
+} // extern "C"
+
+static const char kApexLibPath[] = "/apex/com.android.media/lib"
+#ifdef __LP64__
+ "64"
+#endif
+ "/";
+static const char kMediaPlayer2LibPath[] = "/apex/com.android.media/lib"
+#ifdef __LP64__
+ "64"
+#endif
+ "/libmediaplayer2_jni.so";
+
+typedef jint (*Media2JniOnLoad)(JavaVM*, void*);
+
+JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved)
+{
+ android_namespace_t *media2Ns = android_create_namespace("media2",
+ nullptr, // ld_library_path
+ kApexLibPath,
+ ANDROID_NAMESPACE_TYPE_ISOLATED,
+ nullptr, // permitted_when_isolated_path
+ nullptr); // parent
+ if (!android_link_namespaces(media2Ns, nullptr, LINKED_LIBRARIES)) {
+ ALOGE("Failed to link namespace. Failed to load extractor plug-ins in apex.");
+ return -1;
+ }
+ const android_dlextinfo dlextinfo = {
+ .flags = ANDROID_DLEXT_USE_NAMESPACE,
+ .library_namespace = media2Ns,
+ };
+ // load libmediaplayer2_jni and call JNI_OnLoad.
+ void *libHandle = android_dlopen_ext(kMediaPlayer2LibPath, RTLD_NOW | RTLD_LOCAL, &dlextinfo);
+ if (libHandle == NULL) {
+ ALOGW("couldn't dlopen(%s) %s", kMediaPlayer2LibPath, strerror(errno));
+ return -1;
+ }
+ Media2JniOnLoad media2JniOnLoad = (Media2JniOnLoad) dlsym(libHandle, "JNI_OnLoad");
+ if (!media2JniOnLoad) {
+ ALOGW("%s does not contain JNI_OnLoad()", kMediaPlayer2LibPath);
+ dlclose(libHandle);
+ return -1;
+ }
+ return media2JniOnLoad(vm, reserved);
+}
diff --git a/native/android/Android.bp b/native/android/Android.bp
index fdcfc44..73d4c45 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -49,6 +49,7 @@
"sharedmem.cpp",
"storage_manager.cpp",
"surface_texture.cpp",
+ "surface_control.cpp",
"system_fonts.cpp",
"trace.cpp",
],
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index 537aed4..8be8eda 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -205,6 +205,9 @@
AStorageManager_mountObb;
AStorageManager_new;
AStorageManager_unmountObb;
+ ASurfaceControl_create; # introduced=29
+ ASurfaceControl_createFromWindow; # introduced=29
+ ASurfaceControl_destroy; # introduced=29
ASurfaceTexture_acquireANativeWindow; # introduced=28
ASurfaceTexture_attachToGLContext; # introduced=28
ASurfaceTexture_detachFromGLContext; # introduced=28
@@ -213,6 +216,16 @@
ASurfaceTexture_getTransformMatrix; # introduced=28
ASurfaceTexture_release; # introduced=28
ASurfaceTexture_updateTexImage; # introduced=28
+ ASurfaceTransaction_apply; # introduced=29
+ ASurfaceTransaction_create; # introduced=29
+ ASurfaceTransaction_delete; # introduced=29
+ ASurfaceTransaction_setBuffer; # introduced=29
+ ASurfaceTransaction_setBufferTransparency; # introduced=29
+ ASurfaceTransaction_setDamageRegion; # introduced=29
+ ASurfaceTransaction_setGeometry; # introduced=29
+ ASurfaceTransaction_setOnComplete; # introduced=29
+ ASurfaceTransaction_setVisibility; # introduced=29
+ ASurfaceTransaction_setZOrder; # introduced=29
ASystemFontIterator_open; # introduced=29
ASystemFontIterator_close; # introduced=29
ASystemFontIterator_next; # introduced=29
diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp
new file mode 100644
index 0000000..ead5b0b
--- /dev/null
+++ b/native/android/surface_control.cpp
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/native_window.h>
+#include <android/surface_control.h>
+
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+#include <gui/SurfaceControl.h>
+
+using namespace android;
+
+using Transaction = SurfaceComposerClient::Transaction;
+
+#define CHECK_NOT_NULL(name) \
+ LOG_ALWAYS_FATAL_IF(name == nullptr, "nullptr passed as " #name " argument");
+
+#define CHECK_VALID_RECT(name) \
+ LOG_ALWAYS_FATAL_IF(!static_cast<const Rect&>(name).isValid(), \
+ "invalid arg passed as " #name " argument");
+
+Transaction* ASurfaceTransaction_to_Transaction(ASurfaceTransaction* aSurfaceTransaction) {
+ return reinterpret_cast<Transaction*>(aSurfaceTransaction);
+}
+
+SurfaceControl* ASurfaceControl_to_SurfaceControl(ASurfaceControl* aSurfaceControl) {
+ return reinterpret_cast<SurfaceControl*>(aSurfaceControl);
+}
+
+void SurfaceControl_acquire(SurfaceControl* surfaceControl) {
+ // incStrong/decStrong token must be the same, doesn't matter what it is
+ surfaceControl->incStrong((void*)SurfaceControl_acquire);
+}
+
+void SurfaceControl_release(SurfaceControl* surfaceControl) {
+ // incStrong/decStrong token must be the same, doesn't matter what it is
+ surfaceControl->decStrong((void*)SurfaceControl_acquire);
+}
+
+ASurfaceControl* ASurfaceControl_createFromWindow(ANativeWindow* window, const char* debug_name) {
+ CHECK_NOT_NULL(window);
+ CHECK_NOT_NULL(debug_name);
+
+ sp<SurfaceComposerClient> client = new SurfaceComposerClient();
+ if (client->initCheck() != NO_ERROR) {
+ return nullptr;
+ }
+
+ uint32_t flags = ISurfaceComposerClient::eFXSurfaceBufferState;
+ sp<SurfaceControl> surfaceControl =
+ client->createWithSurfaceParent(String8(debug_name), 0 /* width */, 0 /* height */,
+ // Format is only relevant for buffer queue layers.
+ PIXEL_FORMAT_UNKNOWN /* format */, flags,
+ static_cast<Surface*>(window));
+ if (!surfaceControl) {
+ return nullptr;
+ }
+
+ SurfaceControl_acquire(surfaceControl.get());
+ return reinterpret_cast<ASurfaceControl*>(surfaceControl.get());
+}
+
+ASurfaceControl* ASurfaceControl_create(ASurfaceControl* parent, const char* debug_name) {
+ CHECK_NOT_NULL(parent);
+ CHECK_NOT_NULL(debug_name);
+
+ SurfaceComposerClient* client = ASurfaceControl_to_SurfaceControl(parent)->getClient().get();
+
+ SurfaceControl* surfaceControlParent = ASurfaceControl_to_SurfaceControl(parent);
+
+ uint32_t flags = ISurfaceComposerClient::eFXSurfaceBufferState;
+ sp<SurfaceControl> surfaceControl =
+ client->createSurface(String8(debug_name), 0 /* width */, 0 /* height */,
+ // Format is only relevant for buffer queue layers.
+ PIXEL_FORMAT_UNKNOWN /* format */, flags,
+ surfaceControlParent);
+ if (!surfaceControl) {
+ return nullptr;
+ }
+
+ SurfaceControl_acquire(surfaceControl.get());
+ return reinterpret_cast<ASurfaceControl*>(surfaceControl.get());
+}
+
+void ASurfaceControl_destroy(ASurfaceControl* aSurfaceControl) {
+ sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+
+ Transaction().reparent(surfaceControl, nullptr).apply();
+ SurfaceControl_release(surfaceControl.get());
+}
+
+ASurfaceTransaction* ASurfaceTransaction_create() {
+ Transaction* transaction = new Transaction;
+ return reinterpret_cast<ASurfaceTransaction*>(transaction);
+}
+
+void ASurfaceTransaction_delete(ASurfaceTransaction* aSurfaceTransaction) {
+ Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+ delete transaction;
+}
+
+void ASurfaceTransaction_apply(ASurfaceTransaction* aSurfaceTransaction) {
+ CHECK_NOT_NULL(aSurfaceTransaction);
+
+ Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+ transaction->apply();
+}
+
+void ASurfaceTransaction_setOnComplete(ASurfaceTransaction* aSurfaceTransaction, void* context,
+ ASurfaceTransaction_OnComplete func) {
+ CHECK_NOT_NULL(aSurfaceTransaction);
+ CHECK_NOT_NULL(context);
+ CHECK_NOT_NULL(func);
+
+ TransactionCompletedCallbackTakesContext callback = [func](void* callback_context,
+ const TransactionStats& stats) {
+ int fence = (stats.presentFence) ? stats.presentFence->dup() : -1;
+ (*func)(callback_context, fence);
+ };
+
+ Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+ transaction->addTransactionCompletedCallback(callback, context);
+}
+
+void ASurfaceTransaction_setVisibility(ASurfaceTransaction* aSurfaceTransaction, ASurfaceControl* aSurfaceControl,
+ int8_t visibility) {
+ CHECK_NOT_NULL(aSurfaceTransaction);
+ CHECK_NOT_NULL(aSurfaceControl);
+
+ sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+ Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+ switch (visibility) {
+ case ASURFACE_TRANSACTION_VISIBILITY_SHOW:
+ transaction->show(surfaceControl);
+ break;
+ case ASURFACE_TRANSACTION_VISIBILITY_HIDE:
+ transaction->hide(surfaceControl);
+ break;
+ default:
+ LOG_ALWAYS_FATAL("invalid visibility %d", visibility);
+ }
+}
+
+void ASurfaceTransaction_setZOrder(ASurfaceTransaction* aSurfaceTransaction, ASurfaceControl* aSurfaceControl,
+ int32_t z_order) {
+ CHECK_NOT_NULL(aSurfaceTransaction);
+ CHECK_NOT_NULL(aSurfaceControl);
+
+ sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+ Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+ transaction->setLayer(surfaceControl, z_order);
+}
+
+void ASurfaceTransaction_setBuffer(ASurfaceTransaction* aSurfaceTransaction, ASurfaceControl* aSurfaceControl,
+ AHardwareBuffer* buffer, int fence_fd) {
+ CHECK_NOT_NULL(aSurfaceTransaction);
+ CHECK_NOT_NULL(aSurfaceControl);
+
+ sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+ Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+ sp<GraphicBuffer> graphic_buffer(reinterpret_cast<GraphicBuffer*>(buffer));
+
+ transaction->setBuffer(surfaceControl, graphic_buffer);
+ if (fence_fd != -1) {
+ sp<Fence> fence = new Fence(fence_fd);
+ transaction->setAcquireFence(surfaceControl, fence);
+ }
+}
+
+void ASurfaceTransaction_setGeometry(ASurfaceTransaction* aSurfaceTransaction,
+ ASurfaceControl* aSurfaceControl, const ARect& source,
+ const ARect& destination, int32_t transform) {
+ CHECK_NOT_NULL(aSurfaceTransaction);
+ CHECK_NOT_NULL(aSurfaceControl);
+ CHECK_VALID_RECT(source);
+ CHECK_VALID_RECT(destination);
+
+ sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+ Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+ transaction->setCrop(surfaceControl, static_cast<const Rect&>(source));
+ transaction->setFrame(surfaceControl, static_cast<const Rect&>(destination));
+ transaction->setTransform(surfaceControl, transform);
+}
+
+void ASurfaceTransaction_setBufferTransparency(ASurfaceTransaction* aSurfaceTransaction,
+ ASurfaceControl* aSurfaceControl,
+ int8_t transparency) {
+ CHECK_NOT_NULL(aSurfaceTransaction);
+ CHECK_NOT_NULL(aSurfaceControl);
+
+ sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+ Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+ uint32_t flags = (transparency == ASURFACE_TRANSACTION_TRANSPARENCY_OPAQUE) ?
+ layer_state_t::eLayerOpaque : 0;
+ transaction->setFlags(surfaceControl, flags, layer_state_t::eLayerOpaque);
+}
+
+void ASurfaceTransaction_setDamageRegion(ASurfaceTransaction* aSurfaceTransaction, ASurfaceControl* aSurfaceControl,
+ const ARect rects[], uint32_t count) {
+ CHECK_NOT_NULL(aSurfaceTransaction);
+ CHECK_NOT_NULL(aSurfaceControl);
+
+ sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+ Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+ Region region;
+ for (uint32_t i = 0; i < count; ++i) {
+ region.merge(static_cast<const Rect&>(rects[i]));
+ }
+
+ transaction->setSurfaceDamageRegion(surfaceControl, region);
+}
diff --git a/native/webview/plat_support/draw_fn.h b/native/webview/plat_support/draw_fn.h
index bb2ee9b..0490e65 100644
--- a/native/webview/plat_support/draw_fn.h
+++ b/native/webview/plat_support/draw_fn.h
@@ -74,7 +74,10 @@
VkQueue queue;
uint32_t graphics_queue_index;
uint32_t instance_version;
- const char* const* enabled_extension_names;
+ const char* const* enabled_instance_extension_names;
+ uint32_t enabled_instance_extension_names_length;
+ const char* const* enabled_device_extension_names;
+ uint32_t enabled_device_extension_names_length;
// Only one of device_features and device_features_2 should be non-null.
// If both are null then no features are enabled.
VkPhysicalDeviceFeatures* device_features;
@@ -128,15 +131,13 @@
struct AwDrawFn_PostDrawVkParams {
int version;
-
- // Input: Fence for the composite command buffer to signal it has finished its
- // work on the GPU.
- int fd;
};
// Called on render thread while UI thread is blocked. Called for both GL and
// VK.
-typedef void AwDrawFn_OnSync(int functor, void* data, AwDrawFn_OnSyncParams* params);
+typedef void AwDrawFn_OnSync(int functor,
+ void* data,
+ AwDrawFn_OnSyncParams* params);
// Called on render thread when either the context is destroyed _or_ when the
// functor's last reference goes away. Will always be called with an active
@@ -150,17 +151,24 @@
typedef void AwDrawFn_OnDestroyed(int functor, void* data);
// Only called for GL.
-typedef void AwDrawFn_DrawGL(int functor, void* data, AwDrawFn_DrawGLParams* params);
+typedef void AwDrawFn_DrawGL(int functor,
+ void* data,
+ AwDrawFn_DrawGLParams* params);
// Initialize vulkan state. Needs to be called again after any
// OnContextDestroyed. Only called for Vulkan.
-typedef void AwDrawFn_InitVk(int functor, void* data, AwDrawFn_InitVkParams* params);
+typedef void AwDrawFn_InitVk(int functor,
+ void* data,
+ AwDrawFn_InitVkParams* params);
// Only called for Vulkan.
-typedef void AwDrawFn_DrawVk(int functor, void* data, AwDrawFn_DrawVkParams* params);
+typedef void AwDrawFn_DrawVk(int functor,
+ void* data,
+ AwDrawFn_DrawVkParams* params);
// Only called for Vulkan.
-typedef void AwDrawFn_PostDrawVk(int functor, void* data,
+typedef void AwDrawFn_PostDrawVk(int functor,
+ void* data,
AwDrawFn_PostDrawVkParams* params);
struct AwDrawFnFunctorCallbacks {
@@ -183,7 +191,8 @@
typedef AwDrawFnRenderMode AwDrawFn_QueryRenderMode(void);
// Create a functor. |functor_callbacks| should be valid until OnDestroyed.
-typedef int AwDrawFn_CreateFunctor(void* data, AwDrawFnFunctorCallbacks* functor_callbacks);
+typedef int AwDrawFn_CreateFunctor(void* data,
+ AwDrawFnFunctorCallbacks* functor_callbacks);
// May be called on any thread to signal that the functor should be destroyed.
// The functor will receive an onDestroyed when the last usage of it is
diff --git a/native/webview/plat_support/draw_functor.cpp b/native/webview/plat_support/draw_functor.cpp
index 6c1ceab..b97bbc3 100644
--- a/native/webview/plat_support/draw_functor.cpp
+++ b/native/webview/plat_support/draw_functor.cpp
@@ -74,6 +74,79 @@
support->callbacks.draw_gl(functor, support->data, ¶ms);
}
+void initializeVk(int functor, void* data,
+ const uirenderer::VkFunctorInitParams& init_vk_params) {
+ SupportData* support = static_cast<SupportData*>(data);
+ VkPhysicalDeviceFeatures2 device_features_2;
+ if (init_vk_params.device_features_2)
+ device_features_2 = *init_vk_params.device_features_2;
+
+ AwDrawFn_InitVkParams params{
+ .version = kAwDrawFnVersion,
+ .instance = init_vk_params.instance,
+ .physical_device = init_vk_params.physical_device,
+ .device = init_vk_params.device,
+ .queue = init_vk_params.queue,
+ .graphics_queue_index = init_vk_params.graphics_queue_index,
+ .instance_version = init_vk_params.instance_version,
+ .enabled_instance_extension_names =
+ init_vk_params.enabled_instance_extension_names,
+ .enabled_instance_extension_names_length =
+ init_vk_params.enabled_instance_extension_names_length,
+ .enabled_device_extension_names =
+ init_vk_params.enabled_device_extension_names,
+ .enabled_device_extension_names_length =
+ init_vk_params.enabled_device_extension_names_length,
+ .device_features = nullptr,
+ .device_features_2 =
+ init_vk_params.device_features_2 ? &device_features_2 : nullptr,
+ };
+ support->callbacks.init_vk(functor, support->data, ¶ms);
+}
+
+void drawVk(int functor, void* data, const uirenderer::VkFunctorDrawParams& draw_vk_params) {
+ SupportData* support = static_cast<SupportData*>(data);
+ float gabcdef[7];
+ draw_vk_params.color_space_ptr->transferFn(gabcdef);
+ AwDrawFn_DrawVkParams params{
+ .version = kAwDrawFnVersion,
+ .width = draw_vk_params.width,
+ .height = draw_vk_params.height,
+ .is_layer = draw_vk_params.is_layer,
+ .secondary_command_buffer = draw_vk_params.secondary_command_buffer,
+ .color_attachment_index = draw_vk_params.color_attachment_index,
+ .compatible_render_pass = draw_vk_params.compatible_render_pass,
+ .format = draw_vk_params.format,
+ .transfer_function_g = gabcdef[0],
+ .transfer_function_a = gabcdef[1],
+ .transfer_function_b = gabcdef[2],
+ .transfer_function_c = gabcdef[3],
+ .transfer_function_d = gabcdef[4],
+ .transfer_function_e = gabcdef[5],
+ .transfer_function_f = gabcdef[6],
+ .clip_left = draw_vk_params.clip_left,
+ .clip_top = draw_vk_params.clip_top,
+ .clip_right = draw_vk_params.clip_right,
+ .clip_bottom = draw_vk_params.clip_bottom,
+ };
+ COMPILE_ASSERT(sizeof(params.color_space_toXYZD50) == sizeof(skcms_Matrix3x3),
+ gamut_transform_size_mismatch);
+ draw_vk_params.color_space_ptr->toXYZD50(
+ reinterpret_cast<skcms_Matrix3x3*>(¶ms.color_space_toXYZD50));
+ COMPILE_ASSERT(NELEM(params.transform) == NELEM(draw_vk_params.transform),
+ mismatched_transform_matrix_sizes);
+ for (int i = 0; i < NELEM(params.transform); ++i) {
+ params.transform[i] = draw_vk_params.transform[i];
+ }
+ support->callbacks.draw_vk(functor, support->data, ¶ms);
+}
+
+void postDrawVk(int functor, void* data) {
+ SupportData* support = static_cast<SupportData*>(data);
+ AwDrawFn_PostDrawVkParams params{.version = kAwDrawFnVersion};
+ support->callbacks.post_draw_vk(functor, support->data, ¶ms);
+}
+
int CreateFunctor(void* data, AwDrawFnFunctorCallbacks* functor_callbacks) {
static bool callbacks_initialized = false;
static uirenderer::WebViewFunctorCallbacks webview_functor_callbacks = {
@@ -82,9 +155,19 @@
.onDestroyed = &onDestroyed,
};
if (!callbacks_initialized) {
- // Under uirenderer::RenderMode::Vulkan, whether gles or vk union should
- // be populated should match whether the vk-gl interop is used.
- webview_functor_callbacks.gles.draw = &draw_gl;
+ switch (uirenderer::WebViewFunctor_queryPlatformRenderMode()) {
+ case uirenderer::RenderMode::OpenGL_ES:
+ webview_functor_callbacks.gles.draw = &draw_gl;
+ break;
+ case uirenderer::RenderMode::Vulkan:
+ webview_functor_callbacks.vk.initialize = &initializeVk;
+ webview_functor_callbacks.vk.draw = &drawVk;
+ webview_functor_callbacks.vk.postDraw = &postDrawVk;
+ // TODO(boliu): Remove this once SkiaRecordingCanvas::drawWebViewFunctor
+ // no longer uses GL interop.
+ webview_functor_callbacks.gles.draw = &draw_gl;
+ break;
+ }
callbacks_initialized = true;
}
SupportData* support = new SupportData{
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 03c6205..16bfcc9 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -99,8 +99,12 @@
<string name="connected_via_network_scorer_default">Automatically connected via network rating provider</string>
<!-- Status message of Wi-Fi when it is connected by Passpoint configuration. [CHAR LIMIT=NONE] -->
<string name="connected_via_passpoint">Connected via %1$s</string>
+ <!-- Status message of Wi-Fi when it is connected by Passpoint configuration. [CHAR LIMIT=NONE] -->
+ <string name="ssid_by_passpoint_provider"><xliff:g id="ssid" example="Cafe Wifi">%1$s</xliff:g> by <xliff:g id="passpointProvider" example="Passpoint Provider">%2$s</xliff:g></string>
<!-- Status message of Wi-Fi when network has matching passpoint credentials. [CHAR LIMIT=NONE] -->
<string name="available_via_passpoint">Available via %1$s</string>
+ <!-- Status message of OSU Provider network when not connected. [CHAR LIMIT=NONE] -->
+ <string name="tap_to_set_up">Tap to set up</string>
<!-- Package name for Settings app-->
<string name="settings_package" translatable="false">com.android.settings</string>
<!-- Package name for Certinstaller app-->
@@ -123,6 +127,79 @@
<!-- Status message of Wi-Fi when an available network is a carrier network. [CHAR LIMIT=NONE] -->
<string name="available_via_carrier">Available via %1$s</string>
+ <!-- Status message of OSU Provider on receiving OSU_FAILURE_AP_CONNECTION. [CHAR LIMIT=NONE] -->
+ <string name="osu_failure_ap_connection">Connection failed</string>
+ <!-- Status message of OSU Provider on receiving OSU_FAILURE_SERVER_URL_INVALID. [CHAR LIMIT=NONE] -->
+ <string name="osu_failure_server_url_invalid">Invalid OSU server URL</string>
+ <!-- Status message of OSU Provider on receiving OSU_FAILURE_SERVER_CONNECTION. [CHAR LIMIT=NONE] -->
+ <string name="osu_failure_server_connection">OSU server connection failed</string>
+ <!-- Status message of OSU Provider on receiving OSU_FAILURE_SERVER_VALIDATION. [CHAR LIMIT=NONE] -->
+ <string name="osu_failure_server_validation">OSU server validation failed</string>
+ <!-- Status message of OSU Provider on receiving OSU_FAILURE_SERVICE_PROVIDER_VERIFICATION. [CHAR LIMIT=NONE] -->
+ <string name="osu_failure_service_provider_verification">Invalid OSU server certificate</string>
+ <!-- Status message of OSU Provider on receiving OSU_FAILURE_PROVISIONING_ABORTED. [CHAR LIMIT=NONE] -->
+ <string name="osu_failure_provisioning_aborted">Provisioning aborted</string>
+ <!-- Status message of OSU Provider on receiving OSU_FAILURE_PROVISIONING_NOT_AVAILABLE. [CHAR LIMIT=NONE] -->
+ <string name="osu_failure_provisioning_not_available">Provisioning not available</string>
+ <!-- Status message of OSU Provider on receiving OSU_FAILURE_INVALID_SERVER_URL. [CHAR LIMIT=NONE] -->
+ <string name="osu_failure_invalid_server_url">Invalid OSU server URL</string>
+ <!-- Status message of OSU Provider on receiving OSU_FAILURE_UNEXPECTED_COMMAND_TYPE. [CHAR LIMIT=NONE] -->
+ <string name="osu_failure_unexpected_command_type">Unexpected command type</string>
+ <!-- Status message of OSU Provider on receiving OSU_FAILURE_UNEXPECTED_SOAP_MESSAGE_TYPE. [CHAR LIMIT=NONE] -->
+ <string name="osu_failure_unexpected_soap_message_type">Unexpected SOAP message type</string>
+ <!-- Status message of OSU Provider on receiving OSU_FAILURE_SOAP_MESSAGE_EXCHANGE. [CHAR LIMIT=NONE] -->
+ <string name="osu_failure_soap_message_exchange">SOAP message exchange failed</string>
+ <!-- Status message of OSU Provider on receiving OSU_FAILURE_START_REDIRECT_LISTENER. [CHAR LIMIT=NONE] -->
+ <string name="osu_failure_start_redirect_listener">Redirect listener failed to start</string>
+ <!-- Status message of OSU Provider on receiving OSU_FAILURE_TIMED_OUT_REDIRECT_LISTENER. [CHAR LIMIT=NONE] -->
+ <string name="osu_failure_timed_out_redirect_listener">Timed out waiting for redirect</string>
+ <!-- Status message of OSU Provider on receiving OSU_FAILURE_NO_OSU_ACTIVITY_FOUND. [CHAR LIMIT=NONE] -->
+ <string name="osu_failure_no_osu_activity_found">No OSU activity found</string>
+ <!-- Status message of OSU Provider on receiving OSU_FAILURE_UNEXPECTED_SOAP_MESSAGE_STATUS. [CHAR LIMIT=NONE] -->
+ <string name="osu_failure_unexpected_soap_message_status">Unexpected SOAP message status</string>
+ <!-- Status message of OSU Provider on receiving OSU_FAILURE_NO_PPS_MO. [CHAR LIMIT=NONE] -->
+ <string name="osu_failure_no_pps_mo">Failed to find PPS-MO</string>
+ <!-- Status message of OSU Provider on receiving OSU_FAILURE_NO_AAA_SERVER_TRUST_ROOT_NODE. [CHAR LIMIT=NONE] -->
+ <string name="osu_failure_no_aaa_server_trust_root_node">Failed to find trust root node for AAA server</string>
+ <!-- Status message of OSU Provider on receiving OSU_FAILURE_NO_REMEDIATION_SERVER_TRUST_ROOT_NODE. [CHAR LIMIT=NONE] -->
+ <string name="osu_failure_no_remediation_server_trust_root_node">Failed to find trust root node for remediation server</string>
+ <!-- Status message of OSU Provider on receiving OSU_FAILURE_NO_POLICY_SERVER_TRUST_ROOT_NODE. [CHAR LIMIT=NONE] -->
+ <string name="osu_failure_no_policy_server_trust_root_node">Failed to find trust root node for policy server</string>
+ <!-- Status message of OSU Provider on receiving OSU_FAILURE_RETRIEVE_TRUST_ROOT_CERTIFICATES. [CHAR LIMIT=NONE] -->
+ <string name="osu_failure_retrieve_trust_root_certificates">Failed to retrieve trust root certificates</string>
+ <!-- Status message of OSU Provider on receiving OSU_FAILURE_NO_AAA_TRUST_ROOT_CERTIFICATE. [CHAR LIMIT=NONE] -->
+ <string name="osu_failure_no_aaa_trust_root_certificate">Failed to find trust root certificate for AAA server</string>
+ <!-- Status message of OSU Provider on receiving OSU_FAILURE_ADD_PASSPOINT_CONFIGURATION. [CHAR LIMIT=NONE] -->
+ <string name="osu_failure_add_passpoint_configuration">Failed to add PassPoint configuration</string>
+ <!-- Status message of OSU Provider on receiving OSU_FAILURE_OSU_PROVIDER_NOT_FOUND. [CHAR LIMIT=NONE] -->
+ <string name="osu_failure_osu_provider_not_found">Failed to find an OSU provider</string>
+
+ <!-- Status message of OSU Provider on receiving OSU_STATUS_AP_CONNECTING. [CHAR LIMIT=NONE] -->
+ <string name="osu_status_ap_connecting">Connecting</string>
+ <!-- Status message of OSU Provider on receiving OSU_STATUS_AP_CONNECTED. [CHAR LIMIT=NONE] -->
+ <string name="osu_status_ap_connected">Connected</string>
+ <!-- Status message of OSU Provider on receiving OSU_STATUS_SERVER_CONNECTING. [CHAR LIMIT=NONE] -->
+ <string name="osu_status_server_connecting">Connecting to OSU server</string>
+ <!-- Status message of OSU Provider on receiving OSU_STATUS_SERVER_VALIDATED. [CHAR LIMIT=NONE] -->
+ <string name="osu_status_server_validated">OSU server validated</string>
+ <!-- Status message of OSU Provider on receiving OSU_STATUS_SERVER_CONNECTED. [CHAR LIMIT=NONE] -->
+ <string name="osu_status_server_connected">Connected to OSU server</string>
+ <!-- Status message of OSU Provider on receiving OSU_STATUS_INIT_SOAP_EXCHANGE. [CHAR LIMIT=NONE] -->
+ <string name="osu_status_init_soap_exchange">Initial SOAP exchange</string>
+ <!-- Status message of OSU Provider on receiving OSU_STATUS_WAITING_FOR_REDIRECT_RESPONSE. [CHAR LIMIT=NONE] -->
+ <string name="osu_status_waiting_for_redirect_response">Waiting for redirect response</string>
+ <!-- Status message of OSU Provider on receiving OSU_STATUS_REDIRECT_RESPONSE_RECEIVED. [CHAR LIMIT=NONE] -->
+ <string name="osu_status_redirect_response_received">Received redirect response</string>
+ <!-- Status message of OSU Provider on receiving OSU_STATUS_SECOND_SOAP_EXCHANGE. [CHAR LIMIT=NONE] -->
+ <string name="osu_status_second_soap_exchange">Second SOAP exchange</string>
+ <!-- Status message of OSU Provider on receiving OSU_STATUS_THIRD_SOAP_EXCHANGE. [CHAR LIMIT=NONE] -->
+ <string name="osu_status_third_soap_exchange">Third SOAP exchange</string>
+ <!-- Status message of OSU Provider on receiving OSU_STATUS_RETRIEVING_TRUST_ROOT_CERTS. [CHAR LIMIT=NONE] -->
+ <string name="osu_status_retrieving_trust_root_certs">Retrieving trust root certificates</string>
+
+ <!-- Status message of OSU Provider on completing provisioning. [CHAR LIMIT=NONE] -->
+ <string name="osu_provisioning_complete">Provisioning complete</string>
+
<!-- Speed label for very slow network speed -->
<string name="speed_label_very_slow">Very Slow</string>
<!-- Speed label for slow network speed -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 595aeb3..c751c39 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -38,8 +38,8 @@
private static final String CURRENT_MODE_KEY = "CURRENT_MODE";
private static final String NEW_MODE_KEY = "NEW_MODE";
@VisibleForTesting
- static final String STORAGE_MANAGER_SHOW_OPT_IN_PROPERTY =
- "ro.storage_manager.show_opt_in";
+ static final String STORAGE_MANAGER_ENABLED_PROPERTY =
+ "ro.storage_manager.enabled";
private static Signature[] sSystemSignature;
private static String sPermissionControllerPackageName;
@@ -373,8 +373,7 @@
public static boolean isStorageManagerEnabled(Context context) {
boolean isDefaultOn;
try {
- // Turn off by default if the opt-in was shown.
- isDefaultOn = !SystemProperties.getBoolean(STORAGE_MANAGER_SHOW_OPT_IN_PROPERTY, true);
+ isDefaultOn = SystemProperties.getBoolean(STORAGE_MANAGER_ENABLED_PROPERTY, false);
} catch (Resources.NotFoundException e) {
isDefaultOn = false;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
index 12b8efb..4ab9a9a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
@@ -55,6 +55,12 @@
"com.android.settings.category.ia.privacy";
public static final String CATEGORY_ENTERPRISE_PRIVACY =
"com.android.settings.category.ia.enterprise_privacy";
+ public static final String CATEGORY_ABOUT_LEGAL =
+ "com.android.settings.category.ia.about_legal";
+ public static final String CATEGORY_MY_DEVICE_INFO =
+ "com.android.settings.category.ia.my_device_info";
+ public static final String CATEGORY_BATTERY_SAVER_SETTINGS =
+ "com.android.settings.category.ia.battery_saver_settings";
public static final Map<String, String> KEY_COMPAT_MAP;
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index af5a24f..27dc628 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -41,7 +41,9 @@
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiNetworkScoreCache;
+import android.net.wifi.hotspot2.OsuProvider;
import android.net.wifi.hotspot2.PasspointConfiguration;
+import android.net.wifi.hotspot2.ProvisioningCallback;
import android.os.Bundle;
import android.os.Parcelable;
import android.os.RemoteException;
@@ -182,6 +184,10 @@
public static final int UNREACHABLE_RSSI = Integer.MIN_VALUE;
+ public static final String KEY_PREFIX_AP = "AP:";
+ public static final String KEY_PREFIX_FQDN = "FQDN:";
+ public static final String KEY_PREFIX_OSU = "OSU:";
+
private final Context mContext;
private String ssid;
@@ -204,9 +210,6 @@
@Speed private int mSpeed = Speed.NONE;
private boolean mIsScoredNetworkMetered = false;
- // used to co-relate internal vs returned accesspoint.
- int mId;
-
/**
* Information associated with the {@link PasspointConfiguration}. Only maintaining
* the relevant info to preserve spaces.
@@ -215,6 +218,13 @@
private String mProviderFriendlyName;
private boolean mIsCarrierAp = false;
+
+ private OsuProvider mOsuProvider;
+
+ private String mOsuStatus;
+ private String mOsuFailure;
+ private boolean mOsuProvisioningComplete = false;
+
/**
* The EAP type {@link WifiEnterpriseConfig.Eap} associated with this AP if it is a carrier AP.
*/
@@ -280,14 +290,18 @@
// Calculate required fields
updateKey();
updateRssi();
-
- mId = sLastId.incrementAndGet();
}
+ /**
+ * Creates an AccessPoint with only a WifiConfiguration. This is used for the saved networks
+ * page.
+ *
+ * Passpoint Credential AccessPoints should be created with this.
+ * Make sure to call setScanResults after constructing with this.
+ */
public AccessPoint(Context context, WifiConfiguration config) {
mContext = context;
loadConfig(config);
- mId = sLastId.incrementAndGet();
}
/**
@@ -298,7 +312,17 @@
mContext = context;
mFqdn = config.getHomeSp().getFqdn();
mProviderFriendlyName = config.getHomeSp().getFriendlyName();
- mId = sLastId.incrementAndGet();
+ }
+
+ /**
+ * Initialize an AccessPoint object for a Passpoint OSU Provider.
+ * Make sure to call setScanResults after constructing with this.
+ */
+ public AccessPoint(Context context, OsuProvider provider) {
+ mContext = context;
+ mOsuProvider = provider;
+ ssid = provider.getFriendlyName();
+ updateKey();
}
AccessPoint(Context context, Collection<ScanResult> results) {
@@ -324,8 +348,6 @@
mIsCarrierAp = firstResult.isCarrierAp;
mCarrierApEapType = firstResult.carrierApEapType;
mCarrierName = firstResult.carrierName;
-
- mId = sLastId.incrementAndGet();
}
@VisibleForTesting void loadConfig(WifiConfiguration config) {
@@ -340,19 +362,13 @@
/** Updates {@link #mKey} and should only called upon object creation/initialization. */
private void updateKey() {
// TODO(sghuman): Consolidate Key logic on ScanResultMatchInfo
-
- StringBuilder builder = new StringBuilder();
-
if (isPasspoint()) {
- builder.append(mConfig.FQDN);
- } else if (TextUtils.isEmpty(getSsidStr())) {
- builder.append(getBssid());
- } else {
- builder.append(getSsidStr());
+ mKey = getKey(mConfig);
+ } else if (isOsuProvider()) {
+ mKey = getKey(mOsuProvider);
+ } else { // Non-Passpoint AP
+ mKey = getKey(getSsidStr(), getBssid(), getSecurity());
}
-
- builder.append(',').append(getSecurity());
- mKey = builder.toString();
}
/**
@@ -396,8 +412,8 @@
return difference;
}
- // Sort by ssid.
- difference = getSsidStr().compareToIgnoreCase(other.getSsidStr());
+ // Sort by title.
+ difference = getTitle().compareToIgnoreCase(other.getTitle());
if (difference != 0) {
return difference;
}
@@ -593,30 +609,46 @@
}
public static String getKey(ScanResult result) {
- StringBuilder builder = new StringBuilder();
-
- if (TextUtils.isEmpty(result.SSID)) {
- builder.append(result.BSSID);
- } else {
- builder.append(result.SSID);
- }
-
- builder.append(',').append(getSecurity(result));
- return builder.toString();
+ return getKey(result.SSID, result.BSSID, getSecurity(result));
}
+ /**
+ * Returns the AccessPoint key for a WifiConfiguration.
+ * This will return a special Passpoint key if the config is for Passpoint.
+ */
public static String getKey(WifiConfiguration config) {
- StringBuilder builder = new StringBuilder();
-
if (config.isPasspoint()) {
- builder.append(config.FQDN);
- } else if (TextUtils.isEmpty(config.SSID)) {
- builder.append(config.BSSID);
+ return new StringBuilder()
+ .append(KEY_PREFIX_FQDN)
+ .append(config.FQDN).toString();
} else {
- builder.append(removeDoubleQuotes(config.SSID));
+ return getKey(config.SSID, config.BSSID, getSecurity(config));
}
+ }
- builder.append(',').append(getSecurity(config));
+ /**
+ * Returns the AccessPoint key corresponding to the OsuProvider.
+ */
+ public static String getKey(OsuProvider provider) {
+ return new StringBuilder()
+ .append(KEY_PREFIX_OSU)
+ .append(provider.getFriendlyName())
+ .append(',')
+ .append(provider.getServerUri()).toString();
+ }
+
+ /**
+ * Returns the AccessPoint key for a normal non-Passpoint network by ssid/bssid and security.
+ */
+ private static String getKey(String ssid, String bssid, int security) {
+ StringBuilder builder = new StringBuilder();
+ builder.append(KEY_PREFIX_AP);
+ if (TextUtils.isEmpty(ssid)) {
+ builder.append(bssid);
+ } else {
+ builder.append(ssid);
+ }
+ builder.append(',').append(security);
return builder.toString();
}
@@ -839,91 +871,105 @@
public String getTitle() {
if (isPasspoint()) {
return mConfig.providerFriendlyName;
+ } else if (isOsuProvider()) {
+ return mOsuProvider.getFriendlyName();
} else {
return getSsidStr();
}
}
public String getSummary() {
- return getSettingsSummary(mConfig);
+ return getSettingsSummary();
}
public String getSettingsSummary() {
- return getSettingsSummary(mConfig);
- }
-
- private String getSettingsSummary(WifiConfiguration config) {
// Update to new summary
StringBuilder summary = new StringBuilder();
- if (isActive() && config != null && config.isPasspoint()) {
- // This is the active connection on passpoint
- summary.append(getSummary(mContext, getDetailedState(),
- false, config.providerFriendlyName));
- } else if (isActive() && config != null && getDetailedState() == DetailedState.CONNECTED
- && mIsCarrierAp) {
- summary.append(String.format(mContext.getString(R.string.connected_via_carrier), mCarrierName));
- } else if (isActive()) {
- // This is the active connection on non-passpoint network
- summary.append(getSummary(mContext, getDetailedState(),
- mInfo != null && mInfo.isEphemeral()));
- } else if (config != null && config.isPasspoint()
- && config.getNetworkSelectionStatus().isNetworkEnabled()) {
- String format = mContext.getString(R.string.available_via_passpoint);
- summary.append(String.format(format, config.providerFriendlyName));
- } else if (config != null && config.hasNoInternetAccess()) {
- int messageID = config.getNetworkSelectionStatus().isNetworkPermanentlyDisabled()
- ? R.string.wifi_no_internet_no_reconnect
- : R.string.wifi_no_internet;
- summary.append(mContext.getString(messageID));
- } else if (config != null && !config.getNetworkSelectionStatus().isNetworkEnabled()) {
- WifiConfiguration.NetworkSelectionStatus networkStatus =
- config.getNetworkSelectionStatus();
- switch (networkStatus.getNetworkSelectionDisableReason()) {
- case WifiConfiguration.NetworkSelectionStatus.DISABLED_AUTHENTICATION_FAILURE:
- summary.append(mContext.getString(R.string.wifi_disabled_password_failure));
- break;
- case WifiConfiguration.NetworkSelectionStatus.DISABLED_BY_WRONG_PASSWORD:
- summary.append(mContext.getString(R.string.wifi_check_password_try_again));
- break;
- case WifiConfiguration.NetworkSelectionStatus.DISABLED_DHCP_FAILURE:
- case WifiConfiguration.NetworkSelectionStatus.DISABLED_DNS_FAILURE:
- summary.append(mContext.getString(R.string.wifi_disabled_network_failure));
- break;
- case WifiConfiguration.NetworkSelectionStatus.DISABLED_ASSOCIATION_REJECTION:
- summary.append(mContext.getString(R.string.wifi_disabled_generic));
- break;
+ if (isOsuProvider()) {
+ if (mOsuProvisioningComplete) {
+ summary.append(mContext.getString(R.string.osu_provisioning_complete));
+ } else if (mOsuFailure != null) {
+ summary.append(mOsuFailure);
+ } else if (mOsuStatus != null) {
+ summary.append(mOsuStatus);
+ } else {
+ summary.append(mContext.getString(R.string.tap_to_set_up));
}
- } else if (config != null && config.getNetworkSelectionStatus().isNotRecommended()) {
- summary.append(mContext.getString(R.string.wifi_disabled_by_recommendation_provider));
- } else if (mIsCarrierAp) {
- summary.append(String.format(mContext.getString(R.string.available_via_carrier), mCarrierName));
- } else if (!isReachable()) { // Wifi out of range
- summary.append(mContext.getString(R.string.wifi_not_in_range));
- } else { // In range, not disabled.
- if (config != null) { // Is saved network
- // Last attempt to connect to this failed. Show reason why
- switch (config.recentFailure.getAssociationStatus()) {
- case WifiConfiguration.RecentFailure.STATUS_AP_UNABLE_TO_HANDLE_NEW_STA:
- summary.append(mContext.getString(
- R.string.wifi_ap_unable_to_handle_new_sta));
+ } else if (isActive()) {
+ if (isPasspoint()) {
+ // This is the active connection on passpoint
+ summary.append(getSummary(mContext, ssid, getDetailedState(),
+ false, mConfig.providerFriendlyName));
+ } else if (mConfig != null && getDetailedState() == DetailedState.CONNECTED
+ && mIsCarrierAp) {
+ // This is the active connection on a carrier AP
+ summary.append(String.format(mContext.getString(R.string.connected_via_carrier),
+ mCarrierName));
+ } else {
+ // This is the active connection on non-passpoint network
+ summary.append(getSummary(mContext, getDetailedState(),
+ mInfo != null && mInfo.isEphemeral()));
+ }
+ } else { // not active
+ if (mConfig != null && mConfig.hasNoInternetAccess()) {
+ int messageID = mConfig.getNetworkSelectionStatus().isNetworkPermanentlyDisabled()
+ ? R.string.wifi_no_internet_no_reconnect
+ : R.string.wifi_no_internet;
+ summary.append(mContext.getString(messageID));
+ } else if (mConfig != null && !mConfig.getNetworkSelectionStatus().isNetworkEnabled()) {
+ WifiConfiguration.NetworkSelectionStatus networkStatus =
+ mConfig.getNetworkSelectionStatus();
+ switch (networkStatus.getNetworkSelectionDisableReason()) {
+ case WifiConfiguration.NetworkSelectionStatus.DISABLED_AUTHENTICATION_FAILURE:
+ summary.append(mContext.getString(R.string.wifi_disabled_password_failure));
break;
- default:
- // "Saved"
- summary.append(mContext.getString(R.string.wifi_remembered));
+ case WifiConfiguration.NetworkSelectionStatus.DISABLED_BY_WRONG_PASSWORD:
+ summary.append(mContext.getString(R.string.wifi_check_password_try_again));
break;
+ case WifiConfiguration.NetworkSelectionStatus.DISABLED_DHCP_FAILURE:
+ case WifiConfiguration.NetworkSelectionStatus.DISABLED_DNS_FAILURE:
+ summary.append(mContext.getString(R.string.wifi_disabled_network_failure));
+ break;
+ case WifiConfiguration.NetworkSelectionStatus.DISABLED_ASSOCIATION_REJECTION:
+ summary.append(mContext.getString(R.string.wifi_disabled_generic));
+ break;
+ }
+ } else if (mConfig != null && mConfig.getNetworkSelectionStatus().isNotRecommended()) {
+ summary.append(mContext.getString(
+ R.string.wifi_disabled_by_recommendation_provider));
+ } else if (mIsCarrierAp) {
+ summary.append(String.format(mContext.getString(
+ R.string.available_via_carrier), mCarrierName));
+ } else if (!isReachable()) { // Wifi out of range
+ summary.append(mContext.getString(R.string.wifi_not_in_range));
+ } else { // In range, not disabled.
+ if (mConfig != null) { // Is saved network
+ // Last attempt to connect to this failed. Show reason why
+ switch (mConfig.recentFailure.getAssociationStatus()) {
+ case WifiConfiguration.RecentFailure.STATUS_AP_UNABLE_TO_HANDLE_NEW_STA:
+ summary.append(mContext.getString(
+ R.string.wifi_ap_unable_to_handle_new_sta));
+ break;
+ default:
+ // "Saved"
+ summary.append(mContext.getString(R.string.wifi_remembered));
+ break;
+ }
}
}
}
+
+
if (isVerboseLoggingEnabled()) {
- summary.append(WifiUtils.buildLoggingSummary(this, config));
+ summary.append(WifiUtils.buildLoggingSummary(this, mConfig));
}
- if (config != null && (WifiUtils.isMeteredOverridden(config) || config.meteredHint)) {
+ if (mConfig != null && (WifiUtils.isMeteredOverridden(mConfig) || mConfig.meteredHint)) {
return mContext.getResources().getString(
R.string.preference_summary_default_combination,
- WifiUtils.getMeteredLabel(mContext, config),
+ WifiUtils.getMeteredLabel(mContext, mConfig),
summary.toString());
}
@@ -976,11 +1022,33 @@
}
/**
+ * Return true if this AccessPoint represents an OSU Provider.
+ */
+ public boolean isOsuProvider() {
+ return mOsuProvider != null;
+ }
+
+ /**
+ * Starts the OSU Provisioning flow.
+ */
+ public void startOsuProvisioning() {
+ mContext.getSystemService(WifiManager.class).startSubscriptionProvisioning(
+ mOsuProvider,
+ new AccessPointProvisioningCallback(),
+ ThreadUtils.getUiThreadHandler()
+ );
+ }
+
+ /**
* Return whether the given {@link WifiInfo} is for this access point.
* If the current AP does not have a network Id then the config is used to
* match based on SSID and security.
*/
private boolean isInfoForThisAccessPoint(WifiConfiguration config, WifiInfo info) {
+ if (info.isOsuAp()) {
+ return (mOsuStatus != null);
+ }
+
if (isPasspoint() == false && networkId != WifiConfiguration.INVALID_NETWORK_ID) {
return networkId == info.getNetworkId();
} else if (config != null) {
@@ -1065,8 +1133,8 @@
void setScanResults(Collection<ScanResult> scanResults) {
// Validate scan results are for current AP only by matching SSID/BSSID
- // Passpoint R1 networks are not bound to a specific SSID/BSSID, so skip this for passpoint.
- if (!isPasspoint()) {
+ // Passpoint networks are not bound to a specific SSID/BSSID, so skip this for passpoint.
+ if (!isPasspoint() && !isOsuProvider()) {
String key = getKey();
for (ScanResult result : scanResults) {
String scanResultKey = AccessPoint.getKey(result);
@@ -1119,7 +1187,17 @@
}
}
- /** Attempt to update the AccessPoint and return true if an update occurred. */
+ /**
+ * Attempt to update the AccessPoint with the current connection info.
+ * This is used to set an AccessPoint to the active one if the connection info matches, or
+ * conversely to set an AccessPoint to inactive if the connection info does not match. The RSSI
+ * is also updated upon a match. Listeners will be notified if an update occurred.
+ *
+ * This is called in {@link WifiTracker#updateAccessPoints} as well as in callbacks for handling
+ * NETWORK_STATE_CHANGED_ACTION, RSSI_CHANGED_ACTION, and onCapabilitiesChanged in WifiTracker.
+ *
+ * Returns true if an update occurred.
+ */
public boolean update(
@Nullable WifiConfiguration config, WifiInfo info, NetworkInfo networkInfo) {
@@ -1246,11 +1324,11 @@
public static String getSummary(Context context, String ssid, DetailedState state,
boolean isEphemeral, String passpointProvider) {
- if (state == DetailedState.CONNECTED && ssid == null) {
- if (TextUtils.isEmpty(passpointProvider) == false) {
+ if (state == DetailedState.CONNECTED) {
+ if (!TextUtils.isEmpty(passpointProvider)) {
// Special case for connected + passpoint networks.
- String format = context.getString(R.string.connected_via_passpoint);
- return String.format(format, passpointProvider);
+ String format = context.getString(R.string.ssid_by_passpoint_provider);
+ return String.format(format, ssid, passpointProvider);
} else if (isEphemeral) {
// Special case for connected + ephemeral networks.
final NetworkScoreManager networkScoreManager = context.getSystemService(
@@ -1443,4 +1521,166 @@
private static boolean isVerboseLoggingEnabled() {
return WifiTracker.sVerboseLogging || Log.isLoggable(TAG, Log.VERBOSE);
}
+
+ /**
+ * Callbacks relaying changes to the OSU provisioning status started in startOsuProvisioning().
+ *
+ * All methods are invoked on the Main Thread
+ */
+ private class AccessPointProvisioningCallback extends ProvisioningCallback {
+ // TODO: Remove logs and implement summary changing logic for these provisioning callbacks.
+ @Override
+ @MainThread public void onProvisioningFailure(int status) {
+ switch (status) {
+ case OSU_FAILURE_AP_CONNECTION:
+ mOsuFailure = mContext.getString(R.string.osu_failure_ap_connection);
+ break;
+ case OSU_FAILURE_SERVER_URL_INVALID:
+ mOsuFailure = mContext.getString(R.string.osu_failure_server_url_invalid);
+ break;
+ case OSU_FAILURE_SERVER_CONNECTION:
+ mOsuFailure = mContext.getString(R.string.osu_failure_server_connection);
+ break;
+ case OSU_FAILURE_SERVER_VALIDATION:
+ mOsuFailure = mContext.getString(R.string.osu_failure_server_validation);
+ break;
+ case OSU_FAILURE_SERVICE_PROVIDER_VERIFICATION:
+ mOsuFailure = mContext.getString(
+ R.string.osu_failure_service_provider_verification);
+ break;
+ case OSU_FAILURE_PROVISIONING_ABORTED:
+ mOsuFailure = mContext.getString(R.string.osu_failure_provisioning_aborted);
+ break;
+ case OSU_FAILURE_PROVISIONING_NOT_AVAILABLE:
+ mOsuFailure = mContext.getString(
+ R.string.osu_failure_provisioning_not_available);
+ break;
+ case OSU_FAILURE_INVALID_SERVER_URL:
+ mOsuFailure = mContext.getString(R.string.osu_failure_invalid_server_url);
+ break;
+ case OSU_FAILURE_UNEXPECTED_COMMAND_TYPE:
+ mOsuFailure = mContext.getString(R.string.osu_failure_unexpected_command_type);
+ break;
+ case OSU_FAILURE_UNEXPECTED_SOAP_MESSAGE_TYPE:
+ mOsuFailure = mContext.getString(
+ R.string.osu_failure_unexpected_soap_message_type);
+ break;
+ case OSU_FAILURE_SOAP_MESSAGE_EXCHANGE:
+ mOsuFailure = mContext.getString(R.string.osu_failure_soap_message_exchange);
+ break;
+ case OSU_FAILURE_START_REDIRECT_LISTENER:
+ mOsuFailure = mContext.getString(R.string.osu_failure_start_redirect_listener);
+ break;
+ case OSU_FAILURE_TIMED_OUT_REDIRECT_LISTENER:
+ mOsuFailure = mContext.getString(
+ R.string.osu_failure_timed_out_redirect_listener);
+ break;
+ case OSU_FAILURE_NO_OSU_ACTIVITY_FOUND:
+ mOsuFailure = mContext.getString(R.string.osu_failure_no_osu_activity_found);
+ break;
+ case OSU_FAILURE_UNEXPECTED_SOAP_MESSAGE_STATUS:
+ mOsuFailure = mContext.getString(
+ R.string.osu_failure_unexpected_soap_message_status);
+ break;
+ case OSU_FAILURE_NO_PPS_MO:
+ mOsuFailure = mContext.getString(
+ R.string.osu_failure_no_pps_mo);
+ break;
+ case OSU_FAILURE_NO_AAA_SERVER_TRUST_ROOT_NODE:
+ mOsuFailure = mContext.getString(
+ R.string.osu_failure_no_aaa_server_trust_root_node);
+ break;
+ case OSU_FAILURE_NO_REMEDIATION_SERVER_TRUST_ROOT_NODE:
+ mOsuFailure = mContext.getString(
+ R.string.osu_failure_no_remediation_server_trust_root_node);
+ break;
+ case OSU_FAILURE_NO_POLICY_SERVER_TRUST_ROOT_NODE:
+ mOsuFailure = mContext.getString(
+ R.string.osu_failure_no_policy_server_trust_root_node);
+ break;
+ case OSU_FAILURE_RETRIEVE_TRUST_ROOT_CERTIFICATES:
+ mOsuFailure = mContext.getString(
+ R.string.osu_failure_retrieve_trust_root_certificates);
+ break;
+ case OSU_FAILURE_NO_AAA_TRUST_ROOT_CERTIFICATE:
+ mOsuFailure = mContext.getString(
+ R.string.osu_failure_no_aaa_trust_root_certificate);
+ break;
+ case OSU_FAILURE_ADD_PASSPOINT_CONFIGURATION:
+ mOsuFailure = mContext.getString(
+ R.string.osu_failure_add_passpoint_configuration);
+ break;
+ case OSU_FAILURE_OSU_PROVIDER_NOT_FOUND:
+ mOsuFailure = mContext.getString(R.string.osu_failure_osu_provider_not_found);
+ break;
+ }
+ mOsuStatus = null;
+ mOsuProvisioningComplete = false;
+ ThreadUtils.postOnMainThread(() -> {
+ if (mAccessPointListener != null) {
+ mAccessPointListener.onAccessPointChanged(AccessPoint.this);
+ }
+ });
+ }
+
+ @Override
+ @MainThread public void onProvisioningStatus(int status) {
+ switch (status) {
+ case OSU_STATUS_AP_CONNECTING:
+ mOsuStatus = mContext.getString(R.string.osu_status_ap_connecting);
+ break;
+ case OSU_STATUS_AP_CONNECTED:
+ mOsuStatus = mContext.getString(R.string.osu_status_ap_connected);
+ break;
+ case OSU_STATUS_SERVER_CONNECTING:
+ mOsuStatus = mContext.getString(R.string.osu_status_server_connecting);
+ break;
+ case OSU_STATUS_SERVER_VALIDATED:
+ mOsuStatus = mContext.getString(R.string.osu_status_server_validated);
+ break;
+ case OSU_STATUS_SERVER_CONNECTED:
+ mOsuStatus = mContext.getString(R.string.osu_status_server_connected);
+ break;
+ case OSU_STATUS_INIT_SOAP_EXCHANGE:
+ mOsuStatus = mContext.getString(R.string.osu_status_init_soap_exchange);
+ break;
+ case OSU_STATUS_WAITING_FOR_REDIRECT_RESPONSE:
+ mOsuStatus = mContext.getString(
+ R.string.osu_status_waiting_for_redirect_response);
+ break;
+ case OSU_STATUS_REDIRECT_RESPONSE_RECEIVED:
+ mOsuStatus = mContext.getString(R.string.osu_status_redirect_response_received);
+ break;
+ case OSU_STATUS_SECOND_SOAP_EXCHANGE:
+ mOsuStatus = mContext.getString(R.string.osu_status_second_soap_exchange);
+ break;
+ case OSU_STATUS_THIRD_SOAP_EXCHANGE:
+ mOsuStatus = mContext.getString(R.string.osu_status_third_soap_exchange);
+ break;
+ case OSU_STATUS_RETRIEVING_TRUST_ROOT_CERTS:
+ mOsuStatus = mContext.getString(
+ R.string.osu_status_retrieving_trust_root_certs);
+ break;
+ }
+ mOsuFailure = null;
+ mOsuProvisioningComplete = false;
+ ThreadUtils.postOnMainThread(() -> {
+ if (mAccessPointListener != null) {
+ mAccessPointListener.onAccessPointChanged(AccessPoint.this);
+ }
+ });
+ }
+
+ @Override
+ @MainThread public void onProvisioningComplete() {
+ mOsuProvisioningComplete = true;
+ mOsuFailure = null;
+ mOsuStatus = null;
+ ThreadUtils.postOnMainThread(() -> {
+ if (mAccessPointListener != null) {
+ mAccessPointListener.onAccessPointChanged(AccessPoint.this);
+ }
+ });
+ }
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 79a7240..b9a5f23 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -35,6 +35,7 @@
import android.net.wifi.WifiManager;
import android.net.wifi.WifiNetworkScoreCache;
import android.net.wifi.WifiNetworkScoreCache.CacheListener;
+import android.net.wifi.hotspot2.OsuProvider;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
@@ -67,6 +68,7 @@
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
+import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -584,7 +586,6 @@
Map<Integer, List<ScanResult>>> pairing : passpointConfigsAndScans) {
WifiConfiguration config = pairing.first;
- // TODO: Prioritize home networks before roaming networks
List<ScanResult> scanResults = new ArrayList<>();
List<ScanResult> homeScans =
@@ -599,8 +600,12 @@
roamingScans = new ArrayList<>();
}
- scanResults.addAll(homeScans);
- scanResults.addAll(roamingScans);
+ // TODO(b/118705403): Differentiate home network vs roaming network for summary info
+ if (!homeScans.isEmpty()) {
+ scanResults.addAll(homeScans);
+ } else {
+ scanResults.addAll(roamingScans);
+ }
if (seenFQDNs.add(config.FQDN)) {
int bestRssi = Integer.MIN_VALUE;
@@ -611,13 +616,30 @@
}
}
- AccessPoint accessPoint = new AccessPoint(mContext, config);
- accessPoint.setScanResults(scanResults);
+ AccessPoint accessPoint =
+ getCachedOrCreatePasspoint(scanResults, cachedAccessPoints, config);
accessPoint.update(connectionConfig, mLastInfo, mLastNetworkInfo);
accessPoints.add(accessPoint);
}
}
+ // Add Passpoint OSU Provider AccessPoints
+ Map<OsuProvider, List<ScanResult>> providersAndScans =
+ mWifiManager.getMatchingOsuProviders(cachedScanResults);
+ Set<OsuProvider> alreadyProvisioned = mWifiManager
+ .getMatchingPasspointConfigsForOsuProviders(
+ providersAndScans.keySet()).keySet();
+ for (OsuProvider provider : providersAndScans.keySet()) {
+ if (!alreadyProvisioned.contains(provider)) {
+ AccessPoint accessPointOsu =
+ getCachedOrCreateOsu(providersAndScans.get(provider),
+ cachedAccessPoints, provider);
+ accessPointOsu.update(connectionConfig, mLastInfo, mLastNetworkInfo);
+ accessPoints.add(accessPointOsu);
+ }
+ }
+
+
// If there were no scan results, create an AP for the currently connected network (if
// it exists).
if (accessPoints.isEmpty() && connectionConfig != null) {
@@ -667,16 +689,49 @@
AccessPoint getCachedOrCreate(
List<ScanResult> scanResults,
List<AccessPoint> cache) {
- final int N = cache.size();
- for (int i = 0; i < N; i++) {
- if (cache.get(i).getKey().equals(AccessPoint.getKey(scanResults.get(0)))) {
- AccessPoint ret = cache.remove(i);
- ret.setScanResults(scanResults);
- return ret;
+ AccessPoint accessPoint = getCachedByKey(cache, AccessPoint.getKey(scanResults.get(0)));
+ if (accessPoint == null) {
+ accessPoint = new AccessPoint(mContext, scanResults);
+ } else {
+ accessPoint.setScanResults(scanResults);
+ }
+ return accessPoint;
+ }
+
+ private AccessPoint getCachedOrCreatePasspoint(
+ List<ScanResult> scanResults,
+ List<AccessPoint> cache,
+ WifiConfiguration config) {
+ AccessPoint accessPoint = getCachedByKey(cache, AccessPoint.getKey(config));
+ if (accessPoint == null) {
+ accessPoint = new AccessPoint(mContext, config);
+ }
+ accessPoint.setScanResults(scanResults);
+ return accessPoint;
+ }
+
+ private AccessPoint getCachedOrCreateOsu(
+ List<ScanResult> scanResults,
+ List<AccessPoint> cache,
+ OsuProvider provider) {
+ AccessPoint accessPoint = getCachedByKey(cache, AccessPoint.getKey(provider));
+ if (accessPoint == null) {
+ accessPoint = new AccessPoint(mContext, provider);
+ }
+ accessPoint.setScanResults(scanResults);
+ return accessPoint;
+ }
+
+ private AccessPoint getCachedByKey(List<AccessPoint> cache, String key) {
+ ListIterator<AccessPoint> lit = cache.listIterator();
+ while (lit.hasNext()) {
+ AccessPoint currentAccessPoint = lit.next();
+ if (currentAccessPoint.getKey().equals(key)) {
+ lit.remove();
+ return currentAccessPoint;
}
}
- final AccessPoint accessPoint = new AccessPoint(mContext, scanResults);
- return accessPoint;
+ return null;
}
private void updateNetworkInfo(NetworkInfo networkInfo) {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
index 86f0438..92ebe44 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
@@ -17,7 +17,7 @@
import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
-import static com.android.settingslib.Utils.STORAGE_MANAGER_SHOW_OPT_IN_PROPERTY;
+import static com.android.settingslib.Utils.STORAGE_MANAGER_ENABLED_PROPERTY;
import static com.google.common.truth.Truth.assertThat;
@@ -159,7 +159,7 @@
@Test
public void testIsStorageManagerEnabled_UsesSystemProperties() {
- SystemProperties.set(STORAGE_MANAGER_SHOW_OPT_IN_PROPERTY, "false");
+ SystemProperties.set(STORAGE_MANAGER_ENABLED_PROPERTY, "true");
assertThat(Utils.isStorageManagerEnabled(mContext)).isTrue();
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index bcf37ff..e843eb4 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -705,14 +705,17 @@
Settings.Global.GPU_DEBUG_LAYERS_GLES,
GlobalSettingsProto.Gpu.DEBUG_LAYERS_GLES);
dumpSetting(s, p,
+ Settings.Global.GUP_DEV_ALL_APPS,
+ GlobalSettingsProto.Gpu.GUP_DEV_ALL_APPS);
+ dumpSetting(s, p,
Settings.Global.GUP_DEV_OPT_IN_APPS,
GlobalSettingsProto.Gpu.GUP_DEV_OPT_IN_APPS);
dumpSetting(s, p,
Settings.Global.GUP_DEV_OPT_OUT_APPS,
GlobalSettingsProto.Gpu.GUP_DEV_OPT_OUT_APPS);
dumpSetting(s, p,
- Settings.Global.GUP_BLACK_LIST,
- GlobalSettingsProto.Gpu.GUP_BLACK_LIST);
+ Settings.Global.GUP_BLACKLIST,
+ GlobalSettingsProto.Gpu.GUP_BLACKLIST);
p.end(gpuToken);
final long hdmiToken = p.start(GlobalSettingsProto.HDMI);
@@ -1879,6 +1882,9 @@
dumpSetting(s, p,
Settings.Secure.DOZE_DOUBLE_TAP_GESTURE,
SecureSettingsProto.Doze.PULSE_ON_DOUBLE_TAP);
+ dumpSetting(s, p,
+ Settings.Secure.DOZE_TAP_SCREEN_GESTURE,
+ SecureSettingsProto.Doze.PULSE_ON_TAP);
p.end(dozeToken);
dumpSetting(s, p,
@@ -2363,6 +2369,14 @@
SecureSettingsProto.Zen.SETTINGS_SUGGESTION_VIEWED);
p.end(zenToken);
+ dumpSetting(s, p,
+ Settings.Secure.SKIP_GESTURE,
+ SecureSettingsProto.SKIP_GESTURE_ENABLED);
+
+ dumpSetting(s, p,
+ Settings.Secure.SILENCE_GESTURE,
+ SecureSettingsProto.SILENCE_GESTURE_ENABLED);
+
// Please insert new settings using the same order as in SecureSettingsProto.
p.end(token);
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index afb9781..2d7471d 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -1953,8 +1953,7 @@
@Override
public void onProgress(int progress) throws RemoteException {
- // TODO(b/111441001): change max argument?
- updateProgressInfo(progress, CAPPED_MAX);
+ updateProgressInfo(progress, 100 /* progress is already a percentage; so max = 100 */);
}
@Override
diff --git a/packages/SystemUI/res-keyguard/drawable/bubble_hour_hand.xml b/packages/SystemUI/res-keyguard/drawable/bubble_hour_hand.xml
new file mode 100644
index 0000000..d3c3a51
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/bubble_hour_hand.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="200dp"
+ android:width="200dp"
+ android:viewportHeight="100"
+ android:viewportWidth="100">
+ <path
+ android:fillColor="#000000"
+ android:pathData="M50.082,14.199m-13.985,0a13.985,13.985 0,1 1,27.97 0a13.985,13.985 0,1 1,-27.97 0"/>
+</vector>
diff --git a/packages/SystemUI/res-keyguard/drawable/bubble_minute_hand.xml b/packages/SystemUI/res-keyguard/drawable/bubble_minute_hand.xml
new file mode 100644
index 0000000..a4417fb
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/bubble_minute_hand.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="200dp"
+ android:width="200dp"
+ android:viewportHeight="100"
+ android:viewportWidth="100" >
+ <path
+ android:fillColor="#000000"
+ android:pathData="M50.082,0.025L50.082,0.025A13.985,15.63 0,0 1,64.067 15.656L64.067,49.029A13.985,15.63 0,0 1,50.082 64.659L50.082,64.659A13.985,15.63 0,0 1,36.097 49.029L36.097,15.656A13.985,15.63 0,0 1,50.082 0.025z"/>
+</vector>
diff --git a/packages/SystemUI/res-keyguard/layout/bubble_clock.xml b/packages/SystemUI/res-keyguard/layout/bubble_clock.xml
new file mode 100644
index 0000000..0d72657
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/layout/bubble_clock.xml
@@ -0,0 +1,52 @@
+<?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"
+ >
+ <TextClock
+ 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"
+ />
+ <com.android.keyguard.clock.ImageClock
+ android:id="@+id/analog_clock"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ >
+ <ImageView
+ android:id="@+id/minute_hand"
+ android:layout_width="300dp"
+ android:layout_height="300dp"
+ android:src="@drawable/bubble_minute_hand"
+ android:tint="@color/bubbleMinuteHandColor"
+ />
+ <ImageView
+ android:id="@+id/hour_hand"
+ android:layout_width="300dp"
+ android:layout_height="300dp"
+ android:src="@drawable/bubble_hour_hand"
+ android:tint="@color/bubbleHourHandColor"
+ />
+ </com.android.keyguard.clock.ImageClock>
+</com.android.keyguard.clock.ClockLayout>
diff --git a/packages/SystemUI/res-keyguard/layout/digital_clock.xml b/packages/SystemUI/res-keyguard/layout/digital_clock.xml
new file mode 100644
index 0000000..cf4a573
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/layout/digital_clock.xml
@@ -0,0 +1,35 @@
+<?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.
+ -->
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_alignParentTop="true">
+ <TextClock
+ 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" />
+ />
+</FrameLayout>
+
diff --git a/packages/SystemUI/res-keyguard/layout/stretchanalog_clock.xml b/packages/SystemUI/res-keyguard/layout/stretchanalog_clock.xml
new file mode 100644
index 0000000..9033fce
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/layout/stretchanalog_clock.xml
@@ -0,0 +1,37 @@
+<?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"
+ >
+ <TextClock
+ 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"
+ />
+ <com.android.keyguard.clock.StretchAnalogClock
+ android:id="@+id/analog_clock"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ />
+</com.android.keyguard.clock.ClockLayout>
diff --git a/packages/SystemUI/res-keyguard/values/colors.xml b/packages/SystemUI/res-keyguard/values/colors.xml
new file mode 100644
index 0000000..7a849eb
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/values/colors.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>
+ <!-- Default color for hour hand of Bubble clock. -->
+ <color name="bubbleHourHandColor">#C97343</color>
+ <!-- Default color for minute hand of Bubble clock. -->
+ <color name="bubbleMinuteHandColor">#F5C983</color>
+</resources>
diff --git a/packages/SystemUI/res/layout/ongoing_privacy_dialog_item.xml b/packages/SystemUI/res/layout/ongoing_privacy_dialog_item.xml
index ecfbfb4..c8e0845 100644
--- a/packages/SystemUI/res/layout/ongoing_privacy_dialog_item.xml
+++ b/packages/SystemUI/res/layout/ongoing_privacy_dialog_item.xml
@@ -25,12 +25,18 @@
android:focusable="true"
android:layout_gravity="center_vertical">
- <ImageView
- android:id="@+id/app_icon"
+ <FrameLayout
android:layout_height="@dimen/ongoing_appops_dialog_app_icon_size"
android:layout_width="@dimen/ongoing_appops_dialog_app_icon_size"
- android:layout_gravity="start|center_vertical"
- />
+ android:layout_gravity="start|center_vertical">
+
+ <ImageView
+ android:id="@+id/app_icon"
+ android:layout_height="@dimen/ongoing_appops_dialog_app_icon_size"
+ android:layout_width="@dimen/ongoing_appops_dialog_app_icon_size"
+ android:layout_gravity="center"
+ />
+ </FrameLayout>
<TextView
android:id="@+id/app_name"
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index ef16bca..5a00b45 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -952,6 +952,8 @@
<dimen name="ongoing_appops_dialog_icon_margin">8dp</dimen>
<!-- Height and width of Application icons in Ongoing App Ops dialog -->
<dimen name="ongoing_appops_dialog_app_icon_size">32dp</dimen>
+ <!-- Height and width of Plus sign in Ongoing App Ops dialog -->
+ <dimen name="ongoing_appops_dialog_app_plus_size">24dp</dimen>
<!-- Height of line in Ongoing App Ops dialog-->
<dimen name="ongoing_appops_dialog_line_height">48dp</dimen>
<!-- Side margin of title in Ongoing App Ops dialog -->
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java
index 523720d5..1a684a0 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java
@@ -323,7 +323,7 @@
return null;
}
// Create our own ClassLoader so we can use our own code as the parent.
- ClassLoader classLoader = mManager.getClassLoader(info.sourceDir, info.packageName);
+ ClassLoader classLoader = mManager.getClassLoader(info);
Context pluginContext = new PluginContextWrapper(
mContext.createApplicationContext(info, 0), classLoader);
Class<?> pluginClass = Class.forName(cls, true, classLoader);
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
index da143f9..7139708 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
@@ -14,6 +14,7 @@
package com.android.systemui.shared.plugins;
+import android.app.LoadedApk;
import android.app.Notification;
import android.app.Notification.Action;
import android.app.NotificationManager;
@@ -44,15 +45,17 @@
import com.android.systemui.plugins.Plugin;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.annotations.ProvidesInterface;
-import com.android.systemui.shared.plugins.PluginInstanceManager.PluginContextWrapper;
import com.android.systemui.shared.plugins.PluginInstanceManager.PluginInfo;
import dalvik.system.PathClassLoader;
+import java.io.File;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.Thread.UncaughtExceptionHandler;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import java.util.Map;
/**
* @see Plugin
@@ -117,6 +120,7 @@
return mPluginEnabler;
}
+ // TODO(mankoff): This appears to be only called from tests. Remove?
public <T extends Plugin> T getOneShotPlugin(Class<T> cls) {
ProvidesInterface info = cls.getDeclaredAnnotation(ProvidesInterface.class);
if (info == null) {
@@ -282,17 +286,25 @@
}
}
- public ClassLoader getClassLoader(String sourceDir, String pkg) {
- if (!isDebuggable && !mWhitelistedPlugins.contains(pkg)) {
- Log.w(TAG, "Cannot get class loader for non-whitelisted plugin. Src:" + sourceDir +
- ", pkg: " + pkg);
+ /** Returns class loader specific for the given plugin. */
+ public ClassLoader getClassLoader(ApplicationInfo appInfo) {
+ if (!isDebuggable && !mWhitelistedPlugins.contains(appInfo.packageName)) {
+ Log.w(TAG, "Cannot get class loader for non-whitelisted plugin. Src:"
+ + appInfo.sourceDir + ", pkg: " + appInfo.packageName);
return null;
}
- if (mClassLoaders.containsKey(pkg)) {
- return mClassLoaders.get(pkg);
+ if (mClassLoaders.containsKey(appInfo.packageName)) {
+ return mClassLoaders.get(appInfo.packageName);
}
- ClassLoader classLoader = new PathClassLoader(sourceDir, getParentClassLoader());
- mClassLoaders.put(pkg, classLoader);
+
+ List<String> zipPaths = new ArrayList<>();
+ List<String> libPaths = new ArrayList<>();
+ LoadedApk.makePaths(null, true, appInfo, zipPaths, libPaths);
+ ClassLoader classLoader = new PathClassLoader(
+ TextUtils.join(File.pathSeparator, zipPaths),
+ TextUtils.join(File.pathSeparator, libPaths),
+ getParentClassLoader());
+ mClassLoaders.put(appInfo.packageName, classLoader);
return classLoader;
}
@@ -309,11 +321,6 @@
return mParentClassLoader;
}
- public Context getContext(ApplicationInfo info, String pkg) throws NameNotFoundException {
- ClassLoader classLoader = getClassLoader(info.sourceDir, pkg);
- return new PluginContextWrapper(mContext.createApplicationContext(info, 0), classLoader);
- }
-
public <T> boolean dependsOn(Plugin p, Class<T> cls) {
for (int i = 0; i < mPluginMap.size(); i++) {
if (mPluginMap.valueAt(i).dependsOn(p, cls)) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
index 41e9eba..a055950 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
@@ -46,6 +46,7 @@
protected View mEcaView;
protected boolean mEnableHaptics;
private boolean mDismissing;
+ protected boolean mResumed;
private CountDownTimer mCountdownTimer = null;
// To avoid accidental lockout due to events while the device in in the pocket, ignore
@@ -263,6 +264,8 @@
@Override
public void onPause() {
+ mResumed = false;
+
if (mCountdownTimer != null) {
mCountdownTimer.cancel();
mCountdownTimer = null;
@@ -276,6 +279,7 @@
@Override
public void onResume(int reason) {
+ mResumed = true;
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index 3cfd6a9..a8094d20 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -1,9 +1,15 @@
package com.android.keyguard;
+import android.content.ContentResolver;
import android.content.Context;
+import android.database.ContentObserver;
import android.graphics.Paint;
import android.graphics.Paint.Style;
+import android.os.Handler;
+import android.os.Looper;
+import android.provider.Settings;
import android.util.AttributeSet;
+import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
@@ -12,6 +18,8 @@
import androidx.annotation.VisibleForTesting;
+import com.android.keyguard.clock.BubbleClockController;
+import com.android.keyguard.clock.StretchAnalogClockController;
import com.android.systemui.Dependency;
import com.android.systemui.plugins.ClockPlugin;
import com.android.systemui.statusbar.StatusBarState;
@@ -19,13 +27,19 @@
import com.android.systemui.statusbar.policy.ExtensionController;
import com.android.systemui.statusbar.policy.ExtensionController.Extension;
+import java.util.Objects;
import java.util.TimeZone;
import java.util.function.Consumer;
+import java.util.function.Supplier;
/**
* Switch to show plugin clock when plugin is connected, otherwise it will show default clock.
*/
public class KeyguardClockSwitch extends RelativeLayout {
+
+ private LayoutInflater mLayoutInflater;
+
+ private final ContentResolver mContentResolver;
/**
* Optional/alternative clock injected via plugin.
*/
@@ -79,12 +93,25 @@
}
};
+ private final ContentObserver mContentObserver =
+ new ContentObserver(new Handler(Looper.getMainLooper())) {
+ @Override
+ public void onChange(boolean selfChange) {
+ super.onChange(selfChange);
+ if (mClockExtension != null) {
+ mClockExtension.reload();
+ }
+ }
+ };
+
public KeyguardClockSwitch(Context context) {
this(context, null);
}
public KeyguardClockSwitch(Context context, AttributeSet attrs) {
super(context, attrs);
+ mLayoutInflater = LayoutInflater.from(context);
+ mContentResolver = context.getContentResolver();
}
/**
@@ -108,7 +135,28 @@
mClockExtension = Dependency.get(ExtensionController.class).newExtension(ClockPlugin.class)
.withPlugin(ClockPlugin.class)
.withCallback(mClockPluginConsumer)
+ // Using withDefault even though this isn't the default as a workaround.
+ // ExtensionBulider doesn't provide the ability to supply a ClockPlugin
+ // instance based off of the value of a setting. Since multiple "default"
+ // can be provided, using a supplier that changes the settings value.
+ // A null return will cause Extension#reload to look at the next "default"
+ // supplier.
+ .withDefault(
+ new SettingsGattedSupplier(
+ mContentResolver,
+ Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE,
+ BubbleClockController.class.getName(),
+ () -> BubbleClockController.build(mLayoutInflater)))
+ .withDefault(
+ new SettingsGattedSupplier(
+ mContentResolver,
+ Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE,
+ StretchAnalogClockController.class.getName(),
+ () -> StretchAnalogClockController.build(mLayoutInflater)))
.build();
+ mContentResolver.registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE),
+ false, mContentObserver);
Dependency.get(StatusBarStateController.class).addCallback(mStateListener);
}
@@ -116,6 +164,7 @@
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mClockExtension.destroy();
+ mContentResolver.unregisterContentObserver(mContentObserver);
Dependency.get(StatusBarStateController.class).removeCallback(mStateListener);
}
@@ -269,4 +318,44 @@
StatusBarStateController.StateListener getStateListener() {
return mStateListener;
}
+
+ /**
+ * Supplier that only gets an instance when a settings value matches expected value.
+ */
+ private static class SettingsGattedSupplier implements Supplier<ClockPlugin> {
+
+ private final ContentResolver mContentResolver;
+ private final String mKey;
+ private final String mValue;
+ private final Supplier<ClockPlugin> mSupplier;
+
+ /**
+ * Constructs a supplier that changes secure setting key against value.
+ *
+ * @param contentResolver Used to look up settings value.
+ * @param key Settings key.
+ * @param value If the setting matches this values that get supplies a ClockPlugin
+ * instance.
+ * @param supplier Supplier of ClockPlugin instance, only used if the setting
+ * matches value.
+ */
+ SettingsGattedSupplier(ContentResolver contentResolver, String key, String value,
+ Supplier<ClockPlugin> supplier) {
+ mContentResolver = contentResolver;
+ mKey = key;
+ mValue = value;
+ mSupplier = supplier;
+ }
+
+ /**
+ * Returns null if the settings value doesn't match the expected value.
+ *
+ * A null return causes Extension#reload to skip this supplier and move to the next.
+ */
+ @Override
+ public ClockPlugin get() {
+ final String currentValue = Settings.Secure.getString(mContentResolver, mKey);
+ return Objects.equals(currentValue, mValue) ? mSupplier.get() : null;
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
index 41afa9a..3296c10 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
@@ -81,6 +81,11 @@
protected void resetState() {
mSecurityMessageDisplay.setMessage("");
final boolean wasDisabled = mPasswordEntry.isEnabled();
+ // Don't set enabled password entry & showSoftInput when PasswordEntry is invisible or in
+ // pausing stage.
+ if (!mResumed || !mPasswordEntry.isVisibleToUser()) {
+ return;
+ }
setPasswordEntryEnabled(true);
setPasswordEntryInputEnabled(true);
if (wasDisabled) {
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java
new file mode 100644
index 0000000..db6127f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java
@@ -0,0 +1,114 @@
+/*
+ * 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 android.widget.TextClock;
+
+import com.android.keyguard.R;
+import com.android.systemui.plugins.ClockPlugin;
+
+import java.util.TimeZone;
+
+/**
+ * Controller for Bubble clock that can appear on lock screen and AOD.
+ */
+public class BubbleClockController implements ClockPlugin {
+
+ /**
+ * Custom clock shown on AOD screen and behind stack scroller on lock.
+ */
+ private View mView;
+ private TextClock mDigitalClock;
+ private ImageClock mAnalogClock;
+
+ /**
+ * Small clock shown on lock screen above stack scroller.
+ */
+ private View mLockClockContainer;
+ private TextClock mLockClock;
+
+ /**
+ * Controller for transition to dark state.
+ */
+ private CrossFadeDarkController mDarkController;
+
+ private BubbleClockController() { }
+
+ /**
+ * Create a BubbleClockController instance.
+ *
+ * @param layoutInflater Inflater used to inflate custom clock views.
+ */
+ public static BubbleClockController build(LayoutInflater layoutInflater) {
+ BubbleClockController controller = new BubbleClockController();
+ controller.createViews(layoutInflater);
+ return controller;
+ }
+
+ private void createViews(LayoutInflater layoutInflater) {
+ mView = layoutInflater.inflate(R.layout.bubble_clock, null);
+ mDigitalClock = (TextClock) mView.findViewById(R.id.digital_clock);
+ mAnalogClock = (ImageClock) mView.findViewById(R.id.analog_clock);
+
+ mLockClockContainer = layoutInflater.inflate(R.layout.digital_clock, null);
+ mLockClock = (TextClock) mLockClockContainer.findViewById(R.id.lock_screen_clock);
+ mLockClock.setVisibility(View.GONE);
+
+ mDarkController = new CrossFadeDarkController(mDigitalClock, mLockClock);
+ }
+
+ @Override
+ public View getView() {
+ return mLockClockContainer;
+ }
+
+ @Override
+ public View getBigClockView() {
+ return mView;
+ }
+
+ @Override
+ public void setStyle(Style style) {}
+
+ @Override
+ public void setTextColor(int color) {
+ mLockClock.setTextColor(color);
+ mDigitalClock.setTextColor(color);
+ }
+
+ @Override
+ public void dozeTimeTick() {
+ mAnalogClock.onTimeChanged();
+ }
+
+ @Override
+ public void setDarkAmount(float darkAmount) {
+ mDarkController.setDarkAmount(darkAmount);
+ }
+
+ @Override
+ public void onTimeZoneChanged(TimeZone timeZone) {
+ mAnalogClock.onTimeZoneChanged(timeZone);
+ }
+
+ @Override
+ public boolean shouldShowStatusArea() {
+ return false;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java
new file mode 100644
index 0000000..5aa5668
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java
@@ -0,0 +1,93 @@
+/*
+ * 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 static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import com.android.keyguard.R;
+
+/**
+ * Positions clock faces (analog, digital, typographic) and handles pixel shifting
+ * to prevent screen burn-in.
+ */
+public class ClockLayout extends FrameLayout {
+
+ /**
+ * Clock face views.
+ */
+ private View mDigitalClock;
+ private View mAnalogClock;
+
+ /**
+ * Pixel shifting amplitidues used to prevent screen burn-in.
+ */
+ private int mBurnInPreventionOffsetX;
+ private int mBurnInPreventionOffsetY;
+
+ public ClockLayout(Context context) {
+ this(context, null);
+ }
+
+ public ClockLayout(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public ClockLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mDigitalClock = findViewById(R.id.digital_clock);
+ mAnalogClock = findViewById(R.id.analog_clock);
+
+ // Get pixel shifting X, Y amplitudes from resources.
+ Resources resources = getResources();
+ mBurnInPreventionOffsetX = resources.getDimensionPixelSize(
+ R.dimen.burn_in_prevention_offset_x);
+ mBurnInPreventionOffsetY = resources.getDimensionPixelSize(
+ R.dimen.burn_in_prevention_offset_y);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+
+ final float offsetX = getBurnInOffset(mBurnInPreventionOffsetX, true);
+ final float offsetY = getBurnInOffset(mBurnInPreventionOffsetY, false);
+
+ // Put digital clock in two left corner of the screen.
+ if (mDigitalClock != null) {
+ mDigitalClock.setX(0.1f * getWidth() + offsetX);
+ mDigitalClock.setY(0.1f * getHeight() + offsetY);
+ }
+
+ // Put the analog clock in the middle of the screen.
+ if (mAnalogClock != null) {
+ mAnalogClock.setX(Math.max(0f, 0.5f * (getWidth() - mAnalogClock.getWidth()))
+ + offsetX);
+ mAnalogClock.setY(Math.max(0f, 0.5f * (getHeight() - mAnalogClock.getHeight()))
+ + offsetY);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/CrossFadeDarkController.java b/packages/SystemUI/src/com/android/keyguard/clock/CrossFadeDarkController.java
new file mode 100644
index 0000000..3c3f475
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/clock/CrossFadeDarkController.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard.clock;
+
+import android.view.View;
+
+/**
+ * Controls transition to dark state by cross fading between views.
+ */
+final class CrossFadeDarkController {
+
+ private final View mFadeInView;
+ private final View mFadeOutView;
+
+ /**
+ * Creates a new controller that fades between views.
+ *
+ * @param fadeInView View to fade in when transitioning to AOD.
+ * @param fadeOutView View to fade out when transitioning to AOD.
+ */
+ CrossFadeDarkController(View fadeInView, View fadeOutView) {
+ mFadeInView = fadeInView;
+ mFadeOutView = fadeOutView;
+ }
+
+ /**
+ * Sets the amount the system has transitioned to the dark state.
+ *
+ * @param darkAmount Amount of transition to dark state: 1f for AOD and 0f for lock screen.
+ */
+ void setDarkAmount(float darkAmount) {
+ mFadeInView.setAlpha(Math.max(0f, 2f * darkAmount - 1f));
+ if (darkAmount == 0f) {
+ mFadeInView.setVisibility(View.GONE);
+ } else {
+ if (mFadeInView.getVisibility() == View.GONE) {
+ mFadeInView.setVisibility(View.VISIBLE);
+ }
+ }
+ mFadeOutView.setAlpha(Math.max(0f, 1f - 2f * darkAmount));
+ if (darkAmount == 1f) {
+ mFadeOutView.setVisibility(View.GONE);
+ } else {
+ if (mFadeOutView.getVisibility() == View.GONE) {
+ mFadeOutView.setVisibility(View.VISIBLE);
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ImageClock.java b/packages/SystemUI/src/com/android/keyguard/clock/ImageClock.java
new file mode 100644
index 0000000..2c709e0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ImageClock.java
@@ -0,0 +1,94 @@
+/*
+ * 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.text.format.DateFormat;
+import android.util.AttributeSet;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+import com.android.keyguard.R;
+
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.TimeZone;
+
+/**
+ * Clock composed of two images that rotate with the time.
+ *
+ * The images are the clock hands. ImageClock expects two child ImageViews
+ * with ids hour_hand and minute_hand.
+ */
+public class ImageClock extends FrameLayout {
+
+ private ImageView mHourHand;
+ private ImageView mMinuteHand;
+ private Calendar mTime;
+ private String mDescFormat;
+ private TimeZone mTimeZone;
+
+ public ImageClock(Context context) {
+ this(context, null);
+ }
+
+ public ImageClock(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public ImageClock(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ mTime = Calendar.getInstance();
+ mDescFormat = ((SimpleDateFormat) DateFormat.getTimeFormat(context)).toLocalizedPattern();
+ }
+
+ /**
+ * Call when the time changes to update the rotation of the clock hands.
+ */
+ public void onTimeChanged() {
+ mTime.setTimeInMillis(System.currentTimeMillis());
+ final float hourAngle = mTime.get(Calendar.HOUR) * 30f;
+ mHourHand.setRotation(hourAngle);
+ final float minuteAngle = mTime.get(Calendar.MINUTE) * 6f;
+ mMinuteHand.setRotation(minuteAngle);
+ setContentDescription(DateFormat.format(mDescFormat, mTime));
+ invalidate();
+ }
+
+ /**
+ * Call when the time zone has changed to update clock hands.
+ *
+ * @param timeZone The updated time zone that will be used.
+ */
+ public void onTimeZoneChanged(TimeZone timeZone) {
+ mTimeZone = timeZone;
+ mTime.setTimeZone(timeZone);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mHourHand = findViewById(R.id.hour_hand);
+ mMinuteHand = findViewById(R.id.minute_hand);
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ mTime = Calendar.getInstance(mTimeZone != null ? mTimeZone : TimeZone.getDefault());
+ onTimeChanged();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java b/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java
new file mode 100644
index 0000000..91cec863
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java
@@ -0,0 +1,141 @@
+/*
+ * 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.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.view.View;
+
+import java.util.Calendar;
+import java.util.TimeZone;
+
+/**
+ * Analog clock where the minute hand extends off of the screen.
+ */
+public class StretchAnalogClock extends View {
+
+ private static final int DEFAULT_COLOR = Color.parseColor("#F5C983");
+ private static final float HOUR_STROKE_WIDTH = 60f;
+ private static final float MINUTE_STROKE_WIDTH = 20f;
+ private static final float CENTER_GAP_AND_CIRCLE_RADIUS = 80f;
+
+ private final Paint mHourPaint = new Paint();
+ private final Paint mMinutePaint = new Paint();
+ private Calendar mTime;
+ private TimeZone mTimeZone;
+
+ public StretchAnalogClock(Context context) {
+ this(context, null);
+ }
+
+ public StretchAnalogClock(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public StretchAnalogClock(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public StretchAnalogClock(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ init();
+ }
+
+ /**
+ * Call when the time changes to update the clock hands.
+ */
+ public void onTimeChanged() {
+ mTime.setTimeInMillis(System.currentTimeMillis());
+ invalidate();
+ }
+
+ /**
+ * Call when the time zone has changed to update clock hands.
+ *
+ * @param timeZone The updated time zone that will be used.
+ */
+ public void onTimeZoneChanged(TimeZone timeZone) {
+ mTime.setTimeZone(timeZone);
+ }
+
+ /**
+ * Set the color of the minute hand.
+ */
+ public void setMinuteHandColor(int color) {
+ mMinutePaint.setColor(color);
+ }
+
+ private void init() {
+ mHourPaint.setColor(DEFAULT_COLOR);
+ mHourPaint.setStrokeWidth(HOUR_STROKE_WIDTH);
+ mHourPaint.setAntiAlias(true);
+ mHourPaint.setStrokeCap(Paint.Cap.ROUND);
+
+ mMinutePaint.setColor(Color.WHITE);
+ mMinutePaint.setStrokeWidth(MINUTE_STROKE_WIDTH);
+ mMinutePaint.setAntiAlias(true);
+ mMinutePaint.setStrokeCap(Paint.Cap.ROUND);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ final float centerX = getWidth() / 2f;
+ final float centerY = getHeight() / 2f;
+
+ final float minutesRotation = mTime.get(Calendar.MINUTE) * 6f;
+ final float hoursRotation = (mTime.get(Calendar.HOUR) * 30);
+
+ // Compute length of clock hands. Hour hand is 60% the length from center to edge
+ // and minute hand is twice the length to make sure it extends past screen edge.
+ double sMinuteHandLengthFactor = Math.sin(2d * Math.PI * minutesRotation / 360d);
+ float sMinuteHandLength = (float) (2d * (centerY + (centerX - centerY)
+ * sMinuteHandLengthFactor * sMinuteHandLengthFactor));
+ double sHourHandLengthFactor = Math.sin(2d * Math.PI * hoursRotation / 360d);
+ float sHourHandLength = (float) (0.6d * (centerY + (centerX - centerY)
+ * sHourHandLengthFactor * sHourHandLengthFactor));
+
+ canvas.save();
+
+ canvas.rotate(minutesRotation, centerX, centerY);
+ canvas.drawLine(
+ centerX,
+ centerY + CENTER_GAP_AND_CIRCLE_RADIUS,
+ centerX,
+ centerY - sMinuteHandLength,
+ mMinutePaint);
+
+ canvas.rotate(hoursRotation - minutesRotation, centerX, centerY);
+ canvas.drawLine(
+ centerX,
+ centerY + CENTER_GAP_AND_CIRCLE_RADIUS,
+ centerX,
+ centerY - sHourHandLength,
+ mHourPaint);
+
+ canvas.restore();
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ mTime = Calendar.getInstance(mTimeZone != null ? mTimeZone : TimeZone.getDefault());
+ onTimeChanged();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClockController.java
new file mode 100644
index 0000000..0a39158
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClockController.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard.clock;
+
+import android.graphics.Paint.Style;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.TextClock;
+
+import com.android.keyguard.R;
+import com.android.systemui.plugins.ClockPlugin;
+
+import java.util.TimeZone;
+
+/**
+ * Controller for Stretch clock that can appear on lock screen and AOD.
+ */
+public class StretchAnalogClockController implements ClockPlugin {
+
+ /**
+ * Custom clock shown on AOD screen and behind stack scroller on lock.
+ */
+ private View mBigClockView;
+ private TextClock mDigitalClock;
+ private StretchAnalogClock mAnalogClock;
+
+ /**
+ * Small clock shown on lock screen above stack scroller.
+ */
+ private View mView;
+ private TextClock mLockClock;
+
+ /**
+ * Controller for transition to dark state.
+ */
+ private CrossFadeDarkController mDarkController;
+
+ private StretchAnalogClockController() { }
+
+ /**
+ * Create a BubbleClockController instance.
+ *
+ * @param layoutInflater Inflater used to inflate custom clock views.
+ */
+ public static StretchAnalogClockController build(LayoutInflater layoutInflater) {
+ StretchAnalogClockController controller = new StretchAnalogClockController();
+ controller.createViews(layoutInflater);
+ return controller;
+ }
+
+ private void createViews(LayoutInflater layoutInflater) {
+ mBigClockView = layoutInflater.inflate(R.layout.stretchanalog_clock, null);
+ mAnalogClock = mBigClockView.findViewById(R.id.analog_clock);
+ mDigitalClock = mBigClockView.findViewById(R.id.digital_clock);
+
+ mView = layoutInflater.inflate(R.layout.digital_clock, null);
+ mLockClock = mView.findViewById(R.id.lock_screen_clock);
+ mLockClock.setVisibility(View.GONE);
+
+ mDarkController = new CrossFadeDarkController(mDigitalClock, mLockClock);
+ }
+
+ @Override
+ public View getView() {
+ return mView;
+ }
+
+ @Override
+ public View getBigClockView() {
+ return mBigClockView;
+ }
+
+ @Override
+ public void setStyle(Style style) {}
+
+ @Override
+ public void setTextColor(int color) {
+ mLockClock.setTextColor(color);
+ mDigitalClock.setTextColor(color);
+ mAnalogClock.setMinuteHandColor(color);
+ }
+
+ @Override
+ public void dozeTimeTick() {
+ mAnalogClock.onTimeChanged();
+ }
+
+ @Override
+ public void setDarkAmount(float darkAmount) {
+ mDarkController.setDarkAmount(darkAmount);
+ }
+
+ @Override
+ public void onTimeZoneChanged(TimeZone timeZone) {
+ mAnalogClock.onTimeZoneChanged(timeZone);
+ }
+
+ @Override
+ public boolean shouldShowStatusArea() {
+ return false;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index d7bf77d..957d772 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -284,8 +284,9 @@
@Nullable
private PendingIntent getAppOverlayIntent(NotificationEntry notif) {
Notification notification = notif.notification.getNotification();
- if (canLaunchInActivityView(notification.getAppOverlayIntent())) {
- return notification.getAppOverlayIntent();
+ if (canLaunchInActivityView(notification.getBubbleMetadata() != null
+ ? notification.getBubbleMetadata().getIntent() : null)) {
+ return notification.getBubbleMetadata().getIntent();
} else if (shouldUseContentIntent(mContext)
&& canLaunchInActivityView(notification.contentIntent)) {
Log.d(TAG, "[addBubble " + notif.key
@@ -446,15 +447,16 @@
StatusBarNotification n = entry.notification;
boolean canAppOverlay = false;
try {
- canAppOverlay = mNotificationManagerService.areAppOverlaysAllowedForPackage(
+ canAppOverlay = mNotificationManagerService.areBubblesAllowedForPackage(
n.getPackageName(), n.getUid());
} catch (RemoteException e) {
Log.w(TAG, "Error calling NoMan to determine if app can overlay", e);
}
boolean canChannelOverlay = mNotificationEntryManager.getNotificationData().getChannel(
- entry.key).canOverlayApps();
- boolean hasOverlayIntent = n.getNotification().getAppOverlayIntent() != null;
+ entry.key).canBubble();
+ boolean hasOverlayIntent = n.getNotification().getBubbleMetadata() != null
+ && n.getNotification().getBubbleMetadata().getIntent() != null;
return hasOverlayIntent && canChannelOverlay && canAppOverlay;
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
index 4cb1fee..bd7a421 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
@@ -38,7 +38,13 @@
void setAnimateWakeup(boolean animateWakeup);
void setAnimateScreenOff(boolean animateScreenOff);
- void onDoubleTap(float x, float y);
+ /**
+ * Reports that a tap event happend on the Sensors Low Power Island.
+ *
+ * @param x Touch X, or -1 if sensor doesn't support touch location.
+ * @param y Touch Y, or -1 if sensor doesn't support touch location.
+ */
+ void onSlpiTap(float x, float y);
default void setAodDimmingScrim(float scrimOpacity) {}
void setDozeScreenBrightness(int value);
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
index 50003e3..a784773 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
@@ -35,7 +35,7 @@
private static final int SIZE = Build.IS_DEBUGGABLE ? 400 : 50;
static final SimpleDateFormat FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
- private static final int REASONS = 9;
+ private static final int REASONS = 10;
public static final int PULSE_REASON_NONE = -1;
public static final int PULSE_REASON_INTENT = 0;
@@ -47,6 +47,7 @@
public static final int PULSE_REASON_DOCKING = 6;
public static final int REASON_SENSOR_WAKE_UP = 7;
public static final int PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN = 8;
+ public static final int PULSE_REASON_SENSOR_TAP = 9;
private static boolean sRegisterKeyguardCallback = true;
@@ -207,6 +208,7 @@
case PULSE_REASON_DOCKING: return "docking";
case PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN: return "wakelockscreen";
case REASON_SENSOR_WAKE_UP: return "wakeup";
+ case PULSE_REASON_SENSOR_TAP: return "tap";
default: throw new IllegalArgumentException("bad reason: " + pulseReason);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index b6fc355..78374a0 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -107,6 +107,13 @@
dozeParameters.doubleTapReportsTouchCoordinates(),
true /* touchscreen */),
new TriggerSensor(
+ findSensorWithType(config.tapSensorType()),
+ Settings.Secure.DOZE_TAP_SCREEN_GESTURE,
+ true /* configured */,
+ DozeLog.PULSE_REASON_SENSOR_TAP,
+ false /* reports touch coordinates */,
+ true /* touchscreen */),
+ new TriggerSensor(
findSensorWithType(config.longPressSensorType()),
Settings.Secure.DOZE_PULSE_ON_LONG_PRESS,
false /* settingDef */,
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 6a9b689..e2e448b 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -132,6 +132,7 @@
private void onSensor(int pulseReason, boolean sensorPerformedProxCheck,
float screenX, float screenY, float[] rawValues) {
boolean isDoubleTap = pulseReason == DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP;
+ boolean isTap = pulseReason == DozeLog.PULSE_REASON_SENSOR_TAP;
boolean isPickup = pulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP;
boolean isLongPress = pulseReason == DozeLog.PULSE_REASON_SENSOR_LONG_PRESS;
boolean isWakeDisplay = pulseReason == DozeLog.REASON_SENSOR_WAKE_UP;
@@ -148,8 +149,10 @@
// In pocket, drop event.
return;
}
- if (isDoubleTap) {
- mDozeHost.onDoubleTap(screenX, screenY);
+ if (isDoubleTap || isTap) {
+ if (screenX != -1 && screenY != -1) {
+ mDozeHost.onSlpiTap(screenX, screenY);
+ }
mMachine.wakeUp();
} else if (isPickup) {
mMachine.wakeUp();
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt
index 6ed1eba..77e25e3 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt
@@ -20,6 +20,7 @@
import android.content.DialogInterface
import android.content.Intent
import android.content.res.ColorStateList
+import android.util.IconDrawableFactory
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
@@ -37,11 +38,22 @@
private val iconSize = context.resources.getDimensionPixelSize(
R.dimen.ongoing_appops_dialog_icon_size)
+ private val plusSize = context.resources.getDimensionPixelSize(
+ R.dimen.ongoing_appops_dialog_app_plus_size)
private val iconColor = context.resources.getColor(
com.android.internal.R.color.text_color_primary, context.theme)
+ private val plusColor: Int
private val iconMargin = context.resources.getDimensionPixelSize(
R.dimen.ongoing_appops_dialog_icon_margin)
private val MAX_ITEMS = context.resources.getInteger(R.integer.ongoing_appops_dialog_max_apps)
+ private val iconFactory = IconDrawableFactory.newInstance(context, true)
+
+ init {
+ val a = context.theme.obtainStyledAttributes(
+ intArrayOf(com.android.internal.R.attr.colorAccent))
+ plusColor = a.getColor(0, 0)
+ a.recycle()
+ }
fun createDialog(): Dialog {
val builder = AlertDialog.Builder(context).apply {
@@ -87,9 +99,15 @@
numItems - MAX_ITEMS
)
val overflowPlus = overflow.findViewById(R.id.app_icon) as ImageView
+ val lp = overflowPlus.layoutParams.apply {
+ height = plusSize
+ width = plusSize
+ }
+ overflowPlus.layoutParams = lp
overflowPlus.apply {
- imageTintList = ColorStateList.valueOf(iconColor)
- setImageDrawable(context.getDrawable(R.drawable.plus))
+ val plus = context.getDrawable(R.drawable.plus)
+ imageTintList = ColorStateList.valueOf(plusColor)
+ setImageDrawable(plus)
}
}
@@ -114,7 +132,7 @@
}
app.icon.let {
- appIcon.setImageDrawable(it)
+ appIcon.setImageDrawable(iconFactory.getShadowedIcon(it))
}
appName.text = app.applicationName
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 514bb22..7569a50 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -3999,7 +3999,7 @@
}
@Override
- public void onDoubleTap(float screenX, float screenY) {
+ public void onSlpiTap(float screenX, float screenY) {
if (screenX > 0 && screenY > 0 && mAmbientIndicationContainer != null
&& mAmbientIndicationContainer.getVisibility() == View.VISIBLE) {
mAmbientIndicationContainer.getLocationOnScreen(mTmpInt2);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 9422101..f79ad71 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -541,7 +541,8 @@
@VisibleForTesting
void doUpdateMobileControllers() {
- List<SubscriptionInfo> subscriptions = mSubscriptionManager.getActiveSubscriptionInfoList();
+ List<SubscriptionInfo> subscriptions = mSubscriptionManager
+ .getActiveSubscriptionInfoList(true);
if (subscriptions == null) {
subscriptions = Collections.emptyList();
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/BubbleClockControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/BubbleClockControllerTest.java
new file mode 100644
index 0000000..9e946fa
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/BubbleClockControllerTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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 static com.google.common.truth.Truth.assertThat;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+public final class BubbleClockControllerTest extends SysuiTestCase {
+
+ private BubbleClockController mClockController;
+
+ @Before
+ public void setUp() {
+ LayoutInflater layoutInflater = LayoutInflater.from(getContext());
+ mClockController = BubbleClockController.build(layoutInflater);
+ }
+
+ @Test
+ public void setDarkAmount_fadeIn() {
+ ViewGroup smallClockFrame = (ViewGroup) mClockController.getView();
+ View smallClock = smallClockFrame.getChildAt(0);
+ // WHEN dark amount is set to AOD
+ mClockController.setDarkAmount(1f);
+ // THEN small clock should not be shown.
+ assertThat(smallClock.getVisibility()).isEqualTo(View.GONE);
+ }
+
+ @Test
+ public void setTextColor_setDigitalClock() {
+ ViewGroup smallClock = (ViewGroup) mClockController.getView();
+ // WHEN text color is set
+ mClockController.setTextColor(42);
+ // THEN child of small clock should have text color set.
+ TextView digitalClock = (TextView) smallClock.getChildAt(0);
+ assertThat(digitalClock.getCurrentTextColor()).isEqualTo(42);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/CrossFadeDarkControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/CrossFadeDarkControllerTest.java
new file mode 100644
index 0000000..fd7657f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/CrossFadeDarkControllerTest.java
@@ -0,0 +1,94 @@
+/*
+ * 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 static com.google.common.truth.Truth.assertThat;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+import android.view.View;
+import android.widget.TextView;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+public final class CrossFadeDarkControllerTest extends SysuiTestCase {
+
+ private View mViewFadeIn;
+ private View mViewFadeOut;
+ private CrossFadeDarkController mDarkController;
+
+ @Before
+ public void setUp() {
+ mViewFadeIn = new TextView(getContext());
+ mViewFadeIn.setVisibility(View.VISIBLE);
+ mViewFadeIn.setAlpha(1f);
+ mViewFadeOut = new TextView(getContext());
+ mViewFadeOut.setVisibility(View.VISIBLE);
+ mViewFadeOut.setAlpha(1f);
+
+ mDarkController = new CrossFadeDarkController(mViewFadeIn, mViewFadeOut);
+ }
+
+ @Test
+ public void setDarkAmount_fadeIn() {
+ // WHEN dark amount corresponds to AOD
+ mDarkController.setDarkAmount(1f);
+ // THEN fade in view should be faded in and fade out view faded out.
+ assertThat(mViewFadeIn.getAlpha()).isEqualTo(1f);
+ assertThat(mViewFadeIn.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mViewFadeOut.getAlpha()).isEqualTo(0f);
+ assertThat(mViewFadeOut.getVisibility()).isEqualTo(View.GONE);
+ }
+
+ @Test
+ public void setDarkAmount_fadeOut() {
+ // WHEN dark amount corresponds to lock screen
+ mDarkController.setDarkAmount(0f);
+ // THEN fade out view should bed faded out and fade in view faded in.
+ assertThat(mViewFadeIn.getAlpha()).isEqualTo(0f);
+ assertThat(mViewFadeIn.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewFadeOut.getAlpha()).isEqualTo(1f);
+ assertThat(mViewFadeOut.getVisibility()).isEqualTo(View.VISIBLE);
+ }
+
+ @Test
+ public void setDarkAmount_partialFadeIn() {
+ // WHEN dark amount corresponds to a partial transition
+ mDarkController.setDarkAmount(0.9f);
+ // THEN views should have intermediate alpha value.
+ assertThat(mViewFadeIn.getAlpha()).isGreaterThan(0f);
+ assertThat(mViewFadeIn.getAlpha()).isLessThan(1f);
+ assertThat(mViewFadeIn.getVisibility()).isEqualTo(View.VISIBLE);
+ }
+
+ @Test
+ public void setDarkAmount_partialFadeOut() {
+ // WHEN dark amount corresponds to a partial transition
+ mDarkController.setDarkAmount(0.1f);
+ // THEN views should have intermediate alpha value.
+ assertThat(mViewFadeOut.getAlpha()).isGreaterThan(0f);
+ assertThat(mViewFadeOut.getAlpha()).isLessThan(1f);
+ assertThat(mViewFadeOut.getVisibility()).isEqualTo(View.VISIBLE);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/StretchAnalogClockControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/StretchAnalogClockControllerTest.java
new file mode 100644
index 0000000..8de8f3d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/StretchAnalogClockControllerTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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 static com.google.common.truth.Truth.assertThat;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+public final class StretchAnalogClockControllerTest extends SysuiTestCase {
+
+ private StretchAnalogClockController mClockController;
+
+ @Before
+ public void setUp() {
+ LayoutInflater layoutInflater = LayoutInflater.from(getContext());
+ mClockController = StretchAnalogClockController.build(layoutInflater);
+ }
+
+ @Test
+ public void setDarkAmount_fadeIn() {
+ ViewGroup smallClockFrame = (ViewGroup) mClockController.getView();
+ View smallClock = smallClockFrame.getChildAt(0);
+ // WHEN dark amount is set to AOD
+ mClockController.setDarkAmount(1f);
+ // THEN small clock should not be shown.
+ assertThat(smallClock.getVisibility()).isEqualTo(View.GONE);
+ }
+
+ @Test
+ public void setTextColor_setDigitalClock() {
+ ViewGroup smallClock = (ViewGroup) mClockController.getView();
+ // WHEN text color is set
+ mClockController.setTextColor(42);
+ // THEN child of small clock should have text color set.
+ TextView digitalClock = (TextView) smallClock.getChildAt(0);
+ assertThat(digitalClock.getCurrentTextColor()).isEqualTo(42);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java
index ce28b50..dc42872 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java
@@ -104,7 +104,7 @@
}
@Override
- public void onDoubleTap(float x, float y) {
+ public void onSlpiTap(float x, float y) {
doubleTapX = y;
doubleTapY = y;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceManagerTest.java
index 4583770..3415c72 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceManagerTest.java
@@ -91,7 +91,7 @@
mMockPm = mock(PackageManager.class);
mMockListener = mock(PluginListener.class);
mMockManager = mock(PluginManagerImpl.class);
- when(mMockManager.getClassLoader(any(), any())).thenReturn(getClass().getClassLoader());
+ when(mMockManager.getClassLoader(any())).thenReturn(getClass().getClassLoader());
mMockEnabler = mock(PluginEnabler.class);
when(mMockManager.getPluginEnabler()).thenReturn(mMockEnabler);
mMockVersionInfo = mock(VersionInfo.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginManagerTest.java
index 76e68f1..536c043 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginManagerTest.java
@@ -25,6 +25,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.test.suitebuilder.annotation.SmallTest;
@@ -135,9 +136,13 @@
});
resetExceptionHandler();
+ String sourceDir = "myPlugin";
+ ApplicationInfo applicationInfo = new ApplicationInfo();
+ applicationInfo.sourceDir = sourceDir;
+ applicationInfo.packageName = WHITELISTED_PACKAGE;
mPluginManager.addPluginListener("myAction", mMockListener, TestPlugin.class);
- assertNull(mPluginManager.getOneShotPlugin("myPlugin", TestPlugin.class));
- assertNull(mPluginManager.getClassLoader("myPlugin", WHITELISTED_PACKAGE));
+ assertNull(mPluginManager.getOneShotPlugin(sourceDir, TestPlugin.class));
+ assertNull(mPluginManager.getClassLoader(applicationInfo));
}
@Test
@@ -152,9 +157,16 @@
});
resetExceptionHandler();
+ String sourceDir = "myPlugin";
+ ApplicationInfo whiteListedApplicationInfo = new ApplicationInfo();
+ whiteListedApplicationInfo.sourceDir = sourceDir;
+ whiteListedApplicationInfo.packageName = WHITELISTED_PACKAGE;
+ ApplicationInfo invalidApplicationInfo = new ApplicationInfo();
+ invalidApplicationInfo.sourceDir = sourceDir;
+ invalidApplicationInfo.packageName = "com.android.invalidpackage";
mPluginManager.addPluginListener("myAction", mMockListener, TestPlugin.class);
- assertNotNull(mPluginManager.getClassLoader("myPlugin", WHITELISTED_PACKAGE));
- assertNull(mPluginManager.getClassLoader("myPlugin", "com.android.invalidpackage"));
+ assertNotNull(mPluginManager.getClassLoader(whiteListedApplicationInfo));
+ assertNull(mPluginManager.getClassLoader(invalidApplicationInfo));
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
index 2b13f86..8952594 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
@@ -27,6 +27,7 @@
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
+import android.graphics.drawable.Icon;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.support.test.InstrumentationRegistry;
@@ -220,8 +221,7 @@
notificationBuilder.setGroup(groupKey);
}
if (isBubble) {
- PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
- notificationBuilder.setAppOverlayIntent(bubbleIntent);
+ notificationBuilder.setBubbleMetadata(makeBubbleMetadata());
}
return notificationBuilder.build();
}
@@ -282,4 +282,14 @@
mGroupManager.onEntryAdded(entry);
return row;
}
+
+ private Notification.BubbleMetadata makeBubbleMetadata() {
+ PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+ return new Notification.BubbleMetadata.Builder()
+ .setIntent(bubbleIntent)
+ .setTitle("bubble title")
+ .setIcon(Icon.createWithResource(mContext, 1))
+ .setDesiredHeight(314)
+ .build();
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index fdbf090..c1f8885 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -182,6 +182,7 @@
subs.add(subscription);
}
when(mMockSm.getActiveSubscriptionInfoList()).thenReturn(subs);
+ when(mMockSm.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(subs);
mNetworkController.doUpdateMobileControllers();
}
diff --git a/packages/services/PacProcessor/Android.mk b/packages/services/PacProcessor/Android.mk
index 295b3d8b..be9ba43 100644
--- a/packages/services/PacProcessor/Android.mk
+++ b/packages/services/PacProcessor/Android.mk
@@ -26,6 +26,6 @@
LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
-LOCAL_JNI_SHARED_LIBRARIES := libjni_pacprocessor libpac
+LOCAL_JNI_SHARED_LIBRARIES := libjni_pacprocessor
include $(BUILD_PACKAGE)
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index 44edb56..a07411d 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -6801,8 +6801,20 @@
// ACTION: Tap & Pay -> Default Application Setting -> Use Default
// OS: Q
ACTION_NFC_PAYMENT_ALWAYS_SETTING = 1623;
- // ---- End Q Constants, all Q constants go above this line ----
+ // OPEN: Settings > System > Input & Gesture > Skip song gesture
+ // OS: Q
+ SETTINGS_GESTURE_SKIP_SONG = 1624;
+
+ // OPEN: Settings > System > Input & Gesture > Silence gesture
+ // OS: Q
+ SETTINGS_GESTURE_SILENCE = 1625;
+
+ // OPEN: Settings > System > Input & Gesture > Tap screen gesture
+ // OS: Q
+ SETTINGS_GESTURE_TAP_SCREEN = 1626;
+
+ // ---- 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 24fd7b9..ec6d20d 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -701,6 +701,11 @@
public void onBackKeyPressed() {
if (sDebug) Slog.d(TAG, "onBackKeyPressed()");
mUi.hideAll(null);
+ synchronized (mLock) {
+ final AutofillManagerServiceImpl service =
+ getServiceForUserLocked(UserHandle.getCallingUserId());
+ service.onBackKeyPressed();
+ }
}
@Override
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index a6bb049..d037b08 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -187,6 +187,15 @@
}
@GuardedBy("mLock")
+ void onBackKeyPressed() {
+ final RemoteAugmentedAutofillService remoteService =
+ getRemoteAugmentedAutofillServiceLocked();
+ if (remoteService != null) {
+ remoteService.onDestroyAutofillWindowsRequest();
+ }
+ }
+
+ @GuardedBy("mLock")
@Override // from PerUserSystemService
protected boolean updateLocked(boolean disabled) {
destroySessionsLocked();
diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
index a8ff9b0..5d8d8fa 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
@@ -109,8 +109,8 @@
/**
* Called by {@link Session} when it's time to destroy all augmented autofill requests.
*/
- public void onDestroyAutofillWindowsRequest(int sessionId) {
- scheduleAsyncRequest((s) -> s.onDestroyFillWindowRequest(sessionId));
+ public void onDestroyAutofillWindowsRequest() {
+ scheduleAsyncRequest((s) -> s.onDestroyAllFillWindowsRequest());
}
// TODO(b/111330312): inline into PendingAutofillRequest if it doesn't have any other subclass
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index cf4963c..a5ef21a 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -2619,7 +2619,7 @@
currentValue);
if (mAugmentedAutofillDestroyer == null) {
- mAugmentedAutofillDestroyer = () -> remoteService.onDestroyAutofillWindowsRequest(id);
+ mAugmentedAutofillDestroyer = () -> remoteService.onDestroyAutofillWindowsRequest();
}
return mAugmentedAutofillDestroyer;
}
diff --git a/services/backup/java/com/android/server/backup/TransportManager.java b/services/backup/java/com/android/server/backup/TransportManager.java
index 529430c..a7bada0 100644
--- a/services/backup/java/com/android/server/backup/TransportManager.java
+++ b/services/backup/java/com/android/server/backup/TransportManager.java
@@ -562,7 +562,7 @@
private void registerTransportsFromPackage(
String packageName, Predicate<ComponentName> transportComponentFilter) {
try {
- mPackageManager.getPackageInfo(packageName, 0);
+ mPackageManager.getPackageInfoAsUser(packageName, 0, mUserId);
} catch (PackageManager.NameNotFoundException e) {
Slog.e(TAG, "Trying to register transports from package not found " + packageName);
return;
@@ -599,7 +599,8 @@
return false;
}
try {
- PackageInfo packInfo = mPackageManager.getPackageInfo(transport.getPackageName(), 0);
+ PackageInfo packInfo =
+ mPackageManager.getPackageInfoAsUser(transport.getPackageName(), 0, mUserId);
if ((packInfo.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED)
== 0) {
Slog.w(TAG, "Transport package " + transport.getPackageName() + " not privileged");
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index 3a8966a..e0e81ff 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -495,7 +495,7 @@
mBaseStateDir = checkNotNull(baseStateDir, "baseStateDir cannot be null");
mBaseStateDir.mkdirs();
- if (!SELinux.restorecon(mBaseStateDir)) {
+ if (!SELinux.restoreconRecursive(mBaseStateDir)) {
Slog.w(TAG, "SELinux restorecon failed on " + mBaseStateDir);
}
@@ -504,7 +504,7 @@
// is managed by init.rc so we don't have to create it below.
if (userId != UserHandle.USER_SYSTEM) {
mDataDir.mkdirs();
- if (!SELinux.restorecon(mDataDir)) {
+ if (!SELinux.restoreconRecursive(mDataDir)) {
Slog.w(TAG, "SELinux restorecon failed on " + mDataDir);
}
}
@@ -584,7 +584,7 @@
mBackupHandler.postDelayed(this::parseLeftoverJournals, INITIALIZATION_DELAY_MILLIS);
// Power management
- mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*");
+ mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*-" + userId);
}
void initializeBackupEnableState() {
@@ -1352,7 +1352,7 @@
private List<PackageInfo> allAgentPackages() {
// !!! TODO: cache this and regenerate only when necessary
int flags = PackageManager.GET_SIGNING_CERTIFICATES;
- List<PackageInfo> packages = mPackageManager.getInstalledPackages(flags);
+ List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser(flags, mUserId);
int numPackages = packages.size();
for (int a = numPackages - 1; a >= 0; a--) {
PackageInfo pkg = packages.get(a);
@@ -1366,8 +1366,8 @@
// we will need the shared library path, so look that up and store it here.
// This is used implicitly when we pass the PackageInfo object off to
// the Activity Manager to launch the app for backup/restore purposes.
- app = mPackageManager.getApplicationInfo(pkg.packageName,
- PackageManager.GET_SHARED_LIBRARY_FILES);
+ app = mPackageManager.getApplicationInfoAsUser(pkg.packageName,
+ PackageManager.GET_SHARED_LIBRARY_FILES, mUserId);
pkg.applicationInfo.sharedLibraryFiles = app.sharedLibraryFiles;
pkg.applicationInfo.sharedLibraryInfos = app.sharedLibraryInfos;
}
@@ -1392,7 +1392,7 @@
notification.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES
| Intent.FLAG_RECEIVER_FOREGROUND);
notification.putExtra(BACKUP_FINISHED_PACKAGE_EXTRA, packageName);
- mContext.sendBroadcastAsUser(notification, UserHandle.OWNER);
+ mContext.sendBroadcastAsUser(notification, UserHandle.of(mUserId));
}
mProcessedPackagesJournal.addPackage(packageName);
@@ -2208,11 +2208,10 @@
/** Used by both incremental and full restore to restore widget data. */
public void restoreWidgetData(String packageName, byte[] widgetData) {
// Apply the restored widget state and generate the ID update for the app
- // TODO: http://b/22388012
if (MORE_DEBUG) {
Slog.i(TAG, "Incorporating restored widget data");
}
- AppWidgetBackupBridge.restoreWidgetState(packageName, widgetData, UserHandle.USER_SYSTEM);
+ AppWidgetBackupBridge.restoreWidgetState(packageName, widgetData, mUserId);
}
// *****************************
@@ -2291,20 +2290,6 @@
/** Sent from an app's backup agent to let the service know that there's new data to backup. */
public void dataChanged(final String packageName) {
- final int callingUserHandle = UserHandle.getCallingUserId();
- if (callingUserHandle != UserHandle.USER_SYSTEM) {
- // TODO: http://b/22388012
- // App is running under a non-owner user profile. For now, we do not back
- // up data from secondary user profiles.
- // TODO: backups for all user profiles although don't add backup for profiles
- // without adding admin control in DevicePolicyManager.
- if (MORE_DEBUG) {
- Slog.v(TAG, "dataChanged(" + packageName + ") ignored because it's user "
- + callingUserHandle);
- }
- return;
- }
-
final HashSet<String> targets = dataChangedTargets(packageName);
if (targets == null) {
Slog.w(TAG, "dataChanged but no participant pkg='" + packageName + "'"
@@ -2921,7 +2906,7 @@
try {
int transportUid =
mContext.getPackageManager()
- .getPackageUid(transportComponent.getPackageName(), 0);
+ .getPackageUidAsUser(transportComponent.getPackageName(), 0, mUserId);
if (callingUid != transportUid) {
throw new SecurityException("Only the transport can change its description");
}
diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
index c7f3315..b3d9fbc 100644
--- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
+++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
@@ -68,6 +68,8 @@
public class FullRestoreEngine extends RestoreEngine {
private final UserBackupManagerService mBackupManagerService;
+ private final int mUserId;
+
// Task in charge of monitoring timeouts
private final BackupRestoreTask mMonitorTask;
@@ -146,6 +148,7 @@
backupManagerService.getAgentTimeoutParameters(),
"Timeout parameters cannot be null");
mIsAdbRestore = isAdbRestore;
+ mUserId = backupManagerService.getUserId();
}
public IBackupAgent getAgent() {
@@ -272,7 +275,7 @@
instream, mBackupManagerService.getContext(),
mDeleteObserver, mManifestSignatures,
mPackagePolicies, info, installerPackageName,
- bytesReadListener, mBackupManagerService.getUserId());
+ bytesReadListener, mUserId);
// good to go; promote to ACCEPT
mPackagePolicies.put(pkg, isSuccessfullyInstalled
? RestorePolicy.ACCEPT
@@ -329,9 +332,8 @@
}
try {
- mTargetApp =
- mBackupManagerService.getPackageManager().getApplicationInfo(
- pkg, 0);
+ mTargetApp = mBackupManagerService.getPackageManager()
+ .getApplicationInfoAsUser(pkg, 0, mUserId);
// If we haven't sent any data to this app yet, we probably
// need to clear it first. Check that.
@@ -684,7 +686,7 @@
String packageListString = Settings.Secure.getStringForUser(
mBackupManagerService.getContext().getContentResolver(),
Settings.Secure.PACKAGES_TO_CLEAR_DATA_BEFORE_FULL_RESTORE,
- mBackupManagerService.getUserId());
+ mUserId);
if (TextUtils.isEmpty(packageListString)) {
return false;
}
diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
index 5284d94..d01f77b 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
@@ -360,7 +360,6 @@
// If we're starting a full-system restore, set up to begin widget ID remapping
if (mIsSystemRestore) {
- // TODO: http://b/22388012
AppWidgetBackupBridge.restoreStarting(mUserId);
}
@@ -1079,7 +1078,6 @@
}
// Kick off any work that may be needed regarding app widget restores
- // TODO: http://b/22388012
AppWidgetBackupBridge.restoreFinished(mUserId);
// If this was a full-system restore, record the ancestral
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
index 09aa421..1dae2ce 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
@@ -17,6 +17,9 @@
package com.android.server.contentcapture;
import static android.service.contentcapture.ContentCaptureService.setClientState;
+import static android.view.contentcapture.ContentCaptureSession.STATE_DISABLED;
+import static android.view.contentcapture.ContentCaptureSession.STATE_DUPLICATED_ID;
+import static android.view.contentcapture.ContentCaptureSession.STATE_NO_SERVICE;
import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_CONTENT;
import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_DATA;
@@ -36,10 +39,11 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.service.contentcapture.ContentCaptureService;
+import android.service.contentcapture.IContentCaptureServiceCallback;
import android.service.contentcapture.SnapshotData;
import android.util.ArrayMap;
+import android.util.Log;
import android.util.Slog;
-import android.view.contentcapture.ContentCaptureSession;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.IResultReceiver;
@@ -48,6 +52,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.List;
/**
* Per-user instance of {@link ContentCaptureManagerService}.
@@ -72,6 +77,9 @@
@GuardedBy("mLock")
private RemoteContentCaptureService mRemoteService;
+ private final ContentCaptureServiceRemoteCallback mRemoteServiceCallback =
+ new ContentCaptureServiceRemoteCallback();
+
// TODO(b/111276913): add mechanism to prune stale sessions, similar to Autofill's
ContentCapturePerUserService(@NonNull ContentCaptureManagerService master,
@@ -100,10 +108,10 @@
}
if (!disabled) {
- mRemoteService = new RemoteContentCaptureService(
- mMaster.getContext(),
- ContentCaptureService.SERVICE_INTERFACE, serviceComponentName, mUserId, this,
- mMaster.isBindInstantServiceAllowed(), mMaster.verbose);
+ mRemoteService = new RemoteContentCaptureService(mMaster.getContext(),
+ ContentCaptureService.SERVICE_INTERFACE, serviceComponentName,
+ mRemoteServiceCallback, mUserId, this, mMaster.isBindInstantServiceAllowed(),
+ mMaster.verbose);
}
}
@@ -165,7 +173,7 @@
if (!isEnabledLocked()) {
// TODO: it would be better to split in differet reasons, like
// STATE_DISABLED_NO_SERVICE and STATE_DISABLED_BY_DEVICE_POLICY
- setClientState(clientReceiver, ContentCaptureSession.STATE_DISABLED_NO_SERVICE,
+ setClientState(clientReceiver, STATE_DISABLED | STATE_NO_SERVICE,
/* binder= */ null);
return;
}
@@ -184,7 +192,7 @@
if (existingSession != null) {
Slog.w(TAG, "startSession(id=" + existingSession + ", token=" + activityToken
+ ": ignoring because it already exists for " + existingSession.mActivityToken);
- setClientState(clientReceiver, ContentCaptureSession.STATE_DISABLED_DUPLICATED_ID,
+ setClientState(clientReceiver, STATE_DISABLED | STATE_DUPLICATED_ID,
/* binder=*/ null);
return;
}
@@ -197,8 +205,7 @@
// TODO(b/119613670): log metrics
Slog.w(TAG, "startSession(id=" + existingSession + ", token=" + activityToken
+ ": ignoring because service is not set");
- // TODO(b/111276913): use a new disabled state?
- setClientState(clientReceiver, ContentCaptureSession.STATE_DISABLED_NO_SERVICE,
+ setClientState(clientReceiver, STATE_DISABLED | STATE_NO_SERVICE,
/* binder= */ null);
return;
}
@@ -338,4 +345,50 @@
}
return null;
}
+
+ private final class ContentCaptureServiceRemoteCallback extends
+ IContentCaptureServiceCallback.Stub {
+
+ @Override
+ public void setContentCaptureWhitelist(List<String> packages,
+ List<ComponentName> activities) {
+ if (mMaster.verbose) {
+ Log.v(TAG, "setContentCaptureWhitelist(packages=" + packages + ", activities="
+ + activities + ")");
+ }
+ // TODO(b/122595322): implement
+ // TODO(b/119613670): log metrics
+ }
+
+ @Override
+ public void setActivityContentCaptureEnabled(ComponentName activity, boolean enabled) {
+ if (mMaster.verbose) {
+ Log.v(TAG, "setActivityContentCaptureEnabled(activity=" + activity + ", enabled="
+ + enabled + ")");
+ }
+ // TODO(b/122595322): implement
+ // TODO(b/119613670): log metrics
+ }
+
+ @Override
+ public void setPackageContentCaptureEnabled(String packageName, boolean enabled) {
+ if (mMaster.verbose) {
+ Log.v(TAG,
+ "setPackageContentCaptureEnabled(packageName=" + packageName + ", enabled="
+ + enabled + ")");
+ }
+ // TODO(b/122595322): implement
+ // TODO(b/119613670): log metrics
+ }
+
+ @Override
+ public void getContentCaptureDisabledActivities(IResultReceiver receiver) {
+ // TODO(b/122595322): implement
+ }
+
+ @Override
+ public void getContentCaptureDisabledPackages(IResultReceiver receiver) {
+ // TODO(b/122595322): implement
+ }
+ }
}
diff --git a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
index 82416286..12742ca 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
@@ -21,6 +21,7 @@
import android.content.Context;
import android.os.IBinder;
import android.service.contentcapture.IContentCaptureService;
+import android.service.contentcapture.IContentCaptureServiceCallback;
import android.service.contentcapture.SnapshotData;
import android.text.format.DateUtils;
import android.util.Slog;
@@ -35,12 +36,15 @@
private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 2 * DateUtils.SECOND_IN_MILLIS;
+ private final IBinder mServerCallback;
+
RemoteContentCaptureService(Context context, String serviceInterface,
- ComponentName componentName, int userId,
+ ComponentName serviceComponentName, IContentCaptureServiceCallback callback, int userId,
ContentCaptureServiceCallbacks callbacks, boolean bindInstantServiceAllowed,
boolean verbose) {
- super(context, serviceInterface, componentName, userId, callbacks,
+ super(context, serviceInterface, serviceComponentName, userId, callbacks,
bindInstantServiceAllowed, verbose, /* initialCapacity= */ 2);
+ mServerCallback = callback.asBinder();
// Bind right away, which will trigger a onConnected() on service's
scheduleBind();
@@ -69,7 +73,11 @@
scheduleUnbind();
}
try {
- mService.onConnectedStateChanged(state);
+ if (state) {
+ mService.onConnected(mServerCallback);
+ } else {
+ mService.onDisconnected();
+ }
} catch (Exception e) {
Slog.w(mTag, "Exception calling onConnectedStateChanged(" + state + "): " + e);
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index d0666b9..d6f3e2b 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -4879,7 +4879,7 @@
final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
new Network(reserveNetId()), new NetworkInfo(networkInfo), lp, nc, currentScore,
- mContext, mTrackerHandler, new NetworkMisc(networkMisc), this);
+ mContext, mTrackerHandler, new NetworkMisc(networkMisc), this, mNetd, mNMS);
// Make sure the network capabilities reflect what the agent info says.
nai.networkCapabilities = mixInCapabilities(nai, nc);
final String extraInfo = networkInfo.getExtraInfo();
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 869d564..0b4c01e 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -257,6 +257,9 @@
packageManagerInternal.setLocationPackagesProvider(
userId -> mContext.getResources().getStringArray(
com.android.internal.R.array.config_locationProviderPackageNames));
+ packageManagerInternal.setLocationExtraPackagesProvider(
+ userId -> mContext.getResources().getStringArray(
+ com.android.internal.R.array.config_locationExtraPackageNames));
// most startup is deferred until systemRunning()
}
@@ -1041,12 +1044,13 @@
@Override
public void onSetProperties(ProviderProperties properties) {
- // move calls coming from below LMS onto a different thread to avoid deadlock
- runInternal(() -> {
- synchronized (mLock) {
- mProperties = properties;
- }
- });
+ // because this does not invoke any other methods which might result in calling back
+ // into the location provider, it is safe to run this on the calling thread. it is also
+ // currently necessary to run this on the calling thread to ensure that property changes
+ // are publicly visibly immediately, ie for mock providers which are created.
+ synchronized (mLock) {
+ mProperties = properties;
+ }
}
@GuardedBy("mLock")
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index b0ca2df..aed0684 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -17,13 +17,11 @@
package com.android.server;
import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
-import static android.Manifest.permission.DUMP;
import static android.Manifest.permission.NETWORK_SETTINGS;
import static android.Manifest.permission.NETWORK_STACK;
import static android.Manifest.permission.SHUTDOWN;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_DOZABLE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_DOZABLE;
-import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_NONE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_POWERSAVE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_STANDBY;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NONE;
@@ -40,6 +38,7 @@
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
import static android.net.TrafficStats.UID_TETHERING;
+
import static com.android.server.NetworkManagementService.NetdResponseCode.ClatdStatusResult;
import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceGetCfgResult;
import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceListResult;
@@ -53,11 +52,9 @@
import android.annotation.NonNull;
import android.app.ActivityManager;
-import android.content.ContentResolver;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.INetd;
-import android.net.TetherStatsParcel;
import android.net.INetworkManagementEventObserver;
import android.net.ITetheringStatsProvider;
import android.net.InterfaceConfiguration;
@@ -69,18 +66,15 @@
import android.net.NetworkStats;
import android.net.NetworkUtils;
import android.net.RouteInfo;
+import android.net.TetherStatsParcel;
import android.net.UidRange;
-import android.net.UidRangeParcel;
import android.net.util.NetdService;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.os.BatteryStats;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.INetworkActivityListener;
import android.os.INetworkManagementService;
-import android.os.PersistableBundle;
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteCallbackList;
@@ -91,12 +85,7 @@
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.Trace;
-import android.provider.Settings;
import android.telephony.DataConnectionRealTimeInfo;
-import android.telephony.PhoneStateListener;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;
import android.util.SparseBooleanArray;
@@ -110,13 +99,11 @@
import com.android.internal.util.DumpUtils;
import com.android.internal.util.HexDump;
import com.android.internal.util.Preconditions;
-import com.android.server.NativeDaemonConnector.Command;
-import com.android.server.NativeDaemonConnector.SensitiveArg;
+
import com.google.android.collect.Maps;
import java.io.BufferedReader;
import java.io.DataInputStream;
-import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
@@ -124,15 +111,11 @@
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.InterfaceAddress;
-import java.net.NetworkInterface;
-import java.net.SocketException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.NoSuchElementException;
-import java.util.StringTokenizer;
import java.util.concurrent.CountDownLatch;
/**
@@ -2153,28 +2136,6 @@
}
@Override
- public void startClatd(String interfaceName) throws IllegalStateException {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-
- try {
- mNetdService.clatdStart(interfaceName);
- } catch (RemoteException | ServiceSpecificException e) {
- throw new IllegalStateException(e);
- }
- }
-
- @Override
- public void stopClatd(String interfaceName) throws IllegalStateException {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-
- try {
- mNetdService.clatdStop(interfaceName);
- } catch (RemoteException | ServiceSpecificException e) {
- throw new IllegalStateException(e);
- }
- }
-
- @Override
public void registerNetworkActivityListener(INetworkActivityListener listener) {
mNetworkActivityListeners.register(listener);
}
diff --git a/services/core/java/com/android/server/TEST_MAPPING b/services/core/java/com/android/server/TEST_MAPPING
index 93e1dd3..16b12f1 100644
--- a/services/core/java/com/android/server/TEST_MAPPING
+++ b/services/core/java/com/android/server/TEST_MAPPING
@@ -7,7 +7,7 @@
"include-annotation": "android.platform.test.annotations.Presubmit"
},
{
- "exclude-annotation": "android.support.test.filters.FlakyTest"
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 1c04a94..dd2b33a 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -70,6 +70,12 @@
static final String KEY_MEMORY_INFO_THROTTLE_TIME = "memory_info_throttle_time";
static final String KEY_TOP_TO_FGS_GRACE_DURATION = "top_to_fgs_grace_duration";
static final String KEY_USE_COMPACTION = "use_compaction";
+ static final String KEY_COMPACT_ACTION_1 = "compact_action_1";
+ static final String KEY_COMPACT_ACTION_2 = "compact_action_2";
+ static final String KEY_COMPACT_THROTTLE_1 = "compact_throttle_1";
+ static final String KEY_COMPACT_THROTTLE_2 = "compact_throttle_2";
+ static final String KEY_COMPACT_THROTTLE_3 = "compact_throttle_3";
+ static final String KEY_COMPACT_THROTTLE_4 = "compact_throttle_4";
private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
private static final long DEFAULT_BACKGROUND_SETTLE_TIME = 60*1000;
@@ -101,6 +107,12 @@
private static final long DEFAULT_MEMORY_INFO_THROTTLE_TIME = 5*60*1000;
private static final long DEFAULT_TOP_TO_FGS_GRACE_DURATION = 15 * 1000;
private static final boolean DEFAULT_USE_COMPACTION = false;
+ public static final int DEFAULT_COMPACT_ACTION_1 = 1;
+ public static final int DEFAULT_COMPACT_ACTION_2 = 3;
+ public static final long DEFAULT_COMPACT_THROTTLE_1 = 5000;
+ public static final long DEFAULT_COMPACT_THROTTLE_2 = 10000;
+ public static final long DEFAULT_COMPACT_THROTTLE_3 = 500;
+ public static final long DEFAULT_COMPACT_THROTTLE_4 = 10000;
// Maximum number of cached processes we will allow.
public int MAX_CACHED_PROCESSES = DEFAULT_MAX_CACHED_PROCESSES;
@@ -223,6 +235,20 @@
// Use compaction for background apps.
public boolean USE_COMPACTION = DEFAULT_USE_COMPACTION;
+ // Action for compactAppSome.
+ public int COMPACT_ACTION_1 = DEFAULT_COMPACT_ACTION_1;
+ // Action for compactAppFull;
+ public int COMPACT_ACTION_2 = DEFAULT_COMPACT_ACTION_2;
+
+ // How long we'll skip second compactAppSome after first compactAppSome
+ public long COMPACT_THROTTLE_1 = DEFAULT_COMPACT_THROTTLE_1;
+ // How long we'll skip compactAppSome after compactAppFull
+ public long COMPACT_THROTTLE_2 = DEFAULT_COMPACT_THROTTLE_2;
+ // How long we'll skip compactAppFull after compactAppSome
+ public long COMPACT_THROTTLE_3 = DEFAULT_COMPACT_THROTTLE_3;
+ // How long we'll skip second compactAppFull after first compactAppFull
+ public long COMPACT_THROTTLE_4 = DEFAULT_COMPACT_THROTTLE_4;
+
// Indicates whether the activity starts logging is enabled.
// Controlled by Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED
volatile boolean mFlagActivityStartsLoggingEnabled;
@@ -381,6 +407,12 @@
TOP_TO_FGS_GRACE_DURATION = mParser.getDurationMillis(KEY_TOP_TO_FGS_GRACE_DURATION,
DEFAULT_TOP_TO_FGS_GRACE_DURATION);
USE_COMPACTION = mParser.getBoolean(KEY_USE_COMPACTION, DEFAULT_USE_COMPACTION);
+ COMPACT_ACTION_1 = mParser.getInt(KEY_COMPACT_ACTION_1, DEFAULT_COMPACT_ACTION_1);
+ COMPACT_ACTION_2 = mParser.getInt(KEY_COMPACT_ACTION_2, DEFAULT_COMPACT_ACTION_2);
+ COMPACT_THROTTLE_1 = mParser.getLong(KEY_COMPACT_THROTTLE_1, DEFAULT_COMPACT_THROTTLE_1);
+ COMPACT_THROTTLE_2 = mParser.getLong(KEY_COMPACT_THROTTLE_2, DEFAULT_COMPACT_THROTTLE_2);
+ COMPACT_THROTTLE_3 = mParser.getLong(KEY_COMPACT_THROTTLE_3, DEFAULT_COMPACT_THROTTLE_3);
+ COMPACT_THROTTLE_4 = mParser.getLong(KEY_COMPACT_THROTTLE_4, DEFAULT_COMPACT_THROTTLE_4);
updateMaxCachedProcesses();
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index bd6fa49..089847d 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -32,6 +32,7 @@
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.pm.ApplicationInfo.HIDDEN_API_ENFORCEMENT_DEFAULT;
import static android.content.pm.PackageManager.GET_PROVIDERS;
+import static android.content.pm.PackageManager.MATCH_ALL;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
@@ -318,7 +319,6 @@
import com.android.internal.util.function.QuadFunction;
import com.android.internal.util.function.TriFunction;
import com.android.server.AlarmManagerInternal;
-import com.android.server.appop.AppOpsService;
import com.android.server.AttributeCache;
import com.android.server.DeviceIdleController;
import com.android.server.DisplayThread;
@@ -337,6 +337,7 @@
import com.android.server.Watchdog;
import com.android.server.am.ActivityManagerServiceDumpProcessesProto.UidObserverRegistrationProto;
import com.android.server.am.MemoryStatUtil.MemoryStat;
+import com.android.server.appop.AppOpsService;
import com.android.server.firewall.IntentFirewall;
import com.android.server.job.JobSchedulerInternal;
import com.android.server.pm.Installer;
@@ -658,9 +659,47 @@
/**
* When an app has restrictions on the other apps that can have associations with it,
- * it appears here with a set of the allowed apps.
+ * it appears here with a set of the allowed apps and also track debuggability of the app.
*/
- ArrayMap<String, ArraySet<String>> mAllowedAssociations;
+ ArrayMap<String, PackageAssociationInfo> mAllowedAssociations;
+
+ /**
+ * Tracks association information for a particular package along with debuggability.
+ * <p> Associations for a package A are allowed to package B if B is part of the
+ * allowed associations for A or if A is debuggable.
+ */
+ private final class PackageAssociationInfo {
+ private final String mSourcePackage;
+ private final ArraySet<String> mAllowedPackageAssociations;
+ private boolean mIsDebuggable;
+
+ PackageAssociationInfo(String sourcePackage, ArraySet<String> allowedPackages,
+ boolean isDebuggable) {
+ mSourcePackage = sourcePackage;
+ mAllowedPackageAssociations = allowedPackages;
+ mIsDebuggable = isDebuggable;
+ }
+
+ /**
+ * Returns true if {@code mSourcePackage} is allowed association with
+ * {@code targetPackage}.
+ */
+ boolean isPackageAssociationAllowed(String targetPackage) {
+ return mIsDebuggable || mAllowedPackageAssociations.contains(targetPackage);
+ }
+
+ boolean isDebuggable() {
+ return mIsDebuggable;
+ }
+
+ void setDebuggable(boolean isDebuggable) {
+ mIsDebuggable = isDebuggable;
+ }
+
+ ArraySet<String> getAllowedPackageAssociations() {
+ return mAllowedPackageAssociations;
+ }
+ }
/**
* All of the processes we currently have running organized by pid.
@@ -2392,12 +2431,10 @@
* If it does not, give it an empty set.
*/
void requireAllowedAssociationsLocked(String packageName) {
- if (mAllowedAssociations == null) {
- mAllowedAssociations = new ArrayMap<>(
- SystemConfig.getInstance().getAllowedAssociations());
- }
+ ensureAllowedAssociations();
if (mAllowedAssociations.get(packageName) == null) {
- mAllowedAssociations.put(packageName, new ArraySet<>());
+ mAllowedAssociations.put(packageName, new PackageAssociationInfo(packageName,
+ new ArraySet<>(), /* isDebuggable = */ false));
}
}
@@ -2408,10 +2445,7 @@
* association is implicitly allowed.
*/
boolean validateAssociationAllowedLocked(String pkg1, int uid1, String pkg2, int uid2) {
- if (mAllowedAssociations == null) {
- mAllowedAssociations = new ArrayMap<>(
- SystemConfig.getInstance().getAllowedAssociations());
- }
+ ensureAllowedAssociations();
// Interactions with the system uid are always allowed, since that is the core system
// that everyone needs to be able to interact with. Also allow reflexive associations
// within the same uid.
@@ -2419,24 +2453,57 @@
|| UserHandle.getAppId(uid2) == SYSTEM_UID) {
return true;
}
- // We won't allow this association if either pkg1 or pkg2 has a limit on the
- // associations that are allowed with it, and the other package is not explicitly
- // specified as one of those associations.
- ArraySet<String> pkgs = mAllowedAssociations.get(pkg1);
- if (pkgs != null) {
- if (!pkgs.contains(pkg2)) {
- return false;
- }
+
+ // Check for association on both source and target packages.
+ PackageAssociationInfo pai = mAllowedAssociations.get(pkg1);
+ if (pai != null && !pai.isPackageAssociationAllowed(pkg2)) {
+ return false;
}
- pkgs = mAllowedAssociations.get(pkg2);
- if (pkgs != null) {
- return pkgs.contains(pkg1);
+ pai = mAllowedAssociations.get(pkg2);
+ if (pai != null && !pai.isPackageAssociationAllowed(pkg1)) {
+ return false;
}
// If no explicit associations are provided in the manifest, then assume the app is
// allowed associations with any package.
return true;
}
+ /** Sets up allowed associations for system prebuilt packages from system config (if needed). */
+ private void ensureAllowedAssociations() {
+ if (mAllowedAssociations == null) {
+ ArrayMap<String, ArraySet<String>> allowedAssociations =
+ SystemConfig.getInstance().getAllowedAssociations();
+ mAllowedAssociations = new ArrayMap<>(allowedAssociations.size());
+ PackageManagerInternal pm = getPackageManagerInternalLocked();
+ for (int i = 0; i < allowedAssociations.size(); i++) {
+ final String pkg = allowedAssociations.keyAt(i);
+ final ArraySet<String> asc = allowedAssociations.valueAt(i);
+
+ // Query latest debuggable flag from package-manager.
+ boolean isDebuggable = false;
+ try {
+ ApplicationInfo ai = AppGlobals.getPackageManager()
+ .getApplicationInfo(pkg, MATCH_ALL, 0);
+ if (ai != null) {
+ isDebuggable = (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
+ }
+ } catch (RemoteException e) {
+ /* ignore */
+ }
+ mAllowedAssociations.put(pkg, new PackageAssociationInfo(pkg, asc, isDebuggable));
+ }
+ }
+ }
+
+ /** Updates allowed associations for app info (specifically, based on debuggability). */
+ private void updateAssociationForApp(ApplicationInfo appInfo) {
+ ensureAllowedAssociations();
+ PackageAssociationInfo pai = mAllowedAssociations.get(appInfo.packageName);
+ if (pai != null) {
+ pai.setDebuggable((appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0);
+ }
+ }
+
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
@@ -10628,7 +10695,6 @@
ProtoUtils.toDuration(proto, ActivityManagerServiceDumpProcessesProto.LAST_IDLE_TIME, mLastIdleTime, now);
proto.write(ActivityManagerServiceDumpProcessesProto.LOW_RAM_SINCE_LAST_IDLE_MS, getLowRamTimeSinceIdle(now));
}
-
}
void writeProcessesToGcToProto(ProtoOutputStream proto, long fieldId, String dumpPackage) {
@@ -10910,14 +10976,14 @@
void dumpAllowedAssociationsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
int opti, boolean dumpAll, String dumpPackage) {
boolean needSep = false;
- boolean printedAnything = false;
pw.println("ACTIVITY MANAGER ALLOWED ASSOCIATION STATE (dumpsys activity allowed-associations)");
boolean printed = false;
if (mAllowedAssociations != null) {
for (int i = 0; i < mAllowedAssociations.size(); i++) {
final String pkg = mAllowedAssociations.keyAt(i);
- final ArraySet<String> asc = mAllowedAssociations.valueAt(i);
+ final ArraySet<String> asc =
+ mAllowedAssociations.valueAt(i).getAllowedPackageAssociations();
boolean printedHeader = false;
for (int j = 0; j < asc.size(); j++) {
if (dumpPackage == null || pkg.equals(dumpPackage)
@@ -10926,7 +10992,6 @@
pw.println(" Allowed associations (by restricted package):");
printed = true;
needSep = true;
- printedAnything = true;
}
if (!printedHeader) {
pw.print(" * ");
@@ -10938,6 +11003,9 @@
pw.println(asc.valueAt(j));
}
}
+ if (mAllowedAssociations.valueAt(i).isDebuggable()) {
+ pw.println(" (debuggable)");
+ }
}
}
if (!printed) {
@@ -14519,6 +14587,7 @@
+ " ssp=" + ssp + " data=" + data);
return ActivityManager.BROADCAST_SUCCESS;
}
+ updateAssociationForApp(aInfo);
mAtmInternal.onPackageReplaced(aInfo);
mServices.updateServiceApplicationInfoLocked(aInfo);
sendPackageBroadcastLocked(ApplicationThreadConstants.PACKAGE_REPLACED,
@@ -17798,6 +17867,15 @@
public void clearPendingBackup(int userId) {
ActivityManagerService.this.clearPendingBackup(userId);
}
+
+ /**
+ * When power button is very long pressed, call this interface to do some pre-shutdown work
+ * like persisting database etc.
+ */
+ @Override
+ public void prepareForPossibleShutdown() {
+ ActivityManagerService.this.prepareForPossibleShutdown();
+ }
}
long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) {
@@ -18054,6 +18132,18 @@
}
}
+ /**
+ * When power button is very long pressed, call this interface to do some pre-shutdown work
+ * like persisting database etc.
+ */
+ public void prepareForPossibleShutdown() {
+ synchronized (this) {
+ if (mUsageStatsService != null) {
+ mUsageStatsService.prepareForPossibleShutdown();
+ }
+ }
+ }
+
@VisibleForTesting
public static class Injector {
private NetworkManagementInternal mNmi;
diff --git a/services/core/java/com/android/server/am/AppCompactor.java b/services/core/java/com/android/server/am/AppCompactor.java
index aee16c3..fe27c49 100644
--- a/services/core/java/com/android/server/am/AppCompactor.java
+++ b/services/core/java/com/android/server/am/AppCompactor.java
@@ -44,7 +44,11 @@
*/
final ArrayList<ProcessRecord> mPendingCompactionProcesses = new ArrayList<ProcessRecord>();
- /*
+ static final int COMPACT_PROCESS_SOME = 1;
+ static final int COMPACT_PROCESS_FULL = 2;
+ static final int COMPACT_PROCESS_MSG = 1;
+
+ /**
* This thread must be moved to the system background cpuset.
* If that doesn't happen, it's probably going to draw a lot of power.
* However, this has to happen after the first updateOomAdjLocked, because
@@ -53,13 +57,22 @@
*/
final ServiceThread mCompactionThread;
- static final int COMPACT_PROCESS_SOME = 1;
- static final int COMPACT_PROCESS_FULL = 2;
- static final int COMPACT_PROCESS_MSG = 1;
- final Handler mCompactionHandler;
+ final private Handler mCompactionHandler;
- final ActivityManagerService mAm;
- final ActivityManagerConstants mConstants;
+ final private ActivityManagerService mAm;
+ final private ActivityManagerConstants mConstants;
+
+ final private String COMPACT_ACTION_FILE = "file";
+ final private String COMPACT_ACTION_ANON = "anon";
+ final private String COMPACT_ACTION_FULL = "full";
+
+ final private String compactActionSome;
+ final private String compactActionFull;
+
+ final private long throttleSomeSome;
+ final private long throttleSomeFull;
+ final private long throttleFullSome;
+ final private long throttleFullFull;
public AppCompactor(ActivityManagerService am) {
mAm = am;
@@ -69,6 +82,41 @@
THREAD_PRIORITY_FOREGROUND, true);
mCompactionThread.start();
mCompactionHandler = new MemCompactionHandler(this);
+
+ switch(mConstants.COMPACT_ACTION_1) {
+ case 1:
+ compactActionSome = COMPACT_ACTION_FILE;
+ break;
+ case 2:
+ compactActionSome = COMPACT_ACTION_ANON;
+ break;
+ case 3:
+ compactActionSome = COMPACT_ACTION_FULL;
+ break;
+ default:
+ compactActionSome = COMPACT_ACTION_FILE;
+ break;
+ }
+
+ switch(mConstants.COMPACT_ACTION_2) {
+ case 1:
+ compactActionFull = COMPACT_ACTION_FILE;
+ break;
+ case 2:
+ compactActionFull = COMPACT_ACTION_ANON;
+ break;
+ case 3:
+ compactActionFull = COMPACT_ACTION_FULL;
+ break;
+ default:
+ compactActionFull = COMPACT_ACTION_FULL;
+ break;
+ }
+
+ throttleSomeSome = mConstants.COMPACT_THROTTLE_1;
+ throttleSomeFull = mConstants.COMPACT_THROTTLE_2;
+ throttleFullSome = mConstants.COMPACT_THROTTLE_3;
+ throttleFullFull = mConstants.COMPACT_THROTTLE_4;
}
// Must be called while holding AMS lock.
@@ -128,18 +176,16 @@
}
// basic throttling
+ // use the ActivityManagerConstants knobs to determine whether current/prevous
+ // compaction combo should be throtted or not
if (pendingAction == COMPACT_PROCESS_SOME) {
- // if we're compacting some, then compact if >10s after last full
- // or >5s after last some
- if ((lastCompactAction == COMPACT_PROCESS_SOME && (start - lastCompactTime < 5000)) ||
- (lastCompactAction == COMPACT_PROCESS_FULL && (start - lastCompactTime < 10000))) {
+ if ((lastCompactAction == COMPACT_PROCESS_SOME && (start - lastCompactTime < throttleSomeSome)) ||
+ (lastCompactAction == COMPACT_PROCESS_FULL && (start - lastCompactTime < throttleSomeFull))) {
return;
}
} else {
- // if we're compacting full, then compact if >10s after last full
- // or >.5s after last some
- if ((lastCompactAction == COMPACT_PROCESS_SOME && (start - lastCompactTime < 500)) ||
- (lastCompactAction == COMPACT_PROCESS_FULL && (start - lastCompactTime < 10000))) {
+ if ((lastCompactAction == COMPACT_PROCESS_SOME && (start - lastCompactTime < throttleFullSome)) ||
+ (lastCompactAction == COMPACT_PROCESS_FULL && (start - lastCompactTime < throttleFullFull))) {
return;
}
}
@@ -151,9 +197,9 @@
long[] rssBefore = Process.getRss(pid);
FileOutputStream fos = new FileOutputStream("/proc/" + pid + "/reclaim");
if (pendingAction == COMPACT_PROCESS_SOME) {
- action = "file";
+ action = compactActionSome;
} else {
- action = "all";
+ action = compactActionFull;
}
fos.write(action.getBytes());
fos.close();
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index d7cb2bd..d3953b5 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -67,9 +67,10 @@
sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_LAYERS_GLES, String.class);
sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_LAYER_APP, String.class);
sGlobalSettingToTypeMap.put(Settings.Global.SMS_ACCESS_RESTRICTION_ENABLED, int.class);
+ sGlobalSettingToTypeMap.put(Settings.Global.GUP_DEV_ALL_APPS, int.class);
sGlobalSettingToTypeMap.put(Settings.Global.GUP_DEV_OPT_IN_APPS, String.class);
sGlobalSettingToTypeMap.put(Settings.Global.GUP_DEV_OPT_OUT_APPS, String.class);
- sGlobalSettingToTypeMap.put(Settings.Global.GUP_BLACK_LIST, String.class);
+ sGlobalSettingToTypeMap.put(Settings.Global.GUP_BLACKLIST, String.class);
// add other global settings here...
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index d704a3e..9a4ca1f 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -7824,8 +7824,10 @@
/** see AudioPolicy.setUidDeviceAffinity() */
public int setUidDeviceAffinity(IAudioPolicyCallback pcb, int uid,
- @NonNull int[] deviceTypes,
- @NonNull String[] deviceAddresses) {
+ @NonNull int[] deviceTypes, @NonNull String[] deviceAddresses) {
+ if (DEBUG_AP) {
+ Log.d(TAG, "setUidDeviceAffinity for " + pcb.asBinder() + " uid:" + uid);
+ }
synchronized (mAudioPolicies) {
final AudioPolicyProxy app =
checkUpdateForPolicy(pcb, "Cannot change device affinity in audio policy");
@@ -7835,21 +7837,23 @@
if (!app.hasMixRoutedToDevices(deviceTypes, deviceAddresses)) {
return AudioManager.ERROR;
}
+ return app.setUidDeviceAffinities(uid, deviceTypes, deviceAddresses);
}
- return AudioManager.SUCCESS;
}
/** see AudioPolicy.removeUidDeviceAffinity() */
public int removeUidDeviceAffinity(IAudioPolicyCallback pcb, int uid) {
+ if (DEBUG_AP) {
+ Log.d(TAG, "removeUidDeviceAffinity for " + pcb.asBinder() + " uid:" + uid);
+ }
synchronized (mAudioPolicies) {
final AudioPolicyProxy app =
checkUpdateForPolicy(pcb, "Cannot remove device affinity in audio policy");
if (app == null) {
return AudioManager.ERROR;
}
-
+ return app.removeUidDeviceAffinities(uid);
}
- return AudioManager.SUCCESS;
}
public int setFocusPropertiesForPolicy(int duckingBehavior, IAudioPolicyCallback pcb) {
@@ -8160,27 +8164,41 @@
Binder.restoreCallingIdentity(identity);
}
- void setUidDeviceAffinities(int uid, @NonNull int[] types, @NonNull String[] addresses) {
+ int setUidDeviceAffinities(int uid, @NonNull int[] types, @NonNull String[] addresses) {
final Integer Uid = new Integer(uid);
+ int res;
if (mUidDeviceAffinities.remove(Uid) != null) {
final long identity = Binder.clearCallingIdentity();
- AudioSystem.removeUidDeviceAffinities(uid);
+ res = AudioSystem.removeUidDeviceAffinities(uid);
Binder.restoreCallingIdentity(identity);
+ if (res != AudioSystem.SUCCESS) {
+ Log.e(TAG, "AudioSystem. removeUidDeviceAffinities(" + uid + ") failed, "
+ + " cannot call AudioSystem.setUidDeviceAffinities");
+ return AudioManager.ERROR;
+ }
}
final long identity = Binder.clearCallingIdentity();
- final int res = AudioSystem.setUidDeviceAffinities(uid, types, addresses);
+ res = AudioSystem.setUidDeviceAffinities(uid, types, addresses);
Binder.restoreCallingIdentity(identity);
if (res == AudioSystem.SUCCESS) {
mUidDeviceAffinities.put(Uid, new AudioDeviceArray(types, addresses));
+ return AudioManager.SUCCESS;
}
+ Log.e(TAG, "AudioSystem. setUidDeviceAffinities(" + uid + ") failed");
+ return AudioManager.ERROR;
}
- void removeUidDeviceAffinities(int uid, @NonNull int[] types, @NonNull String[] addresses) {
+ int removeUidDeviceAffinities(int uid) {
if (mUidDeviceAffinities.remove(new Integer(uid)) != null) {
final long identity = Binder.clearCallingIdentity();
- AudioSystem.removeUidDeviceAffinities(uid);
+ final int res = AudioSystem.removeUidDeviceAffinities(uid);
Binder.restoreCallingIdentity(identity);
+ if (res == AudioSystem.SUCCESS) {
+ return AudioManager.SUCCESS;
+ }
}
+ Log.e(TAG, "AudioSystem. removeUidDeviceAffinities failed");
+ return AudioManager.ERROR;
}
};
diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
index ecc3d2d..174ecfa 100644
--- a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
+++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
@@ -116,6 +116,7 @@
protected HashMap<Integer, PerformanceStats> mPerformanceMap = new HashMap<>();
// Transactions that make use of CryptoObjects are tracked by mCryptoPerformaceMap.
protected HashMap<Integer, PerformanceStats> mCryptoPerformanceMap = new HashMap<>();
+ protected int mHALDeathCount;
protected class PerformanceStats {
public int accept; // number of accepted biometrics
@@ -596,6 +597,7 @@
public void serviceDied(long cookie) {
Slog.e(getTag(), "HAL died");
mMetricsLogger.count(getMetrics().tagHalDied(), 1);
+ mHALDeathCount++;
handleError(getHalDeviceId(), BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
0 /*vendorCode */);
}
diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java
index 5a9c1ac..a2aacdd 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -675,6 +675,12 @@
}
@Override
+ public void serviceDied(long cookie) {
+ super.serviceDied(cookie);
+ mDaemon = null;
+ }
+
+ @Override
protected void updateActiveGroup(int userId, String clientPackage) {
IBiometricsFace daemon = getFaceDaemon();
@@ -864,6 +870,8 @@
Slog.e(TAG, "dump formatting failure", e);
}
pw.println(dump);
+ pw.println("HAL Deaths: " + mHALDeathCount);
+ mHALDeathCount = 0;
}
private void dumpProto(FileDescriptor fd) {
diff --git a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
index 1613dc9..3db6a74 100644
--- a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
@@ -777,6 +777,12 @@
}
@Override
+ public void serviceDied(long cookie) {
+ super.serviceDied(cookie);
+ mDaemon = null;
+ }
+
+ @Override
protected void updateActiveGroup(int userId, String clientPackage) {
IBiometricsFingerprint daemon = getFingerprintDaemon();
@@ -1074,6 +1080,8 @@
Slog.e(TAG, "dump formatting failure", e);
}
pw.println(dump);
+ pw.println("HAL Deaths: " + mHALDeathCount);
+ mHALDeathCount = 0;
}
private void dumpProto(FileDescriptor fd) {
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index 6596d27..9d9b1cf 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -16,8 +16,9 @@
package com.android.server.connectivity;
-import android.net.InterfaceConfiguration;
import android.net.ConnectivityManager;
+import android.net.INetd;
+import android.net.InterfaceConfiguration;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.NetworkInfo;
@@ -59,6 +60,7 @@
NetworkInfo.State.SUSPENDED,
};
+ private final INetd mNetd;
private final INetworkManagementService mNMService;
// The network we're running on, and its type.
@@ -76,7 +78,8 @@
private String mIface;
private State mState = State.IDLE;
- public Nat464Xlat(INetworkManagementService nmService, NetworkAgentInfo nai) {
+ public Nat464Xlat(NetworkAgentInfo nai, INetd netd, INetworkManagementService nmService) {
+ mNetd = netd;
mNMService = nmService;
mNetwork = nai;
}
@@ -140,7 +143,7 @@
return;
}
try {
- mNMService.startClatd(baseIface);
+ mNetd.clatdStart(baseIface);
} catch(RemoteException|IllegalStateException e) {
Slog.e(TAG, "Error starting clatd on " + baseIface, e);
}
@@ -162,7 +165,7 @@
*/
private void enterStoppingState() {
try {
- mNMService.stopClatd(mBaseIface);
+ mNetd.clatdStop(mBaseIface);
} catch(RemoteException|IllegalStateException e) {
Slog.e(TAG, "Error stopping clatd on " + mBaseIface, e);
}
@@ -204,7 +207,7 @@
Slog.e(TAG, "startClat: Can't start clat on null interface");
return;
}
- // TODO: should we only do this if mNMService.startClatd() succeeds?
+ // TODO: should we only do this if mNetd.clatdStart() succeeds?
Slog.i(TAG, "Starting clatd on " + baseIface);
enterStartingState(baseIface);
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 54c89aa..9ea73fb 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -17,6 +17,7 @@
package com.android.server.connectivity;
import android.content.Context;
+import android.net.INetd;
import android.net.INetworkMonitor;
import android.net.LinkProperties;
import android.net.Network;
@@ -239,12 +240,15 @@
private static final String TAG = ConnectivityService.class.getSimpleName();
private static final boolean VDBG = false;
private final ConnectivityService mConnService;
+ private final INetd mNetd;
+ private final INetworkManagementService mNMS;
private final Context mContext;
private final Handler mHandler;
public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, Network net, NetworkInfo info,
LinkProperties lp, NetworkCapabilities nc, int score, Context context, Handler handler,
- NetworkMisc misc, ConnectivityService connService) {
+ NetworkMisc misc, ConnectivityService connService, INetd netd,
+ INetworkManagementService nms) {
this.messenger = messenger;
asyncChannel = ac;
network = net;
@@ -253,6 +257,8 @@
networkCapabilities = nc;
currentScore = score;
mConnService = connService;
+ mNetd = netd;
+ mNMS = nms;
mContext = context;
mHandler = handler;
networkMisc = misc;
@@ -587,18 +593,18 @@
public void updateClat(INetworkManagementService netd) {
if (Nat464Xlat.requiresClat(this)) {
- maybeStartClat(netd);
+ maybeStartClat();
} else {
maybeStopClat();
}
}
/** Ensure clat has started for this network. */
- public void maybeStartClat(INetworkManagementService netd) {
+ public void maybeStartClat() {
if (clatd != null && clatd.isStarted()) {
return;
}
- clatd = new Nat464Xlat(netd, this);
+ clatd = new Nat464Xlat(this, mNetd, mNMS);
clatd.start();
}
diff --git a/services/core/java/com/android/server/content/SyncJobService.java b/services/core/java/com/android/server/content/SyncJobService.java
index bfcc629..aaf9cbc 100644
--- a/services/core/java/com/android/server/content/SyncJobService.java
+++ b/services/core/java/com/android/server/content/SyncJobService.java
@@ -141,10 +141,7 @@
final long runtime = nowUptime - startUptime;
- if (startUptime == 0) {
- wtf("Job " + jobId + " start uptime not found: "
- + " params=" + jobParametersToString(params));
- } else if (runtime > 60 * 1000) {
+ if (runtime > 60 * 1000) {
// WTF if startSyncH() hasn't happened, *unless* onStopJob() was called too soon.
// (1 minute threshold.)
// Also don't wtf when it's not ready to sync.
diff --git a/services/core/java/com/android/server/content/SyncLogger.java b/services/core/java/com/android/server/content/SyncLogger.java
index 5cbe5b9..fc20ef20 100644
--- a/services/core/java/com/android/server/content/SyncLogger.java
+++ b/services/core/java/com/android/server/content/SyncLogger.java
@@ -16,6 +16,7 @@
package com.android.server.content;
+import android.accounts.Account;
import android.app.job.JobParameters;
import android.os.Build;
import android.os.Environment;
@@ -31,6 +32,8 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IntPair;
import com.android.server.IoThread;
+import com.android.server.content.SyncManager.ActiveSyncContext;
+import com.android.server.content.SyncStorageEngine.EndPoint;
import libcore.io.IoUtils;
@@ -309,4 +312,20 @@
}
}
}
+
+ static String logSafe(Account account) {
+ return account == null ? "[null]" : account.toSafeString();
+ }
+
+ static String logSafe(EndPoint endPoint) {
+ return endPoint == null ? "[null]" : endPoint.toSafeString();
+ }
+
+ static String logSafe(SyncOperation operation) {
+ return operation == null ? "[null]" : operation.toSafeString();
+ }
+
+ static String logSafe(ActiveSyncContext asc) {
+ return asc == null ? "[null]" : asc.toSafeString();
+ }
}
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 8b93e04..7096477 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -16,6 +16,8 @@
package com.android.server.content;
+import static com.android.server.content.SyncLogger.logSafe;
+
import android.accounts.Account;
import android.accounts.AccountAndUser;
import android.accounts.AccountManager;
@@ -1140,7 +1142,7 @@
/* ignore - local call */
}
if (checkAccountAccess && !canAccessAccount(account, owningPackage, owningUid)) {
- Log.w(TAG, "Access to " + account + " denied for package "
+ Log.w(TAG, "Access to " + logSafe(account) + " denied for package "
+ owningPackage + " in UID " + syncAdapterInfo.uid);
return AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS;
}
@@ -1474,7 +1476,8 @@
if (!syncOperation.ignoreBackoff()) {
Pair<Long, Long> backoff = mSyncStorageEngine.getBackoff(syncOperation.target);
if (backoff == null) {
- Slog.e(TAG, "Couldn't find backoff values for " + syncOperation.target);
+ Slog.e(TAG, "Couldn't find backoff values for "
+ + logSafe(syncOperation.target));
backoff = new Pair<Long, Long>(SyncStorageEngine.NOT_IN_BACKOFF_MODE,
SyncStorageEngine.NOT_IN_BACKOFF_MODE);
}
@@ -1745,8 +1748,8 @@
scheduleSyncOperationH(operation);
} else {
// Otherwise do not reschedule.
- Log.d(TAG, "not retrying sync operation because the error is a hard error: "
- + operation);
+ Log.e(TAG, "not retrying sync operation because the error is a hard error: "
+ + logSafe(operation));
}
}
@@ -1881,11 +1884,12 @@
sendSyncFinishedOrCanceledMessage(this, result);
}
- public void toString(StringBuilder sb) {
+ public void toString(StringBuilder sb, boolean logSafe) {
sb.append("startTime ").append(mStartTime)
.append(", mTimeoutStartTime ").append(mTimeoutStartTime)
.append(", mHistoryRowId ").append(mHistoryRowId)
- .append(", syncOperation ").append(mSyncOperation);
+ .append(", syncOperation ").append(
+ logSafe ? logSafe(mSyncOperation) : mSyncOperation);
}
public void onServiceConnected(ComponentName name, IBinder service) {
@@ -1947,7 +1951,13 @@
public String toString() {
StringBuilder sb = new StringBuilder();
- toString(sb);
+ toString(sb, false);
+ return sb.toString();
+ }
+
+ public String toSafeString() {
+ StringBuilder sb = new StringBuilder();
+ toString(sb, true);
return sb.toString();
}
@@ -2036,7 +2046,7 @@
int count = 0;
for (SyncOperation op: pendingSyncs) {
if (!op.isPeriodic) {
- pw.println(op.dump(null, false, buckets));
+ pw.println(op.dump(null, false, buckets, /*logSafe=*/ false));
count++;
}
}
@@ -2053,7 +2063,7 @@
int count = 0;
for (SyncOperation op: pendingSyncs) {
if (op.isPeriodic) {
- pw.println(op.dump(null, false, buckets));
+ pw.println(op.dump(null, false, buckets, /*logSafe=*/ false));
count++;
}
}
@@ -2186,7 +2196,7 @@
sb.setLength(0);
pw.print(formatDurationHMS(sb, durationInSeconds));
pw.print(" - ");
- pw.print(activeSyncContext.mSyncOperation.dump(pm, false, buckets));
+ pw.print(activeSyncContext.mSyncOperation.dump(pm, false, buckets, /*logSafe=*/ false));
pw.println();
}
pw.println();
@@ -2974,7 +2984,7 @@
case SyncHandler.MESSAGE_CANCEL:
SyncStorageEngine.EndPoint endpoint = (SyncStorageEngine.EndPoint) msg.obj;
Bundle extras = msg.peekData();
- if (Log.isLoggable(TAG, Log.DEBUG)) {
+ if (isLoggable) {
Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_CANCEL: "
+ endpoint + " bundle: " + extras);
}
@@ -2985,9 +2995,11 @@
SyncFinishedOrCancelledMessagePayload payload =
(SyncFinishedOrCancelledMessagePayload) msg.obj;
if (!isSyncStillActiveH(payload.activeSyncContext)) {
- Log.d(TAG, "handleSyncHandlerMessage: dropping since the "
- + "sync is no longer active: "
- + payload.activeSyncContext);
+ if (isLoggable) {
+ Log.d(TAG, "handleSyncHandlerMessage: dropping since the "
+ + "sync is no longer active: "
+ + payload.activeSyncContext);
+ }
break;
}
if (isLoggable) {
@@ -3002,7 +3014,7 @@
case SyncHandler.MESSAGE_SERVICE_CONNECTED: {
ServiceConnectionData msgData = (ServiceConnectionData) msg.obj;
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ if (isLoggable) {
Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_SERVICE_CONNECTED: "
+ msgData.activeSyncContext);
}
@@ -3018,7 +3030,7 @@
case SyncHandler.MESSAGE_SERVICE_DISCONNECTED: {
final ActiveSyncContext currentSyncContext =
((ServiceConnectionData) msg.obj).activeSyncContext;
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ if (isLoggable) {
Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_SERVICE_DISCONNECTED: "
+ currentSyncContext);
}
@@ -3053,7 +3065,7 @@
case SyncHandler.MESSAGE_MONITOR_SYNC:
ActiveSyncContext monitoredSyncContext = (ActiveSyncContext) msg.obj;
- if (Log.isLoggable(TAG, Log.DEBUG)) {
+ if (isLoggable) {
Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_MONITOR_SYNC: " +
monitoredSyncContext.mSyncOperation.target);
}
@@ -3061,7 +3073,7 @@
if (isSyncNotUsingNetworkH(monitoredSyncContext)) {
Log.w(TAG, String.format(
"Detected sync making no progress for %s. cancelling.",
- monitoredSyncContext));
+ logSafe(monitoredSyncContext)));
SyncJobService.callJobFinished(
monitoredSyncContext.mSyncOperation.jobId, false,
"no network activity");
@@ -3558,7 +3570,8 @@
} catch (RuntimeException exc) {
mLogger.log("Sync failed with RuntimeException: ", exc.toString());
closeActiveSyncContext(activeSyncContext);
- Slog.e(TAG, "Caught RuntimeException while starting the sync " + syncOperation, exc);
+ Slog.e(TAG, "Caught RuntimeException while starting the sync "
+ + logSafe(syncOperation), exc);
}
}
@@ -3658,7 +3671,8 @@
reschedulePeriodicSyncH(syncOperation);
}
} else {
- Log.w(TAG, "failed sync operation " + syncOperation + ", " + syncResult);
+ Log.w(TAG, "failed sync operation "
+ + logSafe(syncOperation) + ", " + syncResult);
syncOperation.retries++;
if (syncOperation.retries > mConstants.getMaxRetriesWithAppStandbyExemption()) {
@@ -4042,11 +4056,6 @@
getJobScheduler().cancel(op.jobId);
}
- private void wtfWithLog(String message) {
- Slog.wtf(TAG, message);
- mLogger.log("WTF: ", message);
- }
-
public void resetTodayStats() {
mSyncStorageEngine.resetTodayStats(/*force=*/ true);
}
diff --git a/services/core/java/com/android/server/content/SyncOperation.java b/services/core/java/com/android/server/content/SyncOperation.java
index 25edf40..2abc2e6 100644
--- a/services/core/java/com/android/server/content/SyncOperation.java
+++ b/services/core/java/com/android/server/content/SyncOperation.java
@@ -363,14 +363,19 @@
@Override
public String toString() {
- return dump(null, true, null);
+ return dump(null, true, null, false);
}
- String dump(PackageManager pm, boolean shorter, SyncAdapterStateFetcher appStates) {
+ public String toSafeString() {
+ return dump(null, true, null, true);
+ }
+
+ String dump(PackageManager pm, boolean shorter, SyncAdapterStateFetcher appStates,
+ boolean logSafe) {
StringBuilder sb = new StringBuilder();
sb.append("JobId=").append(jobId)
.append(" ")
- .append(target.account.name)
+ .append(logSafe ? "***" : target.account.name)
.append("/")
.append(target.account.type)
.append(" u")
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index bfd1791..6b441a0 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -16,6 +16,8 @@
package com.android.server.content;
+import static com.android.server.content.SyncLogger.logSafe;
+
import android.accounts.Account;
import android.accounts.AccountAndUser;
import android.accounts.AccountManager;
@@ -225,6 +227,15 @@
sb.append(":u" + userId);
return sb.toString();
}
+
+ public String toSafeString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(account == null ? "ALL ACCS" : logSafe(account))
+ .append("/")
+ .append(provider == null ? "ALL PDRS" : provider);
+ sb.append(":u" + userId);
+ return sb.toString();
+ }
}
public static class AuthorityInfo {
@@ -1861,8 +1872,8 @@
}
} else {
- Slog.w(TAG, "Failure adding authority: account="
- + accountName + " auth=" + authorityName
+ Slog.w(TAG, "Failure adding authority:"
+ + " auth=" + authorityName
+ " enabled=" + enabled
+ " syncable=" + syncable);
}
diff --git a/services/core/java/com/android/server/display/ColorDisplayService.java b/services/core/java/com/android/server/display/ColorDisplayService.java
index b332c47..2fe17d8 100644
--- a/services/core/java/com/android/server/display/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/ColorDisplayService.java
@@ -34,8 +34,10 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
+import android.content.res.Resources;
import android.database.ContentObserver;
import android.hardware.display.ColorDisplayManager;
+import android.graphics.ColorSpace;
import android.hardware.display.IColorDisplayManager;
import android.net.Uri;
import android.opengl.Matrix;
@@ -59,6 +61,7 @@
import com.android.server.twilight.TwilightManager;
import com.android.server.twilight.TwilightState;
+import java.io.PrintWriter;
import java.time.DateTimeException;
import java.time.Instant;
import java.time.LocalDateTime;
@@ -148,26 +151,204 @@
};
private final TintController mDisplayWhiteBalanceTintController = new TintController() {
+ // Three chromaticity coordinates per color: X, Y, and Z
+ private final int NUM_VALUES_PER_PRIMARY = 3;
+ // Four colors: red, green, blue, and white
+ private final int NUM_DISPLAY_PRIMARIES_VALS = 4 * NUM_VALUES_PER_PRIMARY;
+ private final Object mLock = new Object();
+ private int mTemperatureMin;
+ private int mTemperatureMax;
+ private int mTemperatureDefault;
+ private float[] mDisplayNominalWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
+ private ColorSpace.Rgb mDisplayColorSpaceRGB;
+ private float[] mChromaticAdaptationMatrix;
+ private int mCurrentColorTemperature;
+ private float[] mCurrentColorTemperatureXYZ;
+ private boolean mSetUp = false;
private float[] mMatrixDisplayWhiteBalance = new float[16];
@Override
public void setUp(Context context, boolean needsLinear) {
+ mSetUp = false;
+
+ final Resources res = getContext().getResources();
+ final String[] displayPrimariesValues = res.getStringArray(
+ R.array.config_displayWhiteBalanceDisplayPrimaries);
+ final String[] nominalWhiteValues = res.getStringArray(
+ R.array.config_displayWhiteBalanceDisplayNominalWhite);
+
+ if (displayPrimariesValues.length != NUM_DISPLAY_PRIMARIES_VALS) {
+ Slog.e(TAG, "Unexpected display white balance primaries resource length " +
+ displayPrimariesValues.length);
+ return;
+ }
+
+ if (nominalWhiteValues.length != NUM_VALUES_PER_PRIMARY) {
+ Slog.e(TAG, "Unexpected display white balance nominal white resource length " +
+ nominalWhiteValues.length);
+ return;
+ }
+
+ float[] displayRedGreenBlueXYZ =
+ new float[NUM_DISPLAY_PRIMARIES_VALS - NUM_VALUES_PER_PRIMARY];
+ float[] displayWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
+ for (int i = 0; i < displayRedGreenBlueXYZ.length; i++) {
+ displayRedGreenBlueXYZ[i] = Float.parseFloat(displayPrimariesValues[i]);
+ }
+ for (int i = 0; i < displayWhiteXYZ.length; i++) {
+ displayWhiteXYZ[i] = Float.parseFloat(
+ displayPrimariesValues[displayRedGreenBlueXYZ.length + i]);
+ }
+
+ final ColorSpace.Rgb displayColorSpaceRGB = new ColorSpace.Rgb(
+ "Display Color Space",
+ displayRedGreenBlueXYZ,
+ displayWhiteXYZ,
+ 2.2f // gamma, unused for display white balance
+ );
+
+ float[] displayNominalWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
+ for (int i = 0; i < nominalWhiteValues.length; i++) {
+ displayNominalWhiteXYZ[i] = Float.parseFloat(nominalWhiteValues[i]);
+ }
+
+ final int colorTemperatureMin = res.getInteger(
+ R.integer.config_displayWhiteBalanceColorTemperatureMin);
+ if (colorTemperatureMin <= 0) {
+ Slog.e(TAG, "display white balance minimum temperature must be greater than 0");
+ return;
+ }
+
+ final int colorTemperatureMax = res.getInteger(
+ R.integer.config_displayWhiteBalanceColorTemperatureMax);
+ if (colorTemperatureMax < colorTemperatureMin) {
+ Slog.e(TAG, "display white balance max temp must be greater or equal to min");
+ return;
+ }
+
+ final int colorTemperature = res.getInteger(
+ R.integer.config_displayWhiteBalanceColorTemperatureDefault);
+
+ synchronized (mLock) {
+ mDisplayColorSpaceRGB = displayColorSpaceRGB;
+ mDisplayNominalWhiteXYZ = displayNominalWhiteXYZ;
+ mTemperatureMin = colorTemperatureMin;
+ mTemperatureMax = colorTemperatureMax;
+ mTemperatureDefault = colorTemperature;
+ mSetUp = true;
+ }
+
+ setMatrix(mTemperatureDefault);
}
@Override
public float[] getMatrix() {
- return isActivated() ? mMatrixDisplayWhiteBalance : MATRIX_IDENTITY;
+ return mSetUp && isActivated() ? mMatrixDisplayWhiteBalance : MATRIX_IDENTITY;
}
@Override
public void setMatrix(int cct) {
+ if (!mSetUp) {
+ Slog.w(TAG, "Can't set display white balance temperature: uninitialized");
+ return;
+ }
+
+ if (cct < mTemperatureMin) {
+ Slog.w(TAG, "Requested display color temperature is below allowed minimum");
+ cct = mTemperatureMin;
+ } else if (cct > mTemperatureMax) {
+ Slog.w(TAG, "Requested display color temperature is above allowed maximum");
+ cct = mTemperatureMax;
+ }
+
+ Slog.d(TAG, "setDisplayWhiteBalanceTemperatureMatrix: cct = " + cct);
+
+ synchronized (mLock) {
+ mCurrentColorTemperature = cct;
+
+ // Adapt the display's nominal white point to match the requested CCT value
+ mCurrentColorTemperatureXYZ = ColorSpace.cctToIlluminantdXyz(cct);
+
+ mChromaticAdaptationMatrix =
+ ColorSpace.chromaticAdaptation(ColorSpace.Adaptation.BRADFORD,
+ mDisplayNominalWhiteXYZ, mCurrentColorTemperatureXYZ);
+
+ // Convert the adaptation matrix to RGB space
+ float[] result = ColorSpace.mul3x3(mChromaticAdaptationMatrix,
+ mDisplayColorSpaceRGB.getTransform());
+ result = ColorSpace.mul3x3(mDisplayColorSpaceRGB.getInverseTransform(), result);
+
+ // Normalize the transform matrix to peak white value in RGB space
+ final float adaptedMaxR = result[0] + result[3] + result[6];
+ final float adaptedMaxG = result[1] + result[4] + result[7];
+ final float adaptedMaxB = result[2] + result[5] + result[8];
+ final float denum = Math.max(Math.max(adaptedMaxR, adaptedMaxG), adaptedMaxB);
+ for (int i = 0; i < result.length; i++) {
+ result[i] /= denum;
+ }
+
+ Matrix.setIdentityM(mMatrixDisplayWhiteBalance, 0);
+ java.lang.System.arraycopy(result, 0, mMatrixDisplayWhiteBalance, 0, 3);
+ java.lang.System.arraycopy(result, 3, mMatrixDisplayWhiteBalance, 4, 3);
+ java.lang.System.arraycopy(result, 6, mMatrixDisplayWhiteBalance, 8, 3);
+ }
}
@Override
public int getLevel() {
return LEVEL_COLOR_MATRIX_DISPLAY_WHITE_BALANCE;
}
+
+ /**
+ * Format a given matrix into a string.
+ *
+ * @param matrix the matrix to format
+ * @param cols number of columns in the matrix
+ */
+ private String matrixToString(float[] matrix, int cols) {
+ if (matrix == null || cols <= 0) {
+ Slog.e(TAG, "Invalid arguments when formatting matrix to string");
+ return "";
+ }
+
+ StringBuilder sb = new StringBuilder("");
+ for (int i = 0; i < matrix.length; i++) {
+ if (i % cols == 0) {
+ sb.append("\n ");
+ }
+ sb.append(String.format("%9.6f ", matrix[i]));
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public void dump(PrintWriter pw) {
+ synchronized (mLock) {
+ pw.println("ColorDisplayService");
+ pw.println(" mSetUp = " + mSetUp);
+
+ if (!mSetUp) {
+ return;
+ }
+
+ pw.println(" isActivated = " + isActivated());
+ pw.println(" mTemperatureMin = " + mTemperatureMin);
+ pw.println(" mTemperatureMax = " + mTemperatureMax);
+ pw.println(" mTemperatureDefault = " + mTemperatureDefault);
+ pw.println(" mCurrentColorTemperature = " + mCurrentColorTemperature);
+ pw.println(" mCurrentColorTemperatureXYZ = " +
+ matrixToString(mCurrentColorTemperatureXYZ, 3));
+ pw.println(" mDisplayColorSpaceRGB RGB-to-XYZ = " +
+ matrixToString(mDisplayColorSpaceRGB.getTransform(), 3));
+ pw.println(" mChromaticAdaptationMatrix = " +
+ matrixToString(mChromaticAdaptationMatrix, 3));
+ pw.println(" mDisplayColorSpaceRGB XYZ-to-RGB = " +
+ matrixToString(mDisplayColorSpaceRGB.getInverseTransform(), 3));
+ pw.println(" mMatrixDisplayWhiteBalance = " +
+ matrixToString(mMatrixDisplayWhiteBalance, 4));
+ }
+ }
};
private final TintController mGlobalSaturationTintController = new TintController() {
@@ -230,8 +411,6 @@
private NightDisplayAutoMode mNightDisplayAutoMode;
- private Integer mDisplayWhiteBalanceColorTemperature;
-
public ColorDisplayService(Context context) {
super(context);
mHandler = new TintHandler(Looper.getMainLooper());
@@ -363,7 +542,7 @@
onAccessibilityTransformChanged();
break;
case Secure.DISPLAY_WHITE_BALANCE_ENABLED:
- onDisplayWhiteBalanceEnabled(isDisplayWhiteBalanceSettingEnabled());
+ updateDisplayWhiteBalanceStatus();
break;
}
}
@@ -416,14 +595,9 @@
if (ColorDisplayManager.isDisplayWhiteBalanceAvailable(getContext())) {
// Prepare the display white balance transform matrix.
- mDisplayWhiteBalanceTintController
- .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix());
- if (mDisplayWhiteBalanceColorTemperature != null) {
- mDisplayWhiteBalanceTintController
- .setMatrix(mDisplayWhiteBalanceColorTemperature);
- }
+ mDisplayWhiteBalanceTintController.setUp(getContext(), true /* needsLinear */);
- onDisplayWhiteBalanceEnabled(isDisplayWhiteBalanceSettingEnabled());
+ updateDisplayWhiteBalanceStatus();
}
}
@@ -460,6 +634,8 @@
mNightDisplayAutoMode.onActivated(activated);
}
+ updateDisplayWhiteBalanceStatus();
+
applyTint(mNightDisplayTintController, false);
}
}
@@ -516,11 +692,7 @@
.setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix(mode));
mNightDisplayTintController.setMatrix(mNightDisplayController.getColorTemperature());
- mDisplayWhiteBalanceTintController
- .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix(mode));
- if (mDisplayWhiteBalanceColorTemperature != null) {
- mDisplayWhiteBalanceTintController.setMatrix(mDisplayWhiteBalanceColorTemperature);
- }
+ updateDisplayWhiteBalanceStatus();
final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
dtm.setColorMode(mode, mNightDisplayTintController.getMatrix());
@@ -611,10 +783,15 @@
return ldt.isBefore(compareTime) ? ldt.plusDays(1) : ldt;
}
- private void onDisplayWhiteBalanceEnabled(boolean enabled) {
- mDisplayWhiteBalanceTintController.setActivated(enabled);
- if (mDisplayWhiteBalanceListener != null) {
- mDisplayWhiteBalanceListener.onDisplayWhiteBalanceStatusChanged(enabled);
+ private void updateDisplayWhiteBalanceStatus() {
+ boolean oldActivated = mDisplayWhiteBalanceTintController.isActivated();
+ mDisplayWhiteBalanceTintController.setActivated(isDisplayWhiteBalanceSettingEnabled() &&
+ !mNightDisplayTintController.isActivated() &&
+ DisplayTransformManager.needsLinearColorMatrix());
+ boolean activated = mDisplayWhiteBalanceTintController.isActivated();
+
+ if (mDisplayWhiteBalanceListener != null && oldActivated != activated) {
+ mDisplayWhiteBalanceListener.onDisplayWhiteBalanceStatusChanged(activated);
}
}
@@ -896,6 +1073,12 @@
}
/**
+ * Dump debug information.
+ */
+ public void dump(PrintWriter pw) {
+ }
+
+ /**
* Set up any constants needed for computing the matrix.
*/
public abstract void setUp(Context context, boolean needsLinear);
@@ -929,11 +1112,10 @@
*/
public boolean setDisplayWhiteBalanceColorTemperature(int cct) {
// Update the transform matrix even if it can't be applied.
- mDisplayWhiteBalanceColorTemperature = cct;
mDisplayWhiteBalanceTintController.setMatrix(cct);
if (mDisplayWhiteBalanceTintController.isActivated()) {
- applyTint(mDisplayWhiteBalanceTintController, true);
+ applyTint(mDisplayWhiteBalanceTintController, false);
return true;
}
return false;
@@ -946,6 +1128,10 @@
mDisplayWhiteBalanceListener = listener;
return mDisplayWhiteBalanceTintController.isActivated();
}
+
+ public void dump(PrintWriter pw) {
+ mDisplayWhiteBalanceTintController.dump(pw);
+ }
}
/**
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 4a17c65..cb3f91b 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -95,6 +95,7 @@
import com.android.server.UiThread;
import com.android.server.wm.SurfaceAnimationThread;
import com.android.server.wm.WindowManagerInternal;
+import com.android.server.display.ColorDisplayService.ColorDisplayServiceInternal;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -791,6 +792,16 @@
}
}
+ private void setVirtualDisplayStateInternal(IBinder appToken, boolean isOn) {
+ synchronized (mSyncRoot) {
+ if (mVirtualDisplayAdapter == null) {
+ return;
+ }
+
+ mVirtualDisplayAdapter.setVirtualDisplayStateLocked(appToken, isOn);
+ }
+ }
+
private void registerDefaultDisplayAdapters() {
// Register default display adapters.
synchronized (mSyncRoot) {
@@ -1459,6 +1470,13 @@
pw.println();
mPersistentDataStore.dump(pw);
+
+ final ColorDisplayServiceInternal cds = LocalServices.getService(
+ ColorDisplayServiceInternal.class);
+ if (cds != null) {
+ pw.println();
+ cds.dump(pw);
+ }
}
}
@@ -1922,6 +1940,16 @@
}
@Override // Binder call
+ public void setVirtualDisplayState(IVirtualDisplayCallback callback, boolean isOn) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ setVirtualDisplayStateInternal(callback.asBinder(), isOn);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override // Binder call
public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index 5aa585f..1ca8dd3 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -147,6 +147,13 @@
return device;
}
+ void setVirtualDisplayStateLocked(IBinder appToken, boolean isOn) {
+ VirtualDisplayDevice device = mVirtualDisplayDevices.get(appToken);
+ if (device != null) {
+ device.setDisplayState(isOn);
+ }
+ }
+
/**
* Returns the next unique index for the uniqueIdPrefix
*/
@@ -206,6 +213,7 @@
private int mPendingChanges;
private int mUniqueIndex;
private Display.Mode mMode;
+ private boolean mIsDisplayOn;
public VirtualDisplayDevice(IBinder displayToken, IBinder appToken,
int ownerUid, String ownerPackageName,
@@ -226,6 +234,7 @@
mDisplayState = Display.STATE_UNKNOWN;
mPendingChanges |= PENDING_SURFACE_CHANGE;
mUniqueIndex = uniqueIndex;
+ mIsDisplayOn = surface != null;
}
@Override
@@ -304,6 +313,14 @@
}
}
+ void setDisplayState(boolean isOn) {
+ if (mIsDisplayOn != isOn) {
+ mIsDisplayOn = isOn;
+ mInfo = null;
+ sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED);
+ }
+ }
+
public void stopLocked() {
setSurfaceLocked(null);
mStopped = true;
@@ -375,7 +392,9 @@
mInfo.type = Display.TYPE_VIRTUAL;
mInfo.touch = ((mFlags & VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH) == 0) ?
DisplayDeviceInfo.TOUCH_NONE : DisplayDeviceInfo.TOUCH_VIRTUAL;
- mInfo.state = mSurface != null ? Display.STATE_ON : Display.STATE_OFF;
+
+ mInfo.state = mIsDisplayOn ? Display.STATE_ON : Display.STATE_OFF;
+
mInfo.ownerUid = mOwnerUid;
mInfo.ownerPackageName = mOwnerPackageName;
}
diff --git a/services/core/java/com/android/server/hdmi/ArcInitiationActionFromAvr.java b/services/core/java/com/android/server/hdmi/ArcInitiationActionFromAvr.java
index 18d328d..137833c 100644
--- a/services/core/java/com/android/server/hdmi/ArcInitiationActionFromAvr.java
+++ b/services/core/java/com/android/server/hdmi/ArcInitiationActionFromAvr.java
@@ -51,6 +51,13 @@
}
switch (cmd.getOpcode()) {
case Constants.MESSAGE_FEATURE_ABORT:
+ if ((cmd.getParams()[0] & 0xFF) == Constants.MESSAGE_INITIATE_ARC) {
+ audioSystem().setArcStatus(false);
+ finish();
+ return true;
+ } else {
+ return false;
+ }
case Constants.MESSAGE_REPORT_ARC_TERMINATED:
audioSystem().setArcStatus(false);
finish();
diff --git a/services/core/java/com/android/server/hdmi/Constants.java b/services/core/java/com/android/server/hdmi/Constants.java
index ff029c1..297a418 100644
--- a/services/core/java/com/android/server/hdmi/Constants.java
+++ b/services/core/java/com/android/server/hdmi/Constants.java
@@ -17,6 +17,7 @@
package com.android.server.hdmi;
import android.annotation.IntDef;
+import android.annotation.StringDef;
import android.hardware.hdmi.HdmiDeviceInfo;
import java.lang.annotation.Retention;
@@ -222,6 +223,15 @@
static final int AUDIO_CODEC_WMAPRO = 0xE; // Support WMA-Pro
static final int AUDIO_CODEC_MAX = 0xF;
+ @StringDef({
+ AUDIO_DEVICE_ARC_IN,
+ AUDIO_DEVICE_SPDIF,
+ })
+ public @interface AudioDevice {}
+
+ static final String AUDIO_DEVICE_ARC_IN = "ARC_IN";
+ static final String AUDIO_DEVICE_SPDIF = "SPDIF";
+
// Bit mask used to get the routing path of the top level device.
// When &'d with the path 1.2.2.0 (0x1220), for instance, gives 1.0.0.0.
static final int ROUTING_PATH_TOP_MASK = 0xF000;
diff --git a/services/core/java/com/android/server/hdmi/DetectTvSystemAudioModeSupportAction.java b/services/core/java/com/android/server/hdmi/DetectTvSystemAudioModeSupportAction.java
index 0495ff8..7187319 100644
--- a/services/core/java/com/android/server/hdmi/DetectTvSystemAudioModeSupportAction.java
+++ b/services/core/java/com/android/server/hdmi/DetectTvSystemAudioModeSupportAction.java
@@ -50,8 +50,10 @@
if (mState != STATE_WAITING_FOR_FEATURE_ABORT) {
return false;
}
- finishAction(false);
- return true;
+ if ((cmd.getParams()[0] & 0xFF) == Constants.MESSAGE_SET_SYSTEM_AUDIO_MODE) {
+ finishAction(false);
+ return true;
+ }
}
return false;
}
diff --git a/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java b/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
index ba21b78..df0dc77 100755
--- a/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
+++ b/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
@@ -16,6 +16,7 @@
package com.android.server.hdmi;
+import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.util.Slog;
@@ -51,6 +52,10 @@
private static final int STATE_WAITING_FOR_OSD_NAME = 3;
// State in which the action is waiting for gathering vendor id of non-local devices.
private static final int STATE_WAITING_FOR_VENDOR_ID = 4;
+ // State in which the action is waiting for devices to be ready.
+ private static final int STATE_WAITING_FOR_DEVICES = 5;
+ // State in which the action is waiting for gathering power status of non-local devices.
+ private static final int STATE_WAITING_FOR_POWER = 6;
/**
* Interface used to report result of device discovery.
@@ -72,6 +77,7 @@
private int mPhysicalAddress = Constants.INVALID_PHYSICAL_ADDRESS;
private int mPortId = Constants.INVALID_PORT_ID;
private int mVendorId = Constants.UNKNOWN_VENDOR_ID;
+ private int mPowerStatus = HdmiControlManager.POWER_STATUS_UNKNOWN;
private String mDisplayName = "";
private int mDeviceType = HdmiDeviceInfo.DEVICE_INACTIVE;
@@ -81,7 +87,7 @@
private HdmiDeviceInfo toHdmiDeviceInfo() {
return new HdmiDeviceInfo(mLogicalAddress, mPhysicalAddress, mPortId, mDeviceType,
- mVendorId, mDisplayName);
+ mVendorId, mDisplayName, mPowerStatus);
}
}
@@ -89,7 +95,20 @@
private final DeviceDiscoveryCallback mCallback;
private int mProcessedDeviceCount = 0;
private int mTimeoutRetry = 0;
- private boolean mIsTvDevice = source().mService.isTvDevice();
+ private boolean mIsTvDevice = localDevice().mService.isTvDevice();
+ private final int mDelayPeriod;
+
+ /**
+ * Constructor.
+ *
+ * @param source an instance of {@link HdmiCecLocalDevice}.
+ * @param delay delay action for this period between query Physical Address and polling
+ */
+ DeviceDiscoveryAction(HdmiCecLocalDevice source, DeviceDiscoveryCallback callback, int delay) {
+ super(source);
+ mCallback = Preconditions.checkNotNull(callback);
+ mDelayPeriod = delay;
+ }
/**
* Constructor.
@@ -97,8 +116,7 @@
* @param source an instance of {@link HdmiCecLocalDevice}.
*/
DeviceDiscoveryAction(HdmiCecLocalDevice source, DeviceDiscoveryCallback callback) {
- super(source);
- mCallback = Preconditions.checkNotNull(callback);
+ this(source, callback, 0);
}
@Override
@@ -117,7 +135,11 @@
Slog.v(TAG, "Device detected: " + ackedAddress);
allocateDevices(ackedAddress);
- startPhysicalAddressStage();
+ if (mDelayPeriod > 0) {
+ startToDelayAction();
+ } else {
+ startPhysicalAddressStage();
+ }
}
}, Constants.POLL_ITERATION_REVERSE_ORDER
| Constants.POLL_STRATEGY_REMOTES_DEVICES, HdmiConfig.DEVICE_POLLING_RETRY);
@@ -131,6 +153,13 @@
}
}
+ private void startToDelayAction() {
+ Slog.v(TAG, "Waiting for connected devices to be ready");
+ mState = STATE_WAITING_FOR_DEVICES;
+
+ checkAndProceedStage();
+ }
+
private void startPhysicalAddressStage() {
Slog.v(TAG, "Start [Physical Address Stage]:" + mDevices.size());
mProcessedDeviceCount = 0;
@@ -159,6 +188,11 @@
addTimer(mState, HdmiConfig.TIMEOUT_MS);
}
+ private void delayActionWithTimePeriod(int timeDelay) {
+ mActionTimer.clearTimerMessage();
+ addTimer(mState, timeDelay);
+ }
+
private void startOsdNameStage() {
Slog.v(TAG, "Start [Osd Name Stage]:" + mDevices.size());
mProcessedDeviceCount = 0;
@@ -207,6 +241,29 @@
addTimer(mState, HdmiConfig.TIMEOUT_MS);
}
+ private void startPowerStatusStage() {
+ Slog.v(TAG, "Start [Power Status Stage]:" + mDevices.size());
+ mProcessedDeviceCount = 0;
+ mState = STATE_WAITING_FOR_POWER;
+
+ checkAndProceedStage();
+ }
+
+ private void queryPowerStatus(int address) {
+ if (!verifyValidLogicalAddress(address)) {
+ checkAndProceedStage();
+ return;
+ }
+
+ mActionTimer.clearTimerMessage();
+
+ if (mayProcessMessageIfCached(address, Constants.MESSAGE_REPORT_POWER_STATUS)) {
+ return;
+ }
+ sendCommand(HdmiCecMessageBuilder.buildGiveDevicePowerStatus(getSourceAddress(), address));
+ addTimer(mState, HdmiConfig.TIMEOUT_MS);
+ }
+
private boolean mayProcessMessageIfCached(int address, int opcode) {
HdmiCecMessage message = getCecMessageCache().getMessage(address, opcode);
if (message != null) {
@@ -245,6 +302,16 @@
return true;
}
return false;
+ case STATE_WAITING_FOR_POWER:
+ if (cmd.getOpcode() == Constants.MESSAGE_REPORT_POWER_STATUS) {
+ handleReportPowerStatus(cmd);
+ return true;
+ } else if ((cmd.getOpcode() == Constants.MESSAGE_FEATURE_ABORT)
+ && ((cmd.getParams()[0] & 0xFF) == Constants.MESSAGE_REPORT_POWER_STATUS)) {
+ handleReportPowerStatus(cmd);
+ return true;
+ }
+ return false;
case STATE_WAITING_FOR_DEVICE_POLLING:
// Fall through.
default:
@@ -266,6 +333,7 @@
current.mPhysicalAddress = HdmiUtils.twoBytesToInt(params);
current.mPortId = getPortId(current.mPhysicalAddress);
current.mDeviceType = params[2] & 0xFF;
+ current.mDisplayName = HdmiUtils.getDefaultDeviceName(current.mDeviceType);
// TODO(amyjojo): check if non-TV device needs to update cec switch info.
// This is to manager CEC device separately in case they don't have address.
@@ -329,6 +397,26 @@
checkAndProceedStage();
}
+ private void handleReportPowerStatus(HdmiCecMessage cmd) {
+ Preconditions.checkState(mProcessedDeviceCount < mDevices.size());
+
+ DeviceInfo current = mDevices.get(mProcessedDeviceCount);
+ if (current.mLogicalAddress != cmd.getSource()) {
+ Slog.w(TAG, "Unmatched address[expected:" + current.mLogicalAddress + ", actual:"
+ + cmd.getSource());
+ return;
+ }
+
+ if (cmd.getOpcode() != Constants.MESSAGE_FEATURE_ABORT) {
+ byte[] params = cmd.getParams();
+ int powerStatus = params[0] & 0xFF;
+ current.mPowerStatus = powerStatus;
+ }
+
+ increaseProcessedDeviceCount();
+ checkAndProceedStage();
+ }
+
private void increaseProcessedDeviceCount() {
mProcessedDeviceCount++;
mTimeoutRetry = 0;
@@ -372,6 +460,9 @@
startVendorIdStage();
return;
case STATE_WAITING_FOR_VENDOR_ID:
+ startPowerStatusStage();
+ return;
+ case STATE_WAITING_FOR_POWER:
wrapUpAndFinish();
return;
default:
@@ -385,6 +476,9 @@
private void sendQueryCommand() {
int address = mDevices.get(mProcessedDeviceCount).mLogicalAddress;
switch (mState) {
+ case STATE_WAITING_FOR_DEVICES:
+ delayActionWithTimePeriod(mDelayPeriod);
+ return;
case STATE_WAITING_FOR_PHYSICAL_ADDRESS:
queryPhysicalAddress(address);
return;
@@ -394,6 +488,9 @@
case STATE_WAITING_FOR_VENDOR_ID:
queryVendorId(address);
return;
+ case STATE_WAITING_FOR_POWER:
+ queryPowerStatus(address);
+ return;
default:
return;
}
@@ -405,13 +502,24 @@
return;
}
+ if (mState == STATE_WAITING_FOR_DEVICES) {
+ startPhysicalAddressStage();
+ return;
+ }
if (++mTimeoutRetry < HdmiConfig.TIMEOUT_RETRY) {
sendQueryCommand();
return;
}
mTimeoutRetry = 0;
Slog.v(TAG, "Timeout[State=" + mState + ", Processed=" + mProcessedDeviceCount);
- removeDevice(mProcessedDeviceCount);
+ if (mState != STATE_WAITING_FOR_POWER && mState != STATE_WAITING_FOR_OSD_NAME) {
+ // We don't need to remove the device info if the power status is unknown.
+ // Some device does not have preferred OSD name and does not respond to Give OSD name.
+ // Like LG TV. We can give it default device name and not remove it.
+ removeDevice(mProcessedDeviceCount);
+ } else {
+ increaseProcessedDeviceCount();
+ }
checkAndProceedStage();
}
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index e777ce8..86be585 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -77,7 +77,7 @@
private static final int NUM_LOGICAL_ADDRESS = 16;
- private static final int MAX_CEC_MESSAGE_HISTORY = 20;
+ private static final int MAX_CEC_MESSAGE_HISTORY = 200;
// Predicate for whether the given logical address is remote device's one or not.
private final Predicate<Integer> mRemoteDeviceAddressPredicate = new Predicate<Integer>() {
@@ -682,7 +682,7 @@
void dump(final IndentingPrintWriter pw) {
for (int i = 0; i < mLocalDevices.size(); ++i) {
- pw.println("HdmiCecLocalDevice #" + i + ":");
+ pw.println("HdmiCecLocalDevice #" + mLocalDevices.keyAt(i) + ":");
pw.increaseIndent();
mLocalDevices.valueAt(i).dump(pw);
pw.decreaseIndent();
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index 32dc0261..414f6bb 100755
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -56,16 +56,12 @@
// Within the timer, a received <User Control Pressed> will start "Press and Hold" behavior.
// When it expires, we can assume <User Control Release> is received.
private static final int FOLLOWER_SAFETY_TIMEOUT = 550;
- /**
- * Return value of {@link #getLocalPortFromPhysicalAddress(int)}
- */
- private static final int TARGET_NOT_UNDER_LOCAL_DEVICE = -1;
- private static final int TARGET_SAME_PHYSICAL_ADDRESS = 0;
protected final HdmiControlService mService;
protected final int mDeviceType;
protected int mAddress;
protected int mPreferredAddress;
+ @GuardedBy("mLock")
protected HdmiDeviceInfo mDeviceInfo;
protected int mLastKeycode = HdmiCecKeycode.UNSUPPORTED_KEYCODE;
protected int mLastKeyRepeatCount = 0;
@@ -717,16 +713,18 @@
return mDeviceType;
}
- @ServiceThreadOnly
+ @GuardedBy("mLock")
HdmiDeviceInfo getDeviceInfo() {
- assertRunOnServiceThread();
- return mDeviceInfo;
+ synchronized (mLock) {
+ return mDeviceInfo;
+ }
}
- @ServiceThreadOnly
+ @GuardedBy("mLock")
void setDeviceInfo(HdmiDeviceInfo info) {
- assertRunOnServiceThread();
- mDeviceInfo = info;
+ synchronized (mLock) {
+ mDeviceInfo = info;
+ }
}
// Returns true if the logical address is same as the argument.
@@ -1058,47 +1056,6 @@
pw.println(String.format("mActiveRoutingPath: 0x%04x", mActiveRoutingPath));
}
- /**
- * Method to parse target physical address to the port number on the current device.
- *
- * <p>This check assumes target address is valid.
- * @param targetPhysicalAddress is the physical address of the target device
- * @return
- * If the target device is under the current device, return the port number of current device
- * that the target device is connected to.
- *
- * <p>If the target device has the same physical address as the current device, return
- * {@link #TARGET_SAME_PHYSICAL_ADDRESS}.
- *
- * <p>If the target device is not under the current device, return
- * {@link #TARGET_NOT_UNDER_LOCAL_DEVICE}.
- */
- protected int getLocalPortFromPhysicalAddress(int targetPhysicalAddress) {
- int myPhysicalAddress = mService.getPhysicalAddress();
- if (myPhysicalAddress == targetPhysicalAddress) {
- return TARGET_SAME_PHYSICAL_ADDRESS;
- }
- int finalMask = 0xF000;
- int mask;
- int port = 0;
- for (mask = 0x0F00; mask > 0x000F; mask >>= 4) {
- if ((myPhysicalAddress & mask) == 0) {
- port = mask & targetPhysicalAddress;
- break;
- } else {
- finalMask |= mask;
- }
- }
- if (finalMask != 0xFFFF && (finalMask & targetPhysicalAddress) == myPhysicalAddress) {
- while (mask != 0x000F) {
- mask >>= 4;
- port >>= 4;
- }
- return port;
- }
- return TARGET_NOT_UNDER_LOCAL_DEVICE;
- }
-
/** Calculates the physical address for {@code activePortId}.
*
* <p>This method assumes current device physical address is valid.
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
index 0e4e334..63214ed 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -26,22 +26,38 @@
import android.hardware.hdmi.HdmiPortInfo;
import android.hardware.hdmi.IHdmiControlCallback;
import android.media.AudioDeviceInfo;
+import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioSystem;
import android.media.tv.TvContract;
import android.os.SystemProperties;
+import android.provider.Settings.Global;
import android.util.Slog;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.server.hdmi.Constants.AudioCodec;
import com.android.server.hdmi.DeviceDiscoveryAction.DeviceDiscoveryCallback;
import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
+import com.android.server.hdmi.HdmiUtils.CodecSad;
+import com.android.server.hdmi.HdmiUtils.DeviceConfig;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
+import java.util.stream.Collectors;
+
/**
* Represent a logical device of type {@link HdmiDeviceInfo#DEVICE_AUDIO_SYSTEM} residing in Android
@@ -77,25 +93,28 @@
// processing.
private final HashMap<Integer, String> mTvInputs = new HashMap<>();
+ // Copy of mDeviceInfos to guarantee thread-safety.
+ @GuardedBy("mLock")
+ private List<HdmiDeviceInfo> mSafeAllDeviceInfos = Collections.emptyList();
+
// Map-like container of all cec devices.
// device id is used as key of container.
private final SparseArray<HdmiDeviceInfo> mDeviceInfos = new SparseArray<>();
protected HdmiCecLocalDeviceAudioSystem(HdmiControlService service) {
super(service, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
- mSystemAudioControlFeatureEnabled = true;
- // TODO(amyjojo) make System Audio Control controllable by users
- /*mSystemAudioControlFeatureEnabled =
- mService.readBooleanSetting(Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED, true);*/
- // TODO(amyjojo): make the map ro property.
- mTvInputs.put(Constants.CEC_SWITCH_HDMI1,
- "com.droidlogic.tvinput/.services.Hdmi1InputService/HW5");
- mTvInputs.put(Constants.CEC_SWITCH_HDMI2,
- "com.droidlogic.tvinput/.services.Hdmi2InputService/HW6");
- mTvInputs.put(Constants.CEC_SWITCH_HDMI3,
- "com.droidlogic.tvinput/.services.Hdmi3InputService/HW7");
+ mRoutingControlFeatureEnabled =
+ mService.readBooleanSetting(Global.HDMI_CEC_SWITCH_ENABLED, false);
+ mSystemAudioControlFeatureEnabled =
+ mService.readBooleanSetting(Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED, true);
+ // TODO(amyjojo): Maintain a portId to TvinputId map.
+ mTvInputs.put(2, "com.droidlogic.tvinput/.services.Hdmi1InputService/HW5");
+ mTvInputs.put(4, "com.droidlogic.tvinput/.services.Hdmi2InputService/HW6");
+ mTvInputs.put(1, "com.droidlogic.tvinput/.services.Hdmi3InputService/HW7");
}
+ private static final String SHORT_AUDIO_DESCRIPTOR_CONFIG_PATH = "/vendor/etc/sadConfig.xml";
+
/**
* Called when a device is newly added or a new device is detected or
* an existing device is updated.
@@ -167,6 +186,7 @@
removeDeviceInfo(deviceInfo.getId());
}
mDeviceInfos.append(deviceInfo.getId(), deviceInfo);
+ updateSafeDeviceInfoList();
return oldDeviceInfo;
}
@@ -184,6 +204,7 @@
if (deviceInfo != null) {
mDeviceInfos.remove(id);
}
+ updateSafeDeviceInfoList();
return deviceInfo;
}
@@ -200,6 +221,24 @@
return mDeviceInfos.get(HdmiDeviceInfo.idForCecDevice(logicalAddress));
}
+ @ServiceThreadOnly
+ private void updateSafeDeviceInfoList() {
+ assertRunOnServiceThread();
+ List<HdmiDeviceInfo> copiedDevices = HdmiUtils.sparseArrayToList(mDeviceInfos);
+ synchronized (mLock) {
+ mSafeAllDeviceInfos = copiedDevices;
+ }
+ }
+
+ @GuardedBy("mLock")
+ List<HdmiDeviceInfo> getSafeCecDevicesLocked() {
+ ArrayList<HdmiDeviceInfo> infoList = new ArrayList<>();
+ for (HdmiDeviceInfo info : mSafeAllDeviceInfos) {
+ infoList.add(info);
+ }
+ return infoList;
+ }
+
private void invokeDeviceEventListener(HdmiDeviceInfo info, int status) {
mService.invokeDeviceEventListeners(info, status);
}
@@ -229,7 +268,7 @@
mTvSystemAudioModeSupport = false;
// Record the last state of System Audio Control before going to standby
synchronized (mLock) {
- SystemProperties.set(
+ mService.writeStringSetting(
Constants.PROPERTY_LAST_SYSTEM_AUDIO_CONTROL,
mSystemAudioActivated ? "true" : "false");
}
@@ -240,6 +279,10 @@
@ServiceThreadOnly
protected void onAddressAllocated(int logicalAddress, int reason) {
assertRunOnServiceThread();
+ if (reason == mService.INITIATED_BY_ENABLE_CEC) {
+ mService.setAndBroadcastActiveSource(mService.getPhysicalAddress(),
+ getDeviceInfo().getDeviceType(), Constants.ADDR_BROADCAST);
+ }
mService.sendCecCommand(
HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
mAddress, mService.getPhysicalAddress(), mDeviceType));
@@ -259,7 +302,10 @@
@Override
protected int findKeyReceiverAddress() {
- return Constants.ADDR_TV;
+ if (getActiveSource().isValid()) {
+ return getActiveSource().logicalAddress;
+ }
+ return Constants.ADDR_INVALID;
}
@VisibleForTesting
@@ -267,7 +313,7 @@
int systemAudioOnPowerOnProp, boolean lastSystemAudioControlStatus) {
if ((systemAudioOnPowerOnProp == ALWAYS_SYSTEM_AUDIO_CONTROL_ON_POWER_ON)
|| ((systemAudioOnPowerOnProp == USE_LAST_STATE_SYSTEM_AUDIO_CONTROL_ON_POWER_ON)
- && lastSystemAudioControlStatus)) {
+ && lastSystemAudioControlStatus && isSystemAudioControlFeatureEnabled())) {
addAndStartAction(new SystemAudioInitiationActionFromAvr(this));
}
}
@@ -284,7 +330,7 @@
@ServiceThreadOnly
protected void setPreferredAddress(int addr) {
assertRunOnServiceThread();
- SystemProperties.set(
+ mService.writeStringSetting(
Constants.PROPERTY_PREFERRED_ADDRESS_AUDIO_SYSTEM, String.valueOf(addr));
}
@@ -400,8 +446,11 @@
@ServiceThreadOnly
protected boolean handleGiveAudioStatus(HdmiCecMessage message) {
assertRunOnServiceThread();
-
- reportAudioStatus(message);
+ if (isSystemAudioControlFeatureEnabled()) {
+ reportAudioStatus(message.getSource());
+ } else {
+ mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
+ }
return true;
}
@@ -420,7 +469,7 @@
protected boolean handleRequestArcInitiate(HdmiCecMessage message) {
assertRunOnServiceThread();
removeAction(ArcInitiationActionFromAvr.class);
- if (!SystemProperties.getBoolean(Constants.PROPERTY_ARC_SUPPORT, true)) {
+ if (!mService.readBooleanSetting(Constants.PROPERTY_ARC_SUPPORT, true)) {
mService.maySendFeatureAbortCommand(message, Constants.ABORT_UNRECOGNIZED_OPCODE);
} else if (!isDirectConnectToTv()) {
HdmiLogger.debug("AVR device is not directly connected with TV");
@@ -459,13 +508,35 @@
mService.maySendFeatureAbortCommand(message, Constants.ABORT_NOT_IN_CORRECT_MODE);
return true;
}
- AudioDeviceInfo deviceInfo = getSystemAudioDeviceInfo();
- if (deviceInfo == null) {
- mService.maySendFeatureAbortCommand(message, Constants.ABORT_UNABLE_TO_DETERMINE);
- return true;
+
+ List<DeviceConfig> config = null;
+ File file = new File(SHORT_AUDIO_DESCRIPTOR_CONFIG_PATH);
+ if (file.exists()) {
+ try {
+ InputStream in = new FileInputStream(file);
+ config = HdmiUtils.ShortAudioDescriptorXmlParser.parse(in);
+ in.close();
+ } catch (IOException e) {
+ Slog.e(TAG, "Error reading file: " + file, e);
+ } catch (XmlPullParserException e) {
+ Slog.e(TAG, "Unable to parse file: " + file, e);
+ }
}
+
@AudioCodec int[] audioFormatCodes = parseAudioFormatCodes(message.getParams());
- byte[] sadBytes = getSupportedShortAudioDescriptors(deviceInfo, audioFormatCodes);
+ byte[] sadBytes;
+ if (config != null && config.size() > 0) {
+ sadBytes = getSupportedShortAudioDescriptorsFromConfig(config, audioFormatCodes);
+ } else {
+ AudioDeviceInfo deviceInfo = getSystemAudioDeviceInfo();
+ if (deviceInfo == null) {
+ mService.maySendFeatureAbortCommand(message, Constants.ABORT_UNABLE_TO_DETERMINE);
+ return true;
+ }
+
+ sadBytes = getSupportedShortAudioDescriptors(deviceInfo, audioFormatCodes);
+ }
+
if (sadBytes.length == 0) {
mService.maySendFeatureAbortCommand(message, Constants.ABORT_INVALID_OPERAND);
} else {
@@ -478,14 +549,127 @@
private byte[] getSupportedShortAudioDescriptors(
AudioDeviceInfo deviceInfo, @AudioCodec int[] audioFormatCodes) {
- // TODO(b/80297701) implement
- return new byte[] {};
+ ArrayList<byte[]> sads = new ArrayList<>(audioFormatCodes.length);
+ for (@AudioCodec int audioFormatCode : audioFormatCodes) {
+ byte[] sad = getSupportedShortAudioDescriptor(deviceInfo, audioFormatCode);
+ if (sad != null) {
+ if (sad.length == 3) {
+
+ sads.add(sad);
+ } else {
+ HdmiLogger.warning(
+ "Dropping Short Audio Descriptor with length %d for requested codec %x",
+ sad.length, audioFormatCode);
+ }
+ }
+ }
+ return getShortAudioDescriptorBytes(sads);
+ }
+
+ private byte[] getSupportedShortAudioDescriptorsFromConfig(
+ List<DeviceConfig> deviceConfig, @AudioCodec int[] audioFormatCodes) {
+ DeviceConfig deviceConfigToUse = null;
+ for (DeviceConfig device : deviceConfig) {
+ // TODO(amyjojo) use PROPERTY_SYSTEM_AUDIO_MODE_AUDIO_PORT to get the audio device name
+ if (device.name.equals("VX_AUDIO_DEVICE_IN_HDMI_ARC")) {
+ deviceConfigToUse = device;
+ break;
+ }
+ }
+ if (deviceConfigToUse == null) {
+ // TODO(amyjojo) use PROPERTY_SYSTEM_AUDIO_MODE_AUDIO_PORT to get the audio device name
+ Slog.w(TAG, "sadConfig.xml does not have required device info for "
+ + "VX_AUDIO_DEVICE_IN_HDMI_ARC");
+ return new byte[0];
+ }
+ HashMap<Integer, byte[]> map = new HashMap<>();
+ ArrayList<byte[]> sads = new ArrayList<>(audioFormatCodes.length);
+ for (CodecSad codecSad : deviceConfigToUse.supportedCodecs) {
+ map.put(codecSad.audioCodec, codecSad.sad);
+ }
+ for (int i = 0; i < audioFormatCodes.length; i++) {
+ if (map.containsKey(audioFormatCodes[i])) {
+ byte[] sad = map.get(audioFormatCodes[i]);
+ if (sad != null && sad.length == 3) {
+ sads.add(sad);
+ }
+ }
+ }
+ return getShortAudioDescriptorBytes(sads);
+ }
+
+ private byte[] getShortAudioDescriptorBytes(ArrayList<byte[]> sads) {
+ // Short Audio Descriptors are always 3 bytes long.
+ byte[] bytes = new byte[sads.size() * 3];
+ int index = 0;
+ for (byte[] sad : sads) {
+ System.arraycopy(sad, 0, bytes, index, 3);
+ index += 3;
+ }
+ return bytes;
+ }
+
+ /**
+ * Returns a 3 byte short audio descriptor as described in CEC 1.4 table 29 or null if the
+ * audioFormatCode is not supported.
+ */
+ @Nullable
+ private byte[] getSupportedShortAudioDescriptor(
+ AudioDeviceInfo deviceInfo, @AudioCodec int audioFormatCode) {
+ switch (audioFormatCode) {
+ case Constants.AUDIO_CODEC_NONE: {
+ return null;
+ }
+ case Constants.AUDIO_CODEC_LPCM: {
+ return getLpcmShortAudioDescriptor(deviceInfo);
+ }
+ // TODO(b/80297701): implement the rest of the codecs
+ case Constants.AUDIO_CODEC_DD:
+ case Constants.AUDIO_CODEC_MPEG1:
+ case Constants.AUDIO_CODEC_MP3:
+ case Constants.AUDIO_CODEC_MPEG2:
+ case Constants.AUDIO_CODEC_AAC:
+ case Constants.AUDIO_CODEC_DTS:
+ case Constants.AUDIO_CODEC_ATRAC:
+ case Constants.AUDIO_CODEC_ONEBITAUDIO:
+ case Constants.AUDIO_CODEC_DDP:
+ case Constants.AUDIO_CODEC_DTSHD:
+ case Constants.AUDIO_CODEC_TRUEHD:
+ case Constants.AUDIO_CODEC_DST:
+ case Constants.AUDIO_CODEC_WMAPRO:
+ default: {
+ return null;
+ }
+ }
+ }
+
+ @Nullable
+ private byte[] getLpcmShortAudioDescriptor(AudioDeviceInfo deviceInfo) {
+ // TODO(b/80297701): implement
+ return null;
}
@Nullable
private AudioDeviceInfo getSystemAudioDeviceInfo() {
- // TODO(b/80297701) implement
- // Get the audio device used for system audio mode.
+ AudioManager audioManager = mService.getContext().getSystemService(AudioManager.class);
+ if (audioManager == null) {
+ HdmiLogger.error(
+ "Error getting system audio device because AudioManager not available.");
+ return null;
+ }
+ AudioDeviceInfo[] devices = audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS);
+ HdmiLogger.debug("Found %d audio input devices", devices.length);
+ for (AudioDeviceInfo device : devices) {
+ HdmiLogger.debug("%s at port %s", device.getProductName(), device.getPort());
+ HdmiLogger.debug("Supported encodings are %s",
+ Arrays.stream(device.getEncodings()).mapToObj(
+ AudioFormat::toLogFriendlyEncoding
+ ).collect(Collectors.joining(", ")));
+ // TODO(b/80297701) use the actual device type that system audio mode is connected to.
+ if (device.getType() == AudioDeviceInfo.TYPE_HDMI_ARC) {
+ return device;
+ }
+ }
return null;
}
@@ -583,17 +767,20 @@
.setWiredDeviceConnectionState(AudioSystem.DEVICE_IN_HDMI, enabled ? 1 : 0, "", "");
}
- private void reportAudioStatus(HdmiCecMessage message) {
+ void reportAudioStatus(int source) {
assertRunOnServiceThread();
int volume = mService.getAudioManager().getStreamVolume(AudioManager.STREAM_MUSIC);
boolean mute = mService.getAudioManager().isStreamMute(AudioManager.STREAM_MUSIC);
int maxVolume = mService.getAudioManager().getStreamMaxVolume(AudioManager.STREAM_MUSIC);
+ int minVolume = mService.getAudioManager().getStreamMinVolume(AudioManager.STREAM_MUSIC);
int scaledVolume = VolumeControlAction.scaleToCecVolume(volume, maxVolume);
+ HdmiLogger.debug("Reporting volume %i (%i-%i) as CEC volume %i", volume,
+ minVolume, maxVolume, scaledVolume);
mService.sendCecCommand(
HdmiCecMessageBuilder.buildReportAudioStatus(
- mAddress, message.getSource(), scaledVolume, mute));
+ mAddress, source, scaledVolume, mute));
}
/**
@@ -633,7 +820,7 @@
*/
private void setSystemAudioMode(boolean newSystemAudioMode) {
int targetPhysicalAddress = getActiveSource().physicalAddress;
- int port = getLocalPortFromPhysicalAddress(targetPhysicalAddress);
+ int port = mService.pathToPortId(targetPhysicalAddress);
if (newSystemAudioMode && port >= 0) {
switchToAudioInput();
}
@@ -641,16 +828,18 @@
// PROPERTY_SYSTEM_AUDIO_MODE_MUTING_ENABLE is false when device never needs to be muted.
boolean currentMuteStatus =
mService.getAudioManager().isStreamMute(AudioManager.STREAM_MUSIC);
- if (SystemProperties.getBoolean(
- Constants.PROPERTY_SYSTEM_AUDIO_MODE_MUTING_ENABLE, true)
- && currentMuteStatus == newSystemAudioMode) {
- mService.getAudioManager()
- .adjustStreamVolume(
- AudioManager.STREAM_MUSIC,
- newSystemAudioMode
- ? AudioManager.ADJUST_UNMUTE
- : AudioManager.ADJUST_MUTE,
- 0);
+ if (currentMuteStatus == newSystemAudioMode) {
+ if (mService.readBooleanSetting(
+ Constants.PROPERTY_SYSTEM_AUDIO_MODE_MUTING_ENABLE, true)
+ || newSystemAudioMode) {
+ mService.getAudioManager()
+ .adjustStreamVolume(
+ AudioManager.STREAM_MUSIC,
+ newSystemAudioMode
+ ? AudioManager.ADJUST_UNMUTE
+ : AudioManager.ADJUST_MUTE,
+ 0);
+ }
}
updateAudioManagerForSystemAudio(newSystemAudioMode);
synchronized (mLock) {
@@ -688,6 +877,13 @@
HdmiLogger.debug("[A]UpdateSystemAudio mode[on=%b] output=[%X]", on, device);
}
+ void onSystemAduioControlFeatureSupportChanged(boolean enabled) {
+ setSystemAudioControlFeatureEnabled(enabled);
+ if (enabled) {
+ addAndStartAction(new SystemAudioInitiationActionFromAvr(this));
+ }
+ }
+
@ServiceThreadOnly
void setSystemAudioControlFeatureEnabled(boolean enabled) {
assertRunOnServiceThread();
@@ -697,6 +893,14 @@
}
@ServiceThreadOnly
+ void setRoutingControlFeatureEnables(boolean enabled) {
+ assertRunOnServiceThread();
+ synchronized (mLock) {
+ mRoutingControlFeatureEnabled = enabled;
+ }
+ }
+
+ @ServiceThreadOnly
void doManualPortSwitching(int portId, IHdmiControlCallback callback) {
assertRunOnServiceThread();
// TODO: validate port ID
@@ -817,7 +1021,7 @@
@Override
protected void switchInputOnReceivingNewActivePath(int physicalAddress) {
- int port = getLocalPortFromPhysicalAddress(physicalAddress);
+ int port = mService.pathToPortId(physicalAddress);
if (isSystemAudioActivated() && port < 0) {
// If system audio mode is on and the new active source is not under the current device,
// Will switch to ARC input.
@@ -831,6 +1035,10 @@
}
protected void routeToInputFromPortId(int portId) {
+ if (!isRoutingControlFeatureEnabled()) {
+ HdmiLogger.debug("Routing Control Feature is not enabled.");
+ return;
+ }
if (mArcIntentUsed) {
routeToTvInputFromPortId(portId);
} else {
@@ -885,7 +1093,7 @@
@Override
protected void handleRoutingChangeAndInformation(int physicalAddress, HdmiCecMessage message) {
- int port = getLocalPortFromPhysicalAddress(physicalAddress);
+ int port = mService.pathToPortId(physicalAddress);
// Routing change or information sent from switches under the current device can be ignored.
if (port > 0) {
return;
@@ -918,8 +1126,7 @@
return;
}
- int routingInformationPath =
- getActivePathOnSwitchFromActivePortId(getRoutingPort());
+ int routingInformationPath = mService.portIdToPath(getRoutingPort());
// If current device is already the leaf of the whole HDMI system, will do nothing.
if (routingInformationPath == mService.getPhysicalAddress()) {
HdmiLogger.debug("Current device can't assign valid physical address"
@@ -954,6 +1161,10 @@
@ServiceThreadOnly
private void launchDeviceDiscovery() {
assertRunOnServiceThread();
+ if (hasAction(DeviceDiscoveryAction.class)) {
+ Slog.i(TAG, "Device Discovery Action is in progress. Restarting.");
+ removeAction(DeviceDiscoveryAction.class);
+ }
DeviceDiscoveryAction action = new DeviceDiscoveryAction(this,
new DeviceDiscoveryCallback() {
@Override
@@ -977,5 +1188,25 @@
invokeDeviceEventListener(info, HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE);
}
mDeviceInfos.clear();
+ updateSafeDeviceInfoList();
}
+
+ @Override
+ protected void dump(IndentingPrintWriter pw) {
+ pw.println("HdmiCecLocalDeviceAudioSystem:");
+ pw.increaseIndent();
+ pw.println("mSystemAudioActivated: " + mSystemAudioActivated);
+ pw.println("isRoutingFeatureEnabled " + isRoutingControlFeatureEnabled());
+ pw.println("mSystemAudioControlFeatureEnabled: " + mSystemAudioControlFeatureEnabled);
+ pw.println("mTvSystemAudioModeSupport: " + mTvSystemAudioModeSupport);
+ pw.println("mArcEstablished: " + mArcEstablished);
+ pw.println("mArcIntentUsed: " + mArcIntentUsed);
+ pw.println("mRoutingPort: " + getRoutingPort());
+ pw.println("mLocalActivePort: " + getLocalActivePort());
+ HdmiUtils.dumpMap(pw, "mTvInputs:", mTvInputs);
+ HdmiUtils.dumpSparseArray(pw, "mDeviceInfos:", mDeviceInfos);
+ pw.decreaseIndent();
+ super.dump(pw);
+ }
+
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index 07db971..7a0c279 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -77,6 +77,10 @@
@ServiceThreadOnly
protected void onAddressAllocated(int logicalAddress, int reason) {
assertRunOnServiceThread();
+ if (reason == mService.INITIATED_BY_ENABLE_CEC) {
+ mService.setAndBroadcastActiveSource(mService.getPhysicalAddress(),
+ getDeviceInfo().getDeviceType(), Constants.ADDR_BROADCAST);
+ }
mService.sendCecCommand(HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
mAddress, mService.getPhysicalAddress(), mDeviceType));
mService.sendCecCommand(HdmiCecMessageBuilder.buildDeviceVendorIdCommand(
@@ -96,7 +100,7 @@
@ServiceThreadOnly
protected void setPreferredAddress(int addr) {
assertRunOnServiceThread();
- SystemProperties.set(Constants.PROPERTY_PREFERRED_ADDRESS_PLAYBACK,
+ mService.writeStringSetting(Constants.PROPERTY_PREFERRED_ADDRESS_PLAYBACK,
String.valueOf(addr));
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
index a95f7f1..ae008b4 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
@@ -66,6 +66,10 @@
@LocalActivePort
protected int mLocalActivePort = Constants.CEC_SWITCH_HOME;
+ // Whether the Routing Coutrol feature is enabled or not. False by default.
+ @GuardedBy("mLock")
+ protected boolean mRoutingControlFeatureEnabled;
+
protected HdmiCecLocalDeviceSource(HdmiControlService service, int deviceType) {
super(service, deviceType);
}
@@ -123,7 +127,9 @@
}
setIsActiveSource(physicalAddress == mService.getPhysicalAddress());
updateDevicePowerStatus(logicalAddress, HdmiControlManager.POWER_STATUS_ON);
- switchInputOnReceivingNewActivePath(physicalAddress);
+ if (isRoutingControlFeatureEnabled()) {
+ switchInputOnReceivingNewActivePath(physicalAddress);
+ }
return true;
}
@@ -153,6 +159,10 @@
@ServiceThreadOnly
protected boolean handleRoutingChange(HdmiCecMessage message) {
assertRunOnServiceThread();
+ if (!isRoutingControlFeatureEnabled()) {
+ mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
+ return true;
+ }
int newPath = HdmiUtils.twoBytesToInt(message.getParams(), 2);
// if the current device is a pure playback device
if (!mIsSwitchDevice
@@ -168,6 +178,10 @@
@ServiceThreadOnly
protected boolean handleRoutingInformation(HdmiCecMessage message) {
assertRunOnServiceThread();
+ if (!isRoutingControlFeatureEnabled()) {
+ mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
+ return true;
+ }
int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
// if the current device is a pure playback device
if (!mIsSwitchDevice
@@ -204,7 +218,7 @@
// This method should only be called when the device can be the active source.
protected void setAndBroadcastActiveSource(HdmiCecMessage message, int physicalAddress) {
mService.setAndBroadcastActiveSource(
- message, physicalAddress, getDeviceInfo().getDeviceType());
+ physicalAddress, getDeviceInfo().getDeviceType(), message.getSource());
}
@ServiceThreadOnly
@@ -279,6 +293,12 @@
}
}
+ boolean isRoutingControlFeatureEnabled() {
+ synchronized (mLock) {
+ return mRoutingControlFeatureEnabled;
+ }
+ }
+
// Check if the device is trying to switch to the same input that is active right now.
// This can help avoid redundant port switching.
protected boolean isSwitchingToTheSameInput(@LocalActivePort int activePort) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessage.java b/services/core/java/com/android/server/hdmi/HdmiCecMessage.java
index c005615..f8b3962 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessage.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessage.java
@@ -17,6 +17,7 @@
package com.android.server.hdmi;
import android.annotation.Nullable;
+
import libcore.util.EmptyArray;
import java.util.Arrays;
@@ -111,12 +112,11 @@
@Override
public String toString() {
StringBuffer s = new StringBuffer();
- s.append(String.format("<%s> src: %d, dst: %d",
- opcodeToString(mOpcode), mSource, mDestination));
+ s.append(String.format("<%s> %X%X:%02X",
+ opcodeToString(mOpcode), mSource, mDestination, mOpcode));
if (mParams.length > 0) {
- s.append(", params:");
for (byte data : mParams) {
- s.append(String.format(" %02X", data));
+ s.append(String.format(":%02X", data));
}
}
return s.toString();
@@ -133,7 +133,7 @@
case Constants.MESSAGE_TUNER_STEP_DECREMENT:
return "Tuner Step Decrement";
case Constants.MESSAGE_TUNER_DEVICE_STATUS:
- return "Tuner Device Staus";
+ return "Tuner Device Status";
case Constants.MESSAGE_GIVE_TUNER_DEVICE_STATUS:
return "Give Tuner Device Status";
case Constants.MESSAGE_RECORD_ON:
@@ -207,7 +207,7 @@
case Constants.MESSAGE_DEVICE_VENDOR_ID:
return "Device Vendor Id";
case Constants.MESSAGE_VENDOR_COMMAND:
- return "Vendor Commandn";
+ return "Vendor Command";
case Constants.MESSAGE_VENDOR_REMOTE_BUTTON_DOWN:
return "Vendor Remote Button Down";
case Constants.MESSAGE_VENDOR_REMOTE_BUTTON_UP:
@@ -215,7 +215,7 @@
case Constants.MESSAGE_GIVE_DEVICE_VENDOR_ID:
return "Give Device Vendor Id";
case Constants.MESSAGE_MENU_REQUEST:
- return "Menu REquest";
+ return "Menu Request";
case Constants.MESSAGE_MENU_STATUS:
return "Menu Status";
case Constants.MESSAGE_GIVE_DEVICE_POWER_STATUS:
@@ -247,7 +247,7 @@
case Constants.MESSAGE_SET_EXTERNAL_TIMER:
return "Set External Timer";
case Constants.MESSAGE_REPORT_SHORT_AUDIO_DESCRIPTOR:
- return "Repot Short Audio Descriptor";
+ return "Report Short Audio Descriptor";
case Constants.MESSAGE_REQUEST_SHORT_AUDIO_DESCRIPTOR:
return "Request Short Audio Descriptor";
case Constants.MESSAGE_INITIATE_ARC:
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 2d6e762..46219d5 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -20,12 +20,14 @@
import static android.hardware.hdmi.HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE;
import static com.android.internal.os.RoSystemProperties.PROPERTY_HDMI_IS_DEVICE_HDMI_CEC_SWITCH;
+import static com.android.server.hdmi.Constants.ADDR_UNREGISTERED;
import static com.android.server.hdmi.Constants.DISABLED;
import static com.android.server.hdmi.Constants.ENABLED;
import static com.android.server.hdmi.Constants.OPTION_MHL_ENABLE;
import static com.android.server.hdmi.Constants.OPTION_MHL_INPUT_SWITCHING;
import static com.android.server.hdmi.Constants.OPTION_MHL_POWER_CHARGE;
import static com.android.server.hdmi.Constants.OPTION_MHL_SERVICE_CONTROL;
+import static com.android.server.power.ShutdownThread.SHUTDOWN_ACTION_PROPERTY;
import android.annotation.Nullable;
import android.content.BroadcastReceiver;
@@ -184,9 +186,10 @@
@Override
public void onReceive(Context context, Intent intent) {
assertRunOnServiceThread();
+ boolean isReboot = SystemProperties.get(SHUTDOWN_ACTION_PROPERTY).contains("1");
switch (intent.getAction()) {
case Intent.ACTION_SCREEN_OFF:
- if (isPowerOnOrTransient()) {
+ if (isPowerOnOrTransient() && !isReboot) {
onStandby(STANDBY_SCREEN_OFF);
}
break;
@@ -202,7 +205,7 @@
}
break;
case Intent.ACTION_SHUTDOWN:
- if (isPowerOnOrTransient()) {
+ if (isPowerOnOrTransient() && !isReboot) {
onStandby(STANDBY_SHUTDOWN);
}
break;
@@ -345,6 +348,10 @@
@Nullable
private Looper mIoLooper;
+ // Thread safe physical address
+ @GuardedBy("mLock")
+ private int mPhysicalAddress = Constants.INVALID_PHYSICAL_ADDRESS;
+
// Last input port before switching to the MHL port. Should switch back to this port
// when the mobile device sends the request one touch play with off.
// Gets invalidated if we go to other port/input.
@@ -564,7 +571,8 @@
Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED,
Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED,
Global.MHL_INPUT_SWITCHING_ENABLED,
- Global.MHL_POWER_CHARGE_ENABLED
+ Global.MHL_POWER_CHARGE_ENABLED,
+ Global.HDMI_CEC_SWITCH_ENABLED
};
for (String s : settings) {
resolver.registerContentObserver(Global.getUriFor(s), false, mSettingsObserver,
@@ -605,6 +613,24 @@
if (isTvDeviceEnabled()) {
tv().setSystemAudioControlFeatureEnabled(enabled);
}
+ if (isAudioSystemDevice()) {
+ if (audioSystem() == null) {
+ Slog.e(TAG, "Audio System device has not registered yet."
+ + " Can't turn system audio mode on.");
+ break;
+ }
+ audioSystem().onSystemAduioControlFeatureSupportChanged(enabled);
+ }
+ break;
+ case Global.HDMI_CEC_SWITCH_ENABLED:
+ if (isAudioSystemDevice()) {
+ if (audioSystem() == null) {
+ Slog.w(TAG, "Switch device has not registered yet."
+ + " Can't turn routing on.");
+ break;
+ }
+ audioSystem().setRoutingControlFeatureEnables(enabled);
+ }
break;
case Global.MHL_INPUT_SWITCHING_ENABLED:
setMhlInputChangeEnabled(enabled);
@@ -620,6 +646,7 @@
return enabled ? ENABLED : DISABLED;
}
+ @VisibleForTesting
boolean readBooleanSetting(String key, boolean defVal) {
ContentResolver cr = getContext().getContentResolver();
return Global.getInt(cr, key, toInt(defVal)) == ENABLED;
@@ -630,6 +657,11 @@
Global.putInt(cr, key, toInt(value));
}
+ void writeStringSetting(String key, String value) {
+ ContentResolver cr = getContext().getContentResolver();
+ Global.putString(cr, key, value);
+ }
+
private void initializeCec(int initiatedBy) {
mAddressAllocated = false;
mCecController.setOption(OptionKey.SYSTEM_CEC_CONTROL, true);
@@ -734,6 +766,10 @@
assertRunOnServiceThread();
HdmiPortInfo[] cecPortInfo = null;
+ synchronized (mLock) {
+ mPhysicalAddress = getPhysicalAddress();
+ }
+
// CEC HAL provides majority of the info while MHL does only MHL support flag for
// each port. Return empty array if CEC HAL didn't provide the info.
if (mCecController != null) {
@@ -827,7 +863,10 @@
int pathToPortId(int path) {
int mask = 0xF000;
int finalMask = 0xF000;
- int physicalAddress = getPhysicalAddress();
+ int physicalAddress;
+ synchronized (mLock) {
+ physicalAddress = mPhysicalAddress;
+ }
int maskedAddress = physicalAddress;
while (maskedAddress != 0) {
@@ -1135,7 +1174,7 @@
String displayName = Build.MODEL;
return new HdmiDeviceInfo(logicalAddress,
getPhysicalAddress(), pathToPortId(getPhysicalAddress()), deviceType,
- getVendorId(), displayName);
+ getVendorId(), displayName, powerStatus);
}
@ServiceThreadOnly
@@ -1354,6 +1393,33 @@
HdmiCecLocalDeviceTv tv = tv();
if (tv == null) {
Slog.w(TAG, "Local tv device not available");
+ if (isPlaybackDevice()) {
+ // if playback device itself is the active source,
+ // return its own device info.
+ if (playback() != null && playback().mIsActiveSource) {
+ return playback().getDeviceInfo();
+ }
+ // Otherwise get the active source and look for it from the device list
+ ActiveSource activeSource = mActiveSource;
+ // If the active source is not set yet, return null
+ if (!activeSource.isValid()) {
+ return null;
+ }
+ if (audioSystem() != null) {
+ HdmiCecLocalDeviceAudioSystem audioSystem = audioSystem();
+ for (HdmiDeviceInfo info : audioSystem.getSafeCecDevicesLocked()) {
+ if (info.getLogicalAddress() == activeSource.logicalAddress) {
+ return info;
+ }
+ }
+ }
+ // If the device info is not in the list yet, return a device info with minimum
+ // information from mActiveSource.
+ return new HdmiDeviceInfo(activeSource.logicalAddress,
+ activeSource.physicalAddress, pathToPortId(activeSource.physicalAddress),
+ HdmiUtils.getTypeFromAddress(activeSource.logicalAddress), 0,
+ HdmiUtils.getDefaultDeviceName(activeSource.logicalAddress));
+ }
return null;
}
ActiveSource activeSource = tv.getActiveSource();
@@ -1532,6 +1598,14 @@
}
@Override
+ public int getPhysicalAddress() {
+ enforceAccessPermission();
+ synchronized (mLock) {
+ return mPhysicalAddress;
+ }
+ }
+
+ @Override
public void setSystemAudioMode(final boolean enabled, final IHdmiControlCallback callback) {
enforceAccessPermission();
runOnServiceThread(new Runnable() {
@@ -1588,14 +1662,62 @@
public List<HdmiDeviceInfo> getDeviceList() {
enforceAccessPermission();
HdmiCecLocalDeviceTv tv = tv();
- synchronized (mLock) {
- return (tv == null)
+ if (tv != null) {
+ synchronized (mLock) {
+ return tv.getSafeCecDevicesLocked();
+ }
+ } else {
+ HdmiCecLocalDeviceAudioSystem audioSystem = audioSystem();
+ synchronized (mLock) {
+ return (audioSystem == null)
? Collections.<HdmiDeviceInfo>emptyList()
- : tv.getSafeCecDevicesLocked();
+ : audioSystem.getSafeCecDevicesLocked();
+ }
}
}
@Override
+ public void powerOffRemoteDevice(int logicalAddress, int powerStatus) {
+ enforceAccessPermission();
+ runOnServiceThread(new Runnable() {
+ @Override
+ public void run() {
+ Slog.w(TAG, "Device "
+ + logicalAddress + " power status is " + powerStatus
+ + " before standby command sent out");
+ sendCecCommand(HdmiCecMessageBuilder.buildStandby(
+ getRemoteControlSourceAddress(), logicalAddress));
+ }
+ });
+ }
+
+ @Override
+ public void powerOnRemoteDevice(int logicalAddress, int powerStatus) {
+ // TODO(amyjojo): implement the method
+ }
+
+ @Override
+ // TODO(AMYJOJO): add a result callback
+ public void askRemoteDeviceToBecomeActiveSource(int physicalAddress) {
+ enforceAccessPermission();
+ runOnServiceThread(new Runnable() {
+ @Override
+ public void run() {
+ HdmiCecMessage setStreamPath = HdmiCecMessageBuilder.buildSetStreamPath(
+ getRemoteControlSourceAddress(), physicalAddress);
+ if (pathToPortId(physicalAddress) != Constants.INVALID_PORT_ID) {
+ if (getSwitchDevice() != null) {
+ getSwitchDevice().handleSetStreamPath(setStreamPath);
+ } else {
+ Slog.e(TAG, "Can't get the correct local device to handle routing.");
+ }
+ }
+ sendCecCommand(setStreamPath);
+ }
+ });
+ }
+
+ @Override
public void setSystemAudioVolume(final int oldIndex, final int newIndex,
final int maxIndex) {
enforceAccessPermission();
@@ -1834,14 +1956,32 @@
Slog.w(TAG, "audio system is not in system audio mode");
return;
}
- int scaledVolume = VolumeControlAction.scaleToCecVolume(volume, maxVolume);
+ audioSystem().reportAudioStatus(Constants.ADDR_TV);
+ }
+ });
+ }
- sendCecCommand(HdmiCecMessageBuilder
- .buildReportAudioStatus(
- device.getDeviceInfo().getLogicalAddress(),
- Constants.ADDR_TV,
- scaledVolume,
- isMute));
+ @Override
+ public void setSystemAudioModeOnForAudioOnlySource() {
+ enforceAccessPermission();
+ runOnServiceThread(new Runnable() {
+ @Override
+ public void run() {
+ if (!isAudioSystemDevice()) {
+ Slog.e(TAG, "Not an audio system device. Won't set system audio mode on");
+ return;
+ }
+ if (audioSystem() == null) {
+ Slog.e(TAG, "Audio System local device is not registered");
+ return;
+ }
+ if (!audioSystem().checkSupportAndSetSystemAudioMode(true)) {
+ Slog.e(TAG, "System Audio Mode is not supported.");
+ return;
+ }
+ sendCecCommand(
+ HdmiCecMessageBuilder.buildSetSystemAudioMode(
+ audioSystem().mAddress, Constants.ADDR_BROADCAST, true));
}
});
}
@@ -1851,30 +1991,54 @@
if (!DumpUtils.checkDumpPermission(getContext(), TAG, writer)) return;
final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
- pw.println("mHdmiControlEnabled: " + mHdmiControlEnabled);
pw.println("mProhibitMode: " + mProhibitMode);
- if (mCecController != null) {
- pw.println("mCecController: ");
- pw.increaseIndent();
- mCecController.dump(pw);
- pw.decreaseIndent();
- }
+ pw.println("mPowerStatus: " + mPowerStatus);
+
+ // System settings
+ pw.println("System_settings:");
+ pw.increaseIndent();
+ pw.println("mHdmiControlEnabled: " + mHdmiControlEnabled);
+ pw.println("mMhlInputChangeEnabled: " + mMhlInputChangeEnabled);
+ pw.decreaseIndent();
pw.println("mMhlController: ");
pw.increaseIndent();
mMhlController.dump(pw);
pw.decreaseIndent();
- pw.println("mPortInfo: ");
- pw.increaseIndent();
- for (HdmiPortInfo hdmiPortInfo : mPortInfo) {
- pw.println("- " + hdmiPortInfo);
+ HdmiUtils.dumpIterable(pw, "mPortInfo:", mPortInfo);
+ if (mCecController != null) {
+ pw.println("mCecController: ");
+ pw.increaseIndent();
+ mCecController.dump(pw);
+ pw.decreaseIndent();
}
- pw.decreaseIndent();
- pw.println("mPowerStatus: " + mPowerStatus);
}
}
+ // Get the source address to send out commands to devices connected to the current device
+ // when other services interact with HdmiControlService.
+ private int getRemoteControlSourceAddress() {
+ if (isAudioSystemDevice()) {
+ return audioSystem().getDeviceInfo().getLogicalAddress();
+ } else if (isPlaybackDevice()) {
+ return playback().getDeviceInfo().getLogicalAddress();
+ }
+ return ADDR_UNREGISTERED;
+ }
+
+ // Get the switch device to do CEC routing control
+ @Nullable
+ private HdmiCecLocalDeviceSource getSwitchDevice() {
+ if (isAudioSystemDevice()) {
+ return audioSystem();
+ }
+ if (isPlaybackDevice()) {
+ return playback();
+ }
+ return null;
+ }
+
@ServiceThreadOnly
private void oneTouchPlay(final IHdmiControlCallback callback) {
assertRunOnServiceThread();
@@ -2549,14 +2713,14 @@
// For example, when receiving broadcast messages, all the device types will call this
// method but only one of them will be the Active Source.
protected void setAndBroadcastActiveSource(
- HdmiCecMessage message, int physicalAddress, int deviceType) {
+ int physicalAddress, int deviceType, int source) {
// If the device has both playback and audio system logical addresses,
// playback will claim active source. Otherwise audio system will.
if (deviceType == HdmiDeviceInfo.DEVICE_PLAYBACK) {
HdmiCecLocalDevicePlayback playback = playback();
playback.setIsActiveSource(true);
playback.wakeUpIfActiveSource();
- playback.maySendActiveSource(message.getSource());
+ playback.maySendActiveSource(source);
setActiveSource(playback.mAddress, physicalAddress);
}
@@ -2567,7 +2731,7 @@
} else {
audioSystem.setIsActiveSource(true);
audioSystem.wakeUpIfActiveSource();
- audioSystem.maySendActiveSource(message.getSource());
+ audioSystem.maySendActiveSource(source);
setActiveSource(audioSystem.mAddress, physicalAddress);
}
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiUtils.java b/services/core/java/com/android/server/hdmi/HdmiUtils.java
index 2a8117f..e44f1d1 100644
--- a/services/core/java/com/android/server/hdmi/HdmiUtils.java
+++ b/services/core/java/com/android/server/hdmi/HdmiUtils.java
@@ -16,19 +16,35 @@
package com.android.server.hdmi;
+import android.annotation.Nullable;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.Xml;
+import com.android.internal.util.HexDump;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.hdmi.Constants.AudioCodec;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.io.InputStream;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
+import java.util.Objects;
/**
* Various utilities to handle HDMI CEC messages.
*/
final class HdmiUtils {
+ private static final String TAG = "HdmiUtils";
+
private static final int[] ADDRESS_TO_TYPE = {
HdmiDeviceInfo.DEVICE_TV, // ADDR_TV
HdmiDeviceInfo.DEVICE_RECORDER, // ADDR_RECORDER_1
@@ -65,6 +81,12 @@
"Secondary_TV",
};
+ /**
+ * Return value of {@link #getLocalPortFromPhysicalAddress(int, int)}
+ */
+ static final int TARGET_NOT_UNDER_LOCAL_DEVICE = -1;
+ static final int TARGET_SAME_PHYSICAL_ADDRESS = 0;
+
private HdmiUtils() { /* cannot be instantiated */ }
/**
@@ -317,4 +339,339 @@
info.getPhysicalAddress(), info.getPortId(), info.getDeviceType(),
info.getVendorId(), info.getDisplayName(), newPowerStatus);
}
+
+ /**
+ * Dump a {@link SparseArray} to the print writer.
+ *
+ * <p>The dump is formatted:
+ * <pre>
+ * name:
+ * key = value
+ * key = value
+ * ...
+ * </pre>
+ */
+ static <T> void dumpSparseArray(IndentingPrintWriter pw, String name,
+ SparseArray<T> sparseArray) {
+ printWithTrailingColon(pw, name);
+ pw.increaseIndent();
+ int size = sparseArray.size();
+ for (int i = 0; i < size; i++) {
+ int key = sparseArray.keyAt(i);
+ T value = sparseArray.get(key);
+ pw.printPair(Integer.toString(key), value);
+ pw.println();
+ }
+ pw.decreaseIndent();
+ }
+
+ private static void printWithTrailingColon(IndentingPrintWriter pw, String name) {
+ pw.println(name.endsWith(":") ? name : name.concat(":"));
+ }
+
+ /**
+ * Dump a {@link Map} to the print writer.
+ *
+ * <p>The dump is formatted:
+ * <pre>
+ * name:
+ * key = value
+ * key = value
+ * ...
+ * </pre>
+ */
+ static <K, V> void dumpMap(IndentingPrintWriter pw, String name, Map<K, V> map) {
+ printWithTrailingColon(pw, name);
+ pw.increaseIndent();
+ for (Map.Entry<K, V> entry: map.entrySet()) {
+ pw.printPair(entry.getKey().toString(), entry.getValue());
+ pw.println();
+ }
+ pw.decreaseIndent();
+ }
+
+ /**
+ * Dump a {@link Map} to the print writer.
+ *
+ * <p>The dump is formatted:
+ * <pre>
+ * name:
+ * value
+ * value
+ * ...
+ * </pre>
+ */
+ static <T> void dumpIterable(IndentingPrintWriter pw, String name, Iterable<T> values) {
+ printWithTrailingColon(pw, name);
+ pw.increaseIndent();
+ for (T value : values) {
+ pw.println(value);
+ }
+ pw.decreaseIndent();
+ }
+
+ /**
+ * Method to parse target physical address to the port number on the current device.
+ *
+ * <p>This check assumes target address is valid.
+ *
+ * @param targetPhysicalAddress is the physical address of the target device
+ * @param myPhysicalAddress is the physical address of the current device
+ * @return
+ * If the target device is under the current device, return the port number of current device
+ * that the target device is connected to. This also applies to the devices that are indirectly
+ * connected to the current device.
+ *
+ * <p>If the target device has the same physical address as the current device, return
+ * {@link #TARGET_SAME_PHYSICAL_ADDRESS}.
+ *
+ * <p>If the target device is not under the current device, return
+ * {@link #TARGET_NOT_UNDER_LOCAL_DEVICE}.
+ */
+ public static int getLocalPortFromPhysicalAddress(
+ int targetPhysicalAddress, int myPhysicalAddress) {
+ if (myPhysicalAddress == targetPhysicalAddress) {
+ return TARGET_SAME_PHYSICAL_ADDRESS;
+ }
+
+ int mask = 0xF000;
+ int finalMask = 0xF000;
+ int maskedAddress = myPhysicalAddress;
+
+ while (maskedAddress != 0) {
+ maskedAddress = myPhysicalAddress & mask;
+ finalMask |= mask;
+ mask >>= 4;
+ }
+
+ int portAddress = targetPhysicalAddress & finalMask;
+ if ((portAddress & (finalMask << 4)) != myPhysicalAddress) {
+ return TARGET_NOT_UNDER_LOCAL_DEVICE;
+ }
+
+ mask <<= 4;
+ int port = portAddress & mask;
+ while ((port >> 4) != 0) {
+ port >>= 4;
+ }
+ return port;
+ }
+
+ public static class ShortAudioDescriptorXmlParser {
+ // We don't use namespaces
+ private static final String NS = null;
+
+ // return a list of devices config
+ public static List<DeviceConfig> parse(InputStream in)
+ throws XmlPullParserException, IOException {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
+ parser.setInput(in, null);
+ parser.nextTag();
+ return readDevices(parser);
+ }
+
+ private static void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
+ if (parser.getEventType() != XmlPullParser.START_TAG) {
+ throw new IllegalStateException();
+ }
+ int depth = 1;
+ while (depth != 0) {
+ switch (parser.next()) {
+ case XmlPullParser.END_TAG:
+ depth--;
+ break;
+ case XmlPullParser.START_TAG:
+ depth++;
+ break;
+ }
+ }
+ }
+
+ private static List<DeviceConfig> readDevices(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ List<DeviceConfig> devices = new ArrayList<>();
+
+ parser.require(XmlPullParser.START_TAG, NS, "config");
+ while (parser.next() != XmlPullParser.END_TAG) {
+ if (parser.getEventType() != XmlPullParser.START_TAG) {
+ continue;
+ }
+ String name = parser.getName();
+ // Starts by looking for the device tag
+ if (name.equals("device")) {
+ String deviceType = parser.getAttributeValue(null, "type");
+ DeviceConfig config = null;
+ if (deviceType != null) {
+ config = readDeviceConfig(parser, deviceType);
+ }
+ if (config != null) {
+ devices.add(config);
+ }
+ } else {
+ skip(parser);
+ }
+ }
+ return devices;
+ }
+
+ // Processes device tags in the config.
+ @Nullable
+ private static DeviceConfig readDeviceConfig(XmlPullParser parser, String deviceType)
+ throws XmlPullParserException, IOException {
+ List<CodecSad> codecSads = new ArrayList<>();
+ int format;
+ byte[] descriptor;
+
+ parser.require(XmlPullParser.START_TAG, NS, "device");
+ while (parser.next() != XmlPullParser.END_TAG) {
+ if (parser.getEventType() != XmlPullParser.START_TAG) {
+ continue;
+ }
+ String tagName = parser.getName();
+
+ // Starts by looking for the supportedFormat tag
+ if (tagName.equals("supportedFormat")) {
+ String codecAttriValue = parser.getAttributeValue(null, "format");
+ String sadAttriValue = parser.getAttributeValue(null, "descriptor");
+ format = (codecAttriValue) == null
+ ? Constants.AUDIO_CODEC_NONE : formatNameToNum(codecAttriValue);
+ descriptor = readSad(sadAttriValue);
+ if (format != Constants.AUDIO_CODEC_NONE && descriptor != null) {
+ codecSads.add(new CodecSad(format, descriptor));
+ }
+ parser.nextTag();
+ parser.require(XmlPullParser.END_TAG, NS, "supportedFormat");
+ } else {
+ skip(parser);
+ }
+ }
+ if (codecSads.size() == 0) {
+ return null;
+ }
+ return new DeviceConfig(deviceType, codecSads);
+ }
+
+ // Processes sad attribute in the supportedFormat.
+ @Nullable
+ private static byte[] readSad(String sad) {
+ if (sad == null || sad.length() == 0) {
+ return null;
+ }
+ byte[] sadBytes = HexDump.hexStringToByteArray(sad);
+ if (sadBytes.length != 3) {
+ Slog.w(TAG, "SAD byte array length is not 3. Length = " + sadBytes.length);
+ return null;
+ }
+ return sadBytes;
+ }
+
+ @AudioCodec
+ private static int formatNameToNum(String codecAttriValue) {
+ switch (codecAttriValue) {
+ case "AUDIO_FORMAT_NONE":
+ return Constants.AUDIO_CODEC_NONE;
+ case "AUDIO_FORMAT_LPCM":
+ return Constants.AUDIO_CODEC_LPCM;
+ case "AUDIO_FORMAT_DD":
+ return Constants.AUDIO_CODEC_DD;
+ case "AUDIO_FORMAT_MPEG1":
+ return Constants.AUDIO_CODEC_MPEG1;
+ case "AUDIO_FORMAT_MP3":
+ return Constants.AUDIO_CODEC_MP3;
+ case "AUDIO_FORMAT_MPEG2":
+ return Constants.AUDIO_CODEC_MPEG2;
+ case "AUDIO_FORMAT_AAC":
+ return Constants.AUDIO_CODEC_AAC;
+ case "AUDIO_FORMAT_DTS":
+ return Constants.AUDIO_CODEC_DTS;
+ case "AUDIO_FORMAT_ATRAC":
+ return Constants.AUDIO_CODEC_ATRAC;
+ case "AUDIO_FORMAT_ONEBITAUDIO":
+ return Constants.AUDIO_CODEC_ONEBITAUDIO;
+ case "AUDIO_FORMAT_DDP":
+ return Constants.AUDIO_CODEC_DDP;
+ case "AUDIO_FORMAT_DTSHD":
+ return Constants.AUDIO_CODEC_DTSHD;
+ case "AUDIO_FORMAT_TRUEHD":
+ return Constants.AUDIO_CODEC_TRUEHD;
+ case "AUDIO_FORMAT_DST":
+ return Constants.AUDIO_CODEC_DST;
+ case "AUDIO_FORMAT_WMAPRO":
+ return Constants.AUDIO_CODEC_WMAPRO;
+ case "AUDIO_FORMAT_MAX":
+ return Constants.AUDIO_CODEC_MAX;
+ default:
+ return Constants.AUDIO_CODEC_NONE;
+ }
+ }
+ }
+
+ // Device configuration of its supported Codecs and their Short Audio Descriptors.
+ public static class DeviceConfig {
+ /** Name of the device. Should be {@link Constants.AudioDevice}. **/
+ public final String name;
+ /** List of a {@link CodecSad}. **/
+ public final List<CodecSad> supportedCodecs;
+
+ public DeviceConfig(String name, List<CodecSad> supportedCodecs) {
+ this.name = name;
+ this.supportedCodecs = supportedCodecs;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof DeviceConfig) {
+ DeviceConfig that = (DeviceConfig) obj;
+ return that.name.equals(this.name)
+ && that.supportedCodecs.equals(this.supportedCodecs);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ name,
+ supportedCodecs.hashCode());
+ }
+ }
+
+ // Short Audio Descriptor of a specific Codec
+ public static class CodecSad {
+ /** Audio Codec. Should be {@link Constants.AudioCodec}. **/
+ public final int audioCodec;
+ /**
+ * Three-byte Short Audio Descriptor. See HDMI Specification 1.4b CEC 13.15.3 and
+ * ANSI-CTA-861-F-FINAL 7.5.2 Audio Data Block for more details.
+ */
+ public final byte[] sad;
+
+ public CodecSad(int audioCodec, byte[] sad) {
+ this.audioCodec = audioCodec;
+ this.sad = sad;
+ }
+
+ public CodecSad(int audioCodec, String sad) {
+ this.audioCodec = audioCodec;
+ this.sad = HexDump.hexStringToByteArray(sad);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof CodecSad) {
+ CodecSad that = (CodecSad) obj;
+ return that.audioCodec == this.audioCodec
+ && Arrays.equals(that.sad, this.sad);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ audioCodec,
+ Arrays.hashCode(sad));
+ }
+ }
}
diff --git a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
index 41bf01f..354d8d1 100644
--- a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
+++ b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
@@ -92,6 +92,9 @@
if (source.mService.audioSystem() != null) {
source = source.mService.audioSystem();
}
+ if (source.getLocalActivePort() != Constants.CEC_SWITCH_HOME) {
+ source.switchInputOnReceivingNewActivePath(getSourcePath());
+ }
source.setRoutingPort(Constants.CEC_SWITCH_HOME);
source.setLocalActivePort(Constants.CEC_SWITCH_HOME);
}
diff --git a/services/core/java/com/android/server/job/controllers/QuotaController.java b/services/core/java/com/android/server/job/controllers/QuotaController.java
index ac2dbdf..c16d1b4 100644
--- a/services/core/java/com/android/server/job/controllers/QuotaController.java
+++ b/services/core/java/com/android/server/job/controllers/QuotaController.java
@@ -26,7 +26,10 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
import android.app.AlarmManager;
+import android.app.IUidObserver;
import android.app.usage.UsageStatsManagerInternal;
import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener;
import android.content.BroadcastReceiver;
@@ -38,12 +41,14 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.RemoteException;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
@@ -69,6 +74,11 @@
* bucket, it will be eligible to run. When a job's bucket changes, its new quota is immediately
* applied to it.
*
+ * Jobs are throttled while an app is not in a foreground state. All jobs are allowed to run
+ * freely when an app enters the foreground state and are restricted when the app leaves the
+ * foreground state. However, jobs that are started while the app is in the TOP state are not
+ * restricted regardless of the app's state change.
+ *
* Test: atest com.android.server.job.controllers.QuotaControllerTest
*/
public final class QuotaController extends StateController {
@@ -97,6 +107,12 @@
data.put(packageName, obj);
}
+ public void clear() {
+ for (int i = 0; i < mData.size(); ++i) {
+ mData.valueAt(i).clear();
+ }
+ }
+
/** Removes all the data for the user, if there was any. */
public void delete(int userId) {
mData.delete(userId);
@@ -119,6 +135,11 @@
return null;
}
+ /** @see SparseArray#indexOfKey */
+ public int indexOfKey(int userId) {
+ return mData.indexOfKey(userId);
+ }
+
/** Returns the userId at the given index. */
public int keyAt(int index) {
return mData.keyAt(index);
@@ -294,6 +315,17 @@
/** Cached calculation results for each app, with the standby buckets as the array indices. */
private final UserPackageMap<ExecutionStats[]> mExecutionStatsCache = new UserPackageMap<>();
+ /** List of UIDs currently in the foreground. */
+ private final SparseBooleanArray mForegroundUids = new SparseBooleanArray();
+
+ /**
+ * List of jobs that started while the UID was in the TOP state. There will be no more than
+ * 16 ({@link JobSchedulerService.MAX_JOB_CONTEXTS_COUNT}) running at once, so an ArraySet is
+ * fine.
+ */
+ private final ArraySet<JobStatus> mTopStartedJobs = new ArraySet<>();
+
+ private final ActivityManagerInternal mActivityManagerInternal;
private final AlarmManager mAlarmManager;
private final ChargingTracker mChargeTracker;
private final Handler mHandler;
@@ -343,6 +375,29 @@
}
};
+ private final IUidObserver mUidObserver = new IUidObserver.Stub() {
+ @Override
+ public void onUidStateChanged(int uid, int procState, long procStateSeq) {
+ mHandler.obtainMessage(MSG_UID_PROCESS_STATE_CHANGED, uid, procState).sendToTarget();
+ }
+
+ @Override
+ public void onUidGone(int uid, boolean disabled) {
+ }
+
+ @Override
+ public void onUidActive(int uid) {
+ }
+
+ @Override
+ public void onUidIdle(int uid, boolean disabled) {
+ }
+
+ @Override
+ public void onUidCachedChanged(int uid, boolean cached) {
+ }
+ };
+
/**
* The rolling window size for each standby bucket. Within each window, an app will have 10
* minutes to run its jobs.
@@ -363,12 +418,15 @@
private static final int MSG_CLEAN_UP_SESSIONS = 1;
/** Check if a package is now within its quota. */
private static final int MSG_CHECK_PACKAGE = 2;
+ /** Process state for a UID has changed. */
+ private static final int MSG_UID_PROCESS_STATE_CHANGED = 3;
public QuotaController(JobSchedulerService service) {
super(service);
mHandler = new QcHandler(mContext.getMainLooper());
mChargeTracker = new ChargingTracker();
mChargeTracker.startTracking();
+ mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
// Set up the app standby bucketing tracker
@@ -376,6 +434,14 @@
UsageStatsManagerInternal.class);
usageStats.addAppIdleStateChangeListener(new StandbyTracker());
+ try {
+ ActivityManager.getService().registerUidObserver(mUidObserver,
+ ActivityManager.UID_OBSERVER_PROCSTATE,
+ ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, null);
+ } catch (RemoteException e) {
+ // ignored; both services live in system_server
+ }
+
onConstantsUpdatedLocked();
}
@@ -399,11 +465,15 @@
if (DEBUG) Slog.d(TAG, "Prepping for " + jobStatus.toShortString());
final int userId = jobStatus.getSourceUserId();
final String packageName = jobStatus.getSourcePackageName();
+ final int uid = jobStatus.getSourceUid();
Timer timer = mPkgTimers.get(userId, packageName);
if (timer == null) {
- timer = new Timer(userId, packageName);
+ timer = new Timer(uid, userId, packageName);
mPkgTimers.add(userId, packageName, timer);
}
+ if (mActivityManagerInternal.getUidProcessState(uid) == ActivityManager.PROCESS_STATE_TOP) {
+ mTopStartedJobs.add(jobStatus);
+ }
timer.startTrackingJob(jobStatus);
}
@@ -421,6 +491,7 @@
if (jobs != null) {
jobs.remove(jobStatus);
}
+ mTopStartedJobs.remove(jobStatus);
}
}
@@ -511,6 +582,7 @@
mInQuotaAlarmListeners.delete(userId, packageName);
}
mExecutionStatsCache.delete(userId, packageName);
+ mForegroundUids.delete(uid);
}
@Override
@@ -522,6 +594,20 @@
mExecutionStatsCache.delete(userId);
}
+ private boolean isUidInForeground(int uid) {
+ if (UserHandle.isCore(uid)) {
+ return true;
+ }
+ synchronized (mLock) {
+ return mForegroundUids.get(uid);
+ }
+ }
+
+ /** @return true if the job was started while the app was in the TOP state. */
+ private boolean isTopStartedJob(@NonNull final JobStatus jobStatus) {
+ return mTopStartedJobs.contains(jobStatus);
+ }
+
/**
* Returns an appropriate standby bucket for the job, taking into account any standby
* exemptions.
@@ -537,9 +623,15 @@
private boolean isWithinQuotaLocked(@NonNull final JobStatus jobStatus) {
final int standbyBucket = getEffectiveStandbyBucket(jobStatus);
- // Jobs for the active app should always be able to run.
- return jobStatus.uidActive || isWithinQuotaLocked(
- jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(), standbyBucket);
+ Timer timer = mPkgTimers.get(jobStatus.getSourceUserId(), jobStatus.getSourcePackageName());
+ // A job is within quota if one of the following is true:
+ // 1. it was started while the app was in the TOP state
+ // 2. the app is currently in the foreground
+ // 3. the app overall is within its quota
+ return isTopStartedJob(jobStatus)
+ || isUidInForeground(jobStatus.getSourceUid())
+ || isWithinQuotaLocked(
+ jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(), standbyBucket);
}
private boolean isWithinQuotaLocked(final int userId, @NonNull final String packageName,
@@ -800,7 +892,7 @@
final boolean isCharging = mChargeTracker.isCharging();
if (DEBUG) Slog.d(TAG, "handleNewChargingStateLocked: " + isCharging);
// Deal with Timers first.
- mPkgTimers.forEach((t) -> t.onChargingChanged(nowElapsed, isCharging));
+ mPkgTimers.forEach((t) -> t.onStateChanged(nowElapsed, isCharging));
// Now update jobs.
maybeUpdateAllConstraintsLocked();
}
@@ -837,10 +929,15 @@
boolean changed = false;
for (int i = jobs.size() - 1; i >= 0; --i) {
final JobStatus js = jobs.valueAt(i);
- if (js.uidActive) {
- // Jobs for the active app should always be able to run.
+ if (isTopStartedJob(js)) {
+ // Job was started while the app was in the TOP state so we should allow it to
+ // finish.
changed |= js.setQuotaConstraintSatisfied(true);
- } else if (realStandbyBucket == getEffectiveStandbyBucket(js)) {
+ } else if (realStandbyBucket != ACTIVE_INDEX
+ && realStandbyBucket == getEffectiveStandbyBucket(js)) {
+ // An app in the ACTIVE bucket may be out of quota while the job could be in quota
+ // for some reason. Therefore, avoid setting the real value here and check each job
+ // individually.
changed |= js.setQuotaConstraintSatisfied(realInQuota);
} else {
// This job is somehow exempted. Need to determine its own quota status.
@@ -854,7 +951,7 @@
maybeScheduleStartAlarmLocked(userId, packageName, realStandbyBucket);
} else {
QcAlarmListener alarmListener = mInQuotaAlarmListeners.get(userId, packageName);
- if (alarmListener != null) {
+ if (alarmListener != null && alarmListener.isWaiting()) {
mAlarmManager.cancel(alarmListener);
// Set the trigger time to 0 so that the alarm doesn't think it's still waiting.
alarmListener.setTriggerTime(0);
@@ -863,6 +960,56 @@
return changed;
}
+ private class UidConstraintUpdater implements Consumer<JobStatus> {
+ private final UserPackageMap<Integer> mToScheduleStartAlarms = new UserPackageMap<>();
+ public boolean wasJobChanged;
+
+ @Override
+ public void accept(JobStatus jobStatus) {
+ wasJobChanged |= jobStatus.setQuotaConstraintSatisfied(isWithinQuotaLocked(jobStatus));
+ final int userId = jobStatus.getSourceUserId();
+ final String packageName = jobStatus.getSourcePackageName();
+ final int realStandbyBucket = jobStatus.getStandbyBucket();
+ if (isWithinQuotaLocked(userId, packageName, realStandbyBucket)) {
+ QcAlarmListener alarmListener = mInQuotaAlarmListeners.get(userId, packageName);
+ if (alarmListener != null && alarmListener.isWaiting()) {
+ mAlarmManager.cancel(alarmListener);
+ // Set the trigger time to 0 so that the alarm doesn't think it's still waiting.
+ alarmListener.setTriggerTime(0);
+ }
+ } else {
+ mToScheduleStartAlarms.add(userId, packageName, realStandbyBucket);
+ }
+ }
+
+ void postProcess() {
+ for (int u = 0; u < mToScheduleStartAlarms.numUsers(); ++u) {
+ final int userId = mToScheduleStartAlarms.keyAt(u);
+ for (int p = 0; p < mToScheduleStartAlarms.numPackagesForUser(userId); ++p) {
+ final String packageName = mToScheduleStartAlarms.keyAt(u, p);
+ final int standbyBucket = mToScheduleStartAlarms.get(userId, packageName);
+ maybeScheduleStartAlarmLocked(userId, packageName, standbyBucket);
+ }
+ }
+ }
+
+ void reset() {
+ wasJobChanged = false;
+ mToScheduleStartAlarms.clear();
+ }
+ }
+
+ private final UidConstraintUpdater mUpdateUidConstraints = new UidConstraintUpdater();
+
+ private boolean maybeUpdateConstraintForUidLocked(final int uid) {
+ mService.getJobStore().forEachJobForSourceUid(uid, mUpdateUidConstraints);
+
+ mUpdateUidConstraints.postProcess();
+ boolean changed = mUpdateUidConstraints.wasJobChanged;
+ mUpdateUidConstraints.reset();
+ return changed;
+ }
+
/**
* Maybe schedule a non-wakeup alarm for the next time this package will have quota to run
* again. This should only be called if the package is already out of quota.
@@ -1052,6 +1199,7 @@
private final class Timer {
private final Package mPkg;
+ private final int mUid;
// List of jobs currently running for this app that started when the app wasn't in the
// foreground.
@@ -1059,16 +1207,18 @@
private long mStartTimeElapsed;
private int mBgJobCount;
- Timer(int userId, String packageName) {
+ Timer(int uid, int userId, String packageName) {
mPkg = new Package(userId, packageName);
+ mUid = uid;
}
void startTrackingJob(@NonNull JobStatus jobStatus) {
- if (jobStatus.uidActive) {
- // We intentionally don't pay attention to fg state changes after a job has started.
+ if (isTopStartedJob(jobStatus)) {
+ // We intentionally don't pay attention to fg state changes after a TOP job has
+ // started.
if (DEBUG) {
Slog.v(TAG,
- "Timer ignoring " + jobStatus.toShortString() + " because uidActive");
+ "Timer ignoring " + jobStatus.toShortString() + " because isTop");
}
return;
}
@@ -1076,7 +1226,7 @@
synchronized (mLock) {
// Always track jobs, even when charging.
mRunningBgJobs.add(jobStatus);
- if (!mChargeTracker.isCharging()) {
+ if (shouldTrackLocked()) {
mBgJobCount++;
if (mRunningBgJobs.size() == 1) {
// Started tracking the first job.
@@ -1142,6 +1292,10 @@
}
}
+ boolean isRunning(JobStatus jobStatus) {
+ return mRunningBgJobs.contains(jobStatus);
+ }
+
long getCurrentDuration(long nowElapsed) {
synchronized (mLock) {
return !isActive() ? 0 : nowElapsed - mStartTimeElapsed;
@@ -1154,17 +1308,21 @@
}
}
- void onChargingChanged(long nowElapsed, boolean isCharging) {
+ private boolean shouldTrackLocked() {
+ return !mChargeTracker.isCharging() && !mForegroundUids.get(mUid);
+ }
+
+ void onStateChanged(long nowElapsed, boolean isQuotaFree) {
synchronized (mLock) {
- if (isCharging) {
+ if (isQuotaFree) {
emitSessionLocked(nowElapsed);
- } else {
+ } else if (shouldTrackLocked()) {
// Start timing from unplug.
if (mRunningBgJobs.size() > 0) {
mStartTimeElapsed = nowElapsed;
// NOTE: this does have the unfortunate consequence that if the device is
- // repeatedly plugged in and unplugged, the job count for a package may be
- // artificially high.
+ // repeatedly plugged in and unplugged, or an app changes foreground state
+ // very frequently, the job count for a package may be artificially high.
mBgJobCount = mRunningBgJobs.size();
// Starting the timer means that all cached execution stats are now
// incorrect.
@@ -1371,6 +1529,38 @@
}
break;
}
+ case MSG_UID_PROCESS_STATE_CHANGED: {
+ final int uid = msg.arg1;
+ final int procState = msg.arg2;
+ final int userId = UserHandle.getUserId(uid);
+ final long nowElapsed = sElapsedRealtimeClock.millis();
+
+ synchronized (mLock) {
+ boolean isQuotaFree;
+ if (procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
+ mForegroundUids.put(uid, true);
+ isQuotaFree = true;
+ } else {
+ mForegroundUids.delete(uid);
+ isQuotaFree = false;
+ }
+ // Update Timers first.
+ final int userIndex = mPkgTimers.indexOfKey(userId);
+ if (userIndex != -1) {
+ final int numPkgs = mPkgTimers.numPackagesForUser(userId);
+ for (int p = 0; p < numPkgs; ++p) {
+ Timer t = mPkgTimers.valueAt(userIndex, p);
+ if (t != null) {
+ t.onStateChanged(nowElapsed, isQuotaFree);
+ }
+ }
+ }
+ if (maybeUpdateConstraintForUidLocked(uid)) {
+ mStateChangedListener.onControllerStateChanged();
+ }
+ }
+ break;
+ }
}
}
}
@@ -1420,6 +1610,12 @@
@VisibleForTesting
@NonNull
+ SparseBooleanArray getForegroundUids() {
+ return mForegroundUids;
+ }
+
+ @VisibleForTesting
+ @NonNull
Handler getHandler() {
return mHandler;
}
@@ -1450,6 +1646,10 @@
pw.println("In parole: " + mInParole);
pw.println();
+ pw.print("Foreground UIDs: ");
+ pw.println(mForegroundUids.toString());
+ pw.println();
+
mTrackedJobs.forEach((jobs) -> {
for (int j = 0; j < jobs.size(); j++) {
final JobStatus js = jobs.valueAt(j);
@@ -1460,6 +1660,9 @@
js.printUniqueId(pw);
pw.print(" from ");
UserHandle.formatUid(pw, js.getSourceUid());
+ if (mTopStartedJobs.contains(js)) {
+ pw.print(" (TOP)");
+ }
pw.println();
pw.increaseIndent();
@@ -1511,6 +1714,11 @@
proto.write(StateControllerProto.QuotaController.IS_CHARGING, mChargeTracker.isCharging());
proto.write(StateControllerProto.QuotaController.IS_IN_PAROLE, mInParole);
+ for (int i = 0; i < mForegroundUids.size(); ++i) {
+ proto.write(StateControllerProto.QuotaController.FOREGROUND_UIDS,
+ mForegroundUids.keyAt(i));
+ }
+
mTrackedJobs.forEach((jobs) -> {
for (int j = 0; j < jobs.size(); j++) {
final JobStatus js = jobs.valueAt(j);
@@ -1526,6 +1734,8 @@
proto.write(
StateControllerProto.QuotaController.TrackedJob.EFFECTIVE_STANDBY_BUCKET,
getEffectiveStandbyBucket(js));
+ proto.write(StateControllerProto.QuotaController.TrackedJob.IS_TOP_STARTED_JOB,
+ mTopStartedJobs.contains(js));
proto.write(StateControllerProto.QuotaController.TrackedJob.HAS_QUOTA,
js.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
proto.write(StateControllerProto.QuotaController.TrackedJob.REMAINING_QUOTA_MS,
diff --git a/services/core/java/com/android/server/location/GnssConfiguration.java b/services/core/java/com/android/server/location/GnssConfiguration.java
index 29465ad..9e33943 100644
--- a/services/core/java/com/android/server/location/GnssConfiguration.java
+++ b/services/core/java/com/android/server/location/GnssConfiguration.java
@@ -29,7 +29,10 @@
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
@@ -66,6 +69,7 @@
"USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL";
private static final String CONFIG_GPS_LOCK = "GPS_LOCK";
private static final String CONFIG_ES_EXTENSION_SEC = "ES_EXTENSION_SEC";
+ public static final String CONFIG_NFW_PROXY_APPS = "NFW_PROXY_APPS";
// Limit on NI emergency mode time extension after emergency sessions ends
private static final int MAX_EMERGENCY_MODE_EXTENSION_SECONDS = 300; // 5 minute maximum
@@ -171,6 +175,32 @@
}
/**
+ * Returns the list of proxy apps from the value of config parameter NFW_PROXY_APPS or
+ * {@Collections.EMPTY_LIST} if no value is provided.
+ */
+ List<String> getProxyApps() {
+ // Space separated list of Android proxy app package names.
+ String proxyAppsStr = mProperties.getProperty(CONFIG_NFW_PROXY_APPS);
+ if (TextUtils.isEmpty(proxyAppsStr)) {
+ return Collections.EMPTY_LIST;
+ }
+
+ String[] proxyAppsArray = proxyAppsStr.trim().split("\\s+");
+ if (proxyAppsArray.length == 0) {
+ return Collections.EMPTY_LIST;
+ }
+
+ // TODO(b/122856486): Validate proxy app names so that a system app or some popular app
+ // with location permission is not specified as a proxy app.
+ ArrayList proxyApps = new ArrayList(proxyAppsArray.length);
+ for (String proxyApp : proxyAppsArray) {
+ proxyApps.add(proxyApp);
+ }
+
+ return proxyApps;
+ }
+
+ /**
* Updates the GNSS HAL satellite blacklist.
*/
void setSatelliteBlacklist(int[] constellations, int[] svids) {
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 269767a..d346ddc 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -64,6 +64,7 @@
import android.telephony.gsm.GsmCellLocation;
import android.text.TextUtils;
import android.util.Log;
+import android.util.StatsLog;
import com.android.internal.app.IBatteryStats;
import com.android.internal.location.GpsNetInitiatedHandler;
@@ -371,6 +372,7 @@
private boolean mSuplEsEnabled = false;
private final Context mContext;
+ private final Looper mLooper;
private final LocationExtras mLocationExtras = new LocationExtras();
private final GnssStatusListenerHelper mGnssStatusListenerHelper;
private final GnssSatelliteBlacklistHelper mGnssSatelliteBlacklistHelper;
@@ -381,6 +383,7 @@
private final NtpTimeHelper mNtpTimeHelper;
private final GnssBatchingProvider mGnssBatchingProvider;
private final GnssGeofenceProvider mGnssGeofenceProvider;
+ private GnssVisibilityControl mGnssVisibilityControl;
// Handler for processing events
private Handler mHandler;
@@ -555,6 +558,9 @@
mC2KServerPort = mGnssConfiguration.getC2KPort(TCP_MIN_PORT);
mNIHandler.setEmergencyExtensionSeconds(mGnssConfiguration.getEsExtensionSec());
mSuplEsEnabled = mGnssConfiguration.getSuplEs(0) == 1;
+ if (mGnssVisibilityControl != null) {
+ mGnssVisibilityControl.updateProxyApps(mGnssConfiguration.getProxyApps());
+ }
}
public GnssLocationProvider(Context context, LocationProviderManager locationProviderManager,
@@ -562,6 +568,7 @@
super(locationProviderManager);
mContext = context;
+ mLooper = looper;
// Create a wake lock
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
@@ -1704,6 +1711,24 @@
", response: " + userResponse);
}
native_send_ni_response(notificationId, userResponse);
+
+ StatsLog.write(StatsLog.GNSS_NI_EVENT_REPORTED,
+ StatsLog.GNSS_NI_EVENT_REPORTED__EVENT_TYPE__NI_RESPONSE,
+ notificationId,
+ /* niType= */ 0,
+ /* needNotify= */ false,
+ /* needVerify= */ false,
+ /* privacyOverride= */ false,
+ /* timeout= */ 0,
+ /* defaultResponse= */ 0,
+ /* requestorId= */ null,
+ /* text= */ null,
+ /* requestorIdEncoding= */ 0,
+ /* textEncoding= */ 0,
+ mSuplEsEnabled,
+ mEnabled,
+ userResponse);
+
return true;
}
};
@@ -1753,6 +1778,22 @@
notification.textEncoding = textEncoding;
mNIHandler.handleNiNotification(notification);
+ StatsLog.write(StatsLog.GNSS_NI_EVENT_REPORTED,
+ StatsLog.GNSS_NI_EVENT_REPORTED__EVENT_TYPE__NI_REQUEST,
+ notification.notificationId,
+ notification.niType,
+ notification.needNotify,
+ notification.needVerify,
+ notification.privacyOverride,
+ notification.timeout,
+ notification.defaultResponse,
+ notification.requestorId,
+ notification.text,
+ notification.requestorIdEncoding,
+ notification.textEncoding,
+ mSuplEsEnabled,
+ mEnabled,
+ /* userResponse= */ 0);
}
/**
@@ -1834,6 +1875,27 @@
}
}
+ // Implements method nfwNotifyCb() in IGnssVisibilityControlCallback.hal.
+ @NativeEntryPoint
+ private void reportNfwNotification(String proxyAppPackageName, byte protocolStack,
+ String otherProtocolStackName, byte requestor, String requestorId, byte responseType,
+ boolean inEmergencyMode, boolean isCachedLocation) {
+ if (mGnssVisibilityControl == null) {
+ Log.e(TAG, "reportNfwNotification: mGnssVisibilityControl is not initialized.");
+ return;
+ }
+
+ mGnssVisibilityControl.reportNfwNotification(proxyAppPackageName, protocolStack,
+ otherProtocolStackName, requestor, requestorId, responseType, inEmergencyMode,
+ isCachedLocation);
+ }
+
+ // Implements method isInEmergencySession() in IGnssVisibilityControlCallback.hal.
+ @NativeEntryPoint
+ boolean isInEmergencySession() {
+ return mNIHandler.getInEmergency();
+ }
+
private void sendMessage(int message, int arg, Object obj) {
// hold a wake lock until this message is delivered
// note that this assumes the message will not be removed from the queue before
@@ -1922,6 +1984,10 @@
native_cleanup();
}
+ if (native_is_gnss_visibility_control_supported()) {
+ mGnssVisibilityControl = new GnssVisibilityControl(mContext, mLooper);
+ }
+
// load default GPS configuration
// (this configuration might change in the future based on SIM changes)
reloadGpsProperties();
@@ -2079,6 +2145,8 @@
private static native boolean native_is_supported();
+ private static native boolean native_is_gnss_visibility_control_supported();
+
private static native void native_init_once();
private native boolean native_init();
diff --git a/services/core/java/com/android/server/location/GnssVisibilityControl.java b/services/core/java/com/android/server/location/GnssVisibilityControl.java
new file mode 100644
index 0000000..845aa9d
--- /dev/null
+++ b/services/core/java/com/android/server/location/GnssVisibilityControl.java
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location;
+
+import android.annotation.SuppressLint;
+import android.app.AppOpsManager;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Handles GNSS non-framework location access user visibility and control.
+ *
+ * The state of the GnssVisibilityControl object must be accessed/modified through the Handler
+ * thread only.
+ */
+class GnssVisibilityControl {
+ private static final String TAG = "GnssVisibilityControl";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ // Constants related to non-framework (NFW) location access permission proxy apps.
+ private static final String NFW_PROXY_APP_PKG_ACTIVITY_NAME_SUFFIX =
+ ".NonFrameworkLocationAccessActivity";
+ private static final String NFW_INTENT_ACTION_NFW_LOCATION_ACCESS_SUFFIX =
+ ".intent.action.NON_FRAMEWORK_LOCATION_ACCESS";
+ private static final String NFW_INTENT_TYPE = "text/plain";
+
+ private static final String LOCATION_PERMISSION_NAME =
+ "android.permission.ACCESS_FINE_LOCATION";
+
+ // Wakelocks
+ private static final String WAKELOCK_KEY = TAG;
+ private static final long WAKELOCK_TIMEOUT_MILLIS = 60 * 1000;
+ private final PowerManager.WakeLock mWakeLock;
+
+ private final AppOpsManager mAppOps;
+ private final PackageManager mPackageManager;
+
+ private final Handler mHandler;
+ private final Context mContext;
+
+ // Number of non-framework location access proxy apps is expected to be small (< 5).
+ private static final int HASH_MAP_INITIAL_CAPACITY_PROXY_APP_TO_LOCATION_PERMISSIONS = 7;
+ private HashMap<String, Boolean> mProxyAppToLocationPermissions = new HashMap<>(
+ HASH_MAP_INITIAL_CAPACITY_PROXY_APP_TO_LOCATION_PERMISSIONS);
+
+ private PackageManager.OnPermissionsChangedListener mOnPermissionsChangedListener =
+ uid -> postEvent(() -> handlePermissionsChanged(uid));
+
+ GnssVisibilityControl(Context context, Looper looper) {
+ mContext = context;
+ PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+ mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
+ mHandler = new Handler(looper);
+ mAppOps = mContext.getSystemService(AppOpsManager.class);
+ mPackageManager = mContext.getPackageManager();
+ // TODO(b/122855984): Handle global location settings on/off.
+ // TODO(b/122856189): Handle roaming case.
+ }
+
+ void updateProxyApps(List<String> nfwLocationAccessProxyApps) {
+ // NOTE: This class doesn't explicitly register and listen for SIM_STATE_CHANGED event
+ // but rather piggy backs on the GnssLocationProvider SIM_STATE_CHANGED handling
+ // so that the order of processing is preserved. GnssLocationProvider should
+ // first load the new config parameters for the new SIM and then call this method.
+ postEvent(() -> handleSubscriptionOrSimChanged(nfwLocationAccessProxyApps));
+ }
+
+ void reportNfwNotification(String proxyAppPackageName, byte protocolStack,
+ String otherProtocolStackName, byte requestor, String requestorId, byte responseType,
+ boolean inEmergencyMode, boolean isCachedLocation) {
+ postEvent(() -> handleNfwNotification(
+ new NfwNotification(proxyAppPackageName, protocolStack, otherProtocolStackName,
+ requestor, requestorId, responseType, inEmergencyMode, isCachedLocation)));
+ }
+
+ private void handleSubscriptionOrSimChanged(List<String> nfwLocationAccessProxyApps) {
+ if (nfwLocationAccessProxyApps.isEmpty()) {
+ // Stop listening for app permission changes. Clear the app list in GNSS HAL.
+ if (!mProxyAppToLocationPermissions.isEmpty()) {
+ mPackageManager.removeOnPermissionsChangeListener(mOnPermissionsChangedListener);
+ mProxyAppToLocationPermissions.clear();
+ updateNfwLocationAccessProxyAppsInGnssHal();
+ }
+ return;
+ }
+
+ if (mProxyAppToLocationPermissions.isEmpty()) {
+ mPackageManager.addOnPermissionsChangeListener(mOnPermissionsChangedListener);
+ } else {
+ mProxyAppToLocationPermissions.clear();
+ }
+
+ for (String proxApp : nfwLocationAccessProxyApps) {
+ mProxyAppToLocationPermissions.put(proxApp, hasLocationPermission(proxApp));
+ }
+
+ updateNfwLocationAccessProxyAppsInGnssHal();
+ }
+
+ // Represents NfwNotification structure in IGnssVisibilityControlCallback.hal
+ private static class NfwNotification {
+ private static final String KEY_PROTOCOL_STACK = "ProtocolStack";
+ private static final String KEY_OTHER_PROTOCOL_STACK_NAME = "OtherProtocolStackName";
+ private static final String KEY_REQUESTOR = "Requestor";
+ private static final String KEY_REQUESTOR_ID = "RequestorId";
+ private static final String KEY_RESPONSE_TYPE = "ResponseType";
+ private static final String KEY_IN_EMERGENCY_MODE = "InEmergencyMode";
+ private static final String KEY_IS_CACHED_LOCATION = "IsCachedLocation";
+
+ // This must match with NfwResponseType enum in IGnssVisibilityControlCallback.hal.
+ private static final byte NFW_RESPONSE_TYPE_REJECTED = 0;
+ private static final byte NFW_RESPONSE_TYPE_ACCEPTED_NO_LOCATION_PROVIDED = 1;
+ private static final byte NFW_RESPONSE_TYPE_ACCEPTED_LOCATION_PROVIDED = 2;
+
+ private final String mProxyAppPackageName;
+ private final byte mProtocolStack;
+ private final String mOtherProtocolStackName;
+ private final byte mRequestor;
+ private final String mRequestorId;
+ private final byte mResponseType;
+ private final boolean mInEmergencyMode;
+ private final boolean mIsCachedLocation;
+
+ NfwNotification(String proxyAppPackageName, byte protocolStack,
+ String otherProtocolStackName, byte requestor, String requestorId,
+ byte responseType, boolean inEmergencyMode, boolean isCachedLocation) {
+ mProxyAppPackageName = proxyAppPackageName;
+ mProtocolStack = protocolStack;
+ mOtherProtocolStackName = otherProtocolStackName;
+ mRequestor = requestor;
+ mRequestorId = requestorId;
+ mResponseType = responseType;
+ mInEmergencyMode = inEmergencyMode;
+ mIsCachedLocation = isCachedLocation;
+ }
+
+ void copyFieldsToIntent(Intent intent) {
+ intent.putExtra(KEY_PROTOCOL_STACK, mProtocolStack);
+ if (!TextUtils.isEmpty(mOtherProtocolStackName)) {
+ intent.putExtra(KEY_OTHER_PROTOCOL_STACK_NAME, mOtherProtocolStackName);
+ }
+ intent.putExtra(KEY_REQUESTOR, mRequestor);
+ if (!TextUtils.isEmpty(mRequestorId)) {
+ intent.putExtra(KEY_REQUESTOR_ID, mRequestorId);
+ }
+ intent.putExtra(KEY_RESPONSE_TYPE, mResponseType);
+ intent.putExtra(KEY_IN_EMERGENCY_MODE, mInEmergencyMode);
+ if (mResponseType == NFW_RESPONSE_TYPE_ACCEPTED_LOCATION_PROVIDED) {
+ intent.putExtra(KEY_IS_CACHED_LOCATION, mIsCachedLocation);
+ }
+ }
+
+ @SuppressLint("DefaultLocale")
+ public String toString() {
+ return String.format(
+ "[Notification] proxyAppPackageName: %s, protocolStack: %d"
+ + ", otherProtocolStackName: %s, requestor: %d, requestorId: %s"
+ + ", responseType: %d, inEmergencyMode: %b, isCachedLocation: %b",
+ mProxyAppPackageName, mProtocolStack, mOtherProtocolStackName,
+ mRequestor, mRequestorId, mResponseType, mInEmergencyMode, mIsCachedLocation);
+ }
+
+ String getResponseTypeAsString() {
+ switch (mResponseType) {
+ case NFW_RESPONSE_TYPE_REJECTED:
+ return "REJECTED";
+ case NFW_RESPONSE_TYPE_ACCEPTED_NO_LOCATION_PROVIDED:
+ return "ACCEPTED_NO_LOCATION_PROVIDED";
+ case NFW_RESPONSE_TYPE_ACCEPTED_LOCATION_PROVIDED:
+ return "ACCEPTED_LOCATION_PROVIDED";
+ default:
+ return "<Unknown>";
+ }
+ }
+ }
+
+ private void handlePermissionsChanged(int uid) {
+ if (mProxyAppToLocationPermissions.isEmpty()) {
+ return;
+ }
+
+ for (Map.Entry<String, Boolean> entry : mProxyAppToLocationPermissions.entrySet()) {
+ // Cannot cache uid since the application could be uninstalled and reinstalled.
+ final String proxyApp = entry.getKey();
+ final Integer nfwProxyAppUid = getApplicationUid(proxyApp);
+ if (nfwProxyAppUid == null || nfwProxyAppUid != uid) {
+ continue;
+ }
+
+ final boolean isLocationPermissionEnabled = hasLocationPermission(proxyApp);
+ if (isLocationPermissionEnabled != entry.getValue()) {
+ Log.i(TAG, "Location permission setting is changed to "
+ + (isLocationPermissionEnabled ? "enabled" : "disabled")
+ + " for non-framework location access proxy app "
+ + proxyApp);
+ entry.setValue(isLocationPermissionEnabled);
+ updateNfwLocationAccessProxyAppsInGnssHal();
+ return;
+ }
+ }
+ }
+
+ private Integer getApplicationUid(String pkgName) {
+ try {
+ return mPackageManager.getApplicationInfo(pkgName, 0).uid;
+ } catch (PackageManager.NameNotFoundException e) {
+ if (DEBUG) {
+ Log.d(TAG, "Non-framework location access proxy app "
+ + pkgName + " is not found.");
+ }
+ return null;
+ }
+ }
+
+ private boolean hasLocationPermission(String pkgName) {
+ return mPackageManager.checkPermission(LOCATION_PERMISSION_NAME, pkgName)
+ == PackageManager.PERMISSION_GRANTED;
+ }
+
+ private void updateNfwLocationAccessProxyAppsInGnssHal() {
+ // Get a count of proxy apps with location permission enabled to array creation size.
+ int countLocationPermissionEnabledProxyApps = 0;
+ for (Boolean hasLocationPermissionEnabled : mProxyAppToLocationPermissions.values()) {
+ if (hasLocationPermissionEnabled) {
+ ++countLocationPermissionEnabledProxyApps;
+ }
+ }
+
+ int i = 0;
+ String[] locationPermissionEnabledProxyApps =
+ new String[countLocationPermissionEnabledProxyApps];
+ for (Map.Entry<String, Boolean> entry : mProxyAppToLocationPermissions.entrySet()) {
+ final String proxyApp = entry.getKey();
+ final boolean hasLocationPermissionEnabled = entry.getValue();
+ if (hasLocationPermissionEnabled) {
+ locationPermissionEnabledProxyApps[i++] = proxyApp;
+ }
+ }
+
+ String proxyAppsStr = Arrays.toString(locationPermissionEnabledProxyApps);
+ Log.i(TAG, "Updating non-framework location access proxy apps in the GNSS HAL to: "
+ + proxyAppsStr);
+ boolean result = native_enable_nfw_location_access(locationPermissionEnabledProxyApps);
+ if (!result) {
+ Log.e(TAG, "Failed to update non-framework location access proxy apps in the"
+ + " GNSS HAL to: " + proxyAppsStr);
+ }
+ }
+
+ private void handleNfwNotification(NfwNotification nfwNotification) {
+ if (DEBUG) Log.d(TAG, nfwNotification.toString());
+
+ final String proxyAppPackageName = nfwNotification.mProxyAppPackageName;
+ if (TextUtils.isEmpty(proxyAppPackageName)) {
+ Log.e(TAG, "ProxyAppPackageName field is not set. Not sending intent to proxy app for "
+ + nfwNotification);
+ return;
+ }
+
+ Boolean isLocationPermissionEnabled = mProxyAppToLocationPermissions.get(
+ proxyAppPackageName);
+ if (isLocationPermissionEnabled == null) {
+ // App is not in the configured list.
+ Log.e(TAG, "Could not find proxy app with name: " + proxyAppPackageName + " in the "
+ + "value specified for config parameter: "
+ + GnssConfiguration.CONFIG_NFW_PROXY_APPS + ". Not sending intent to proxy app"
+ + " for " + nfwNotification);
+ return;
+ }
+
+ // Send intent to non-framework location proxy app with notification information.
+ final Intent intent = new Intent(
+ proxyAppPackageName + NFW_INTENT_ACTION_NFW_LOCATION_ACCESS_SUFFIX);
+ final String proxAppActivityName =
+ proxyAppPackageName + NFW_PROXY_APP_PKG_ACTIVITY_NAME_SUFFIX;
+ intent.setClassName(proxyAppPackageName, proxAppActivityName);
+ intent.setType(NFW_INTENT_TYPE);
+ nfwNotification.copyFieldsToIntent(intent);
+
+ // Check if the proxy app is still installed.
+ final Integer clsAppUid = getApplicationUid(proxyAppPackageName);
+ if (clsAppUid == null || intent.resolveActivity(mPackageManager) == null) {
+ Log.i(TAG, "Proxy application " + proxyAppPackageName + " and/or activity "
+ + proxAppActivityName + " is not found. Not sending"
+ + " intent to proxy app for " + nfwNotification);
+ return;
+ }
+
+ // Display location icon attributed to this proxy app.
+ mAppOps.noteOpNoThrow(AppOpsManager.OP_FINE_LOCATION, clsAppUid, proxyAppPackageName);
+
+ // Log proxy app permission mismatch between framework and GNSS HAL.
+ boolean isLocationRequestAccepted =
+ nfwNotification.mResponseType != NfwNotification.NFW_RESPONSE_TYPE_REJECTED;
+ if (isLocationPermissionEnabled != isLocationRequestAccepted) {
+ Log.w(TAG, "Permission mismatch. Framework proxy app " + proxyAppPackageName
+ + " location permission is set to " + isLocationPermissionEnabled
+ + " but GNSS non-framework location access response type is "
+ + nfwNotification.getResponseTypeAsString() + " for " + nfwNotification);
+ }
+
+ // Notify proxy app.
+ try {
+ if (DEBUG) {
+ Log.d(TAG, "Sending non-framework location access notification intent: " + intent);
+ }
+ mContext.startActivityAsUser(intent, UserHandle.getUserHandleForUid(clsAppUid));
+ } catch (ActivityNotFoundException e) {
+ Log.w(TAG, "Activity not found. Failed to send non-framework location access"
+ + " notification intent to proxy app activity: " + proxAppActivityName);
+ }
+ }
+
+ private void postEvent(Runnable event) {
+ // Hold a wake lock until this message is delivered.
+ // Note that this assumes the message will not be removed from the queue before
+ // it is handled (otherwise the wake lock would be leaked).
+ mWakeLock.acquire(WAKELOCK_TIMEOUT_MILLIS);
+ if (!mHandler.post(runEventAndReleaseWakeLock(event))) {
+ mWakeLock.release();
+ }
+ }
+
+ private Runnable runEventAndReleaseWakeLock(Runnable event) {
+ return () -> {
+ try {
+ event.run();
+ } finally {
+ mWakeLock.release();
+ }
+ };
+ }
+
+ private native boolean native_enable_nfw_location_access(String[] proxyApps);
+}
diff --git a/services/core/java/com/android/server/location/MockProvider.java b/services/core/java/com/android/server/location/MockProvider.java
index 86bc9f3..fe91c63 100644
--- a/services/core/java/com/android/server/location/MockProvider.java
+++ b/services/core/java/com/android/server/location/MockProvider.java
@@ -52,7 +52,6 @@
mExtras = null;
setProperties(properties);
- setEnabled(true);
}
/** Sets the enabled state of this mock provider. */
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index d611a17..7fffe8e 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -80,7 +80,7 @@
private final ControllerStub mController;
private final SessionStub mSession;
private final SessionCb mSessionCb;
- private final MediaSessionService mService;
+ private final MediaSessionService.ServiceImpl mService;
private final Context mContext;
private final Object mLock = new Object();
@@ -120,7 +120,8 @@
private String mMetadataDescription;
public MediaSessionRecord(int ownerPid, int ownerUid, int userId, String ownerPackageName,
- SessionCallbackLink cb, String tag, MediaSessionService service, Looper handlerLooper) {
+ SessionCallbackLink cb, String tag, MediaSessionService.ServiceImpl service,
+ Looper handlerLooper) {
mOwnerPid = ownerPid;
mOwnerUid = ownerUid;
mUserId = userId;
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index ba7b87e..d20ed8c 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -16,79 +16,15 @@
package com.android.server.media;
-import static android.os.UserHandle.USER_ALL;
-
-import android.annotation.Nullable;
-import android.app.ActivityManager;
-import android.app.INotificationManager;
-import android.app.KeyguardManager;
-import android.app.PendingIntent;
-import android.app.PendingIntent.CanceledException;
-import android.content.ActivityNotFoundException;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.ContentResolver;
import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ServiceInfo;
-import android.content.pm.UserInfo;
-import android.database.ContentObserver;
-import android.media.AudioManager;
-import android.media.AudioManagerInternal;
-import android.media.AudioPlaybackConfiguration;
-import android.media.AudioSystem;
-import android.media.IAudioService;
-import android.media.IRemoteVolumeController;
-import android.media.MediaController2;
-import android.media.Session2CommandGroup;
import android.media.Session2Token;
-import android.media.session.IActiveSessionsListener;
-import android.media.session.ICallback;
-import android.media.session.IOnMediaKeyListener;
-import android.media.session.IOnVolumeKeyLongPressListener;
-import android.media.session.ISession;
-import android.media.session.ISession2TokensListener;
-import android.media.session.ISessionManager;
-import android.media.session.MediaSession;
-import android.media.session.MediaSessionManager;
-import android.media.session.SessionCallbackLink;
-import android.net.Uri;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.HandlerExecutor;
import android.os.IBinder;
-import android.os.Message;
-import android.os.PowerManager;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.ResultReceiver;
-import android.os.ServiceManager;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.provider.Settings;
-import android.speech.RecognizerIntent;
-import android.text.TextUtils;
import android.util.Log;
-import android.util.Slog;
-import android.util.SparseArray;
-import android.util.SparseIntArray;
-import android.view.KeyEvent;
-import android.view.ViewConfiguration;
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.DumpUtils;
-import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.Watchdog;
import com.android.server.Watchdog.Monitor;
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
import java.util.List;
/**
@@ -97,2040 +33,124 @@
public class MediaSessionService extends SystemService implements Monitor {
private static final String TAG = "MediaSessionService";
static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- // Leave log for key event always.
- private static final boolean DEBUG_KEY_EVENT = true;
- private static final int WAKELOCK_TIMEOUT = 5000;
- private static final int MEDIA_KEY_LISTENER_TIMEOUT = 1000;
-
- private final SessionManagerImpl mSessionManagerImpl;
- private final MessageHandler mHandler = new MessageHandler();
- private final PowerManager.WakeLock mMediaEventWakeLock;
- private final int mLongPressTimeout;
- private final INotificationManager mNotificationManager;
- private final Object mLock = new Object();
- // Keeps the full user id for each user.
- @GuardedBy("mLock")
- private final SparseIntArray mFullUserIds = new SparseIntArray();
- @GuardedBy("mLock")
- private final SparseArray<FullUserRecord> mUserRecords = new SparseArray<FullUserRecord>();
- @GuardedBy("mLock")
- private final ArrayList<SessionsListenerRecord> mSessionsListeners
- = new ArrayList<SessionsListenerRecord>();
- // Map user id as index to list of Session2Tokens
- // TODO: Keep session2 info in MediaSessionStack for prioritizing both session1 and session2 in
- // one place.
- @GuardedBy("mLock")
- private final SparseArray<List<Session2Token>> mSession2TokensPerUser = new SparseArray<>();
- @GuardedBy("mLock")
- private final List<Session2TokensListenerRecord> mSession2TokensListenerRecords =
- new ArrayList<>();
-
- private KeyguardManager mKeyguardManager;
- private IAudioService mAudioService;
- private AudioManagerInternal mAudioManagerInternal;
- private ActivityManager mActivityManager;
- private ContentResolver mContentResolver;
- private SettingsObserver mSettingsObserver;
- private boolean mHasFeatureLeanback;
-
- // The FullUserRecord of the current users. (i.e. The foreground user that isn't a profile)
- // It's always not null after the MediaSessionService is started.
- private FullUserRecord mCurrentFullUserRecord;
- private MediaSessionRecord mGlobalPrioritySession;
- private AudioPlayerStateMonitor mAudioPlayerStateMonitor;
-
- // Used to notify system UI when remote volume was changed. TODO find a
- // better way to handle this.
- private IRemoteVolumeController mRvc;
+ private final ServiceImpl mImpl;
public MediaSessionService(Context context) {
super(context);
- mSessionManagerImpl = new SessionManagerImpl();
- PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
- mMediaEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleMediaEvent");
- mLongPressTimeout = ViewConfiguration.getLongPressTimeout();
- mNotificationManager = INotificationManager.Stub.asInterface(
- ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+ mImpl = new MediaSessionServiceImpl(context);
}
@Override
public void onStart() {
- publishBinderService(Context.MEDIA_SESSION_SERVICE, mSessionManagerImpl);
+ publishBinderService(Context.MEDIA_SESSION_SERVICE, mImpl.getServiceBinder());
Watchdog.getInstance().addMonitor(this);
- mKeyguardManager =
- (KeyguardManager) getContext().getSystemService(Context.KEYGUARD_SERVICE);
- mAudioService = getAudioService();
- mAudioManagerInternal = LocalServices.getService(AudioManagerInternal.class);
- mActivityManager =
- (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE);
- mAudioPlayerStateMonitor = AudioPlayerStateMonitor.getInstance();
- mAudioPlayerStateMonitor.registerListener(
- (config, isRemoved) -> {
- if (isRemoved || !config.isActive() || config.getPlayerType()
- == AudioPlaybackConfiguration.PLAYER_TYPE_JAM_SOUNDPOOL) {
- return;
- }
- synchronized (mLock) {
- FullUserRecord user = getFullUserRecordLocked(
- UserHandle.getUserId(config.getClientUid()));
- if (user != null) {
- user.mPriorityStack.updateMediaButtonSessionIfNeeded();
- }
- }
- }, null /* handler */);
- mAudioPlayerStateMonitor.registerSelfIntoAudioServiceIfNeeded(mAudioService);
- mContentResolver = getContext().getContentResolver();
- mSettingsObserver = new SettingsObserver();
- mSettingsObserver.observe();
- mHasFeatureLeanback = getContext().getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_LEANBACK);
- updateUser();
+ mImpl.onStart();
}
- private IAudioService getAudioService() {
- IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
- return IAudioService.Stub.asInterface(b);
+ @Override
+ public void onStartUser(int userId) {
+ mImpl.onStartUser(userId);
}
- private boolean isGlobalPriorityActiveLocked() {
- return mGlobalPrioritySession != null && mGlobalPrioritySession.isActive();
+ @Override
+ public void onSwitchUser(int userId) {
+ mImpl.onSwitchUser(userId);
}
+ // Called when the user with the userId is removed.
+ @Override
+ public void onStopUser(int userId) {
+ mImpl.onStopUser(userId);
+ }
+
+ @Override
+ public void monitor() {
+ mImpl.monitor();
+ }
+
+ /**
+ * Updates session.
+ */
public void updateSession(MediaSessionRecord record) {
- synchronized (mLock) {
- FullUserRecord user = getFullUserRecordLocked(record.getUserId());
- if (user == null) {
- Log.w(TAG, "Unknown session updated. Ignoring.");
- return;
- }
- if ((record.getFlags() & MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0) {
- if (DEBUG_KEY_EVENT) {
- Log.d(TAG, "Global priority session is updated, active=" + record.isActive());
- }
- user.pushAddressedPlayerChangedLocked();
- } else {
- if (!user.mPriorityStack.contains(record)) {
- Log.w(TAG, "Unknown session updated. Ignoring.");
- return;
- }
- user.mPriorityStack.onSessionStateChange(record);
- }
- mHandler.postSessionsChanged(record.getUserId());
- }
+ mImpl.updateSession(record);
}
+ /**
+ * Sets global priority session.
+ */
public void setGlobalPrioritySession(MediaSessionRecord record) {
- synchronized (mLock) {
- FullUserRecord user = getFullUserRecordLocked(record.getUserId());
- if (mGlobalPrioritySession != record) {
- Log.d(TAG, "Global priority session is changed from " + mGlobalPrioritySession
- + " to " + record);
- mGlobalPrioritySession = record;
- if (user != null && user.mPriorityStack.contains(record)) {
- // Handle the global priority session separately.
- // Otherwise, it can be the media button session regardless of the active state
- // because it or other system components might have been the lastly played media
- // app.
- user.mPriorityStack.removeSession(record);
- }
- }
- }
- }
-
- private List<MediaSessionRecord> getActiveSessionsLocked(int userId) {
- List<MediaSessionRecord> records = new ArrayList<>();
- if (userId == USER_ALL) {
- int size = mUserRecords.size();
- for (int i = 0; i < size; i++) {
- records.addAll(mUserRecords.valueAt(i).mPriorityStack.getActiveSessions(userId));
- }
- } else {
- FullUserRecord user = getFullUserRecordLocked(userId);
- if (user == null) {
- Log.w(TAG, "getSessions failed. Unknown user " + userId);
- return records;
- }
- records.addAll(user.mPriorityStack.getActiveSessions(userId));
- }
-
- // Return global priority session at the first whenever it's asked.
- if (isGlobalPriorityActiveLocked()
- && (userId == USER_ALL || userId == mGlobalPrioritySession.getUserId())) {
- records.add(0, mGlobalPrioritySession);
- }
- return records;
+ mImpl.setGlobalPrioritySession(record);
}
List<Session2Token> getSession2TokensLocked(int userId) {
- List<Session2Token> list = new ArrayList<>();
- if (userId == USER_ALL) {
- for (int i = 0; i < mSession2TokensPerUser.size(); i++) {
- list.addAll(mSession2TokensPerUser.valueAt(i));
- }
- } else {
- list.addAll(mSession2TokensPerUser.get(userId));
- }
- return list;
+ return mImpl.getSession2TokensLocked(userId);
}
/**
* Tells the system UI that volume has changed on an active remote session.
*/
public void notifyRemoteVolumeChanged(int flags, MediaSessionRecord session) {
- if (mRvc == null || !session.isActive()) {
- return;
- }
- try {
- mRvc.remoteVolumeChanged(session.getControllerBinder(), flags);
- } catch (Exception e) {
- Log.wtf(TAG, "Error sending volume change to system UI.", e);
- }
+ mImpl.notifyRemoteVolumeChanged(flags, session);
}
+ /**
+ * Called when session playstate is changed.
+ */
public void onSessionPlaystateChanged(MediaSessionRecord record, int oldState, int newState) {
- synchronized (mLock) {
- FullUserRecord user = getFullUserRecordLocked(record.getUserId());
- if (user == null || !user.mPriorityStack.contains(record)) {
- Log.d(TAG, "Unknown session changed playback state. Ignoring.");
- return;
- }
- user.mPriorityStack.onPlaystateChanged(record, oldState, newState);
- }
+ mImpl.onSessionPlaystateChanged(record, oldState, newState);
}
+ /**
+ * Called when session playback type is changed.
+ */
public void onSessionPlaybackTypeChanged(MediaSessionRecord record) {
- synchronized (mLock) {
- FullUserRecord user = getFullUserRecordLocked(record.getUserId());
- if (user == null || !user.mPriorityStack.contains(record)) {
- Log.d(TAG, "Unknown session changed playback type. Ignoring.");
- return;
- }
- pushRemoteVolumeUpdateLocked(record.getUserId());
- }
- }
-
- @Override
- public void onStartUser(int userId) {
- if (DEBUG) Log.d(TAG, "onStartUser: " + userId);
- updateUser();
- }
-
- @Override
- public void onSwitchUser(int userId) {
- if (DEBUG) Log.d(TAG, "onSwitchUser: " + userId);
- updateUser();
- }
-
- // Called when the user with the userId is removed.
- @Override
- public void onStopUser(int userId) {
- if (DEBUG) Log.d(TAG, "onStopUser: " + userId);
- synchronized (mLock) {
- // TODO: Also handle removing user in updateUser() because adding/switching user is
- // handled in updateUser().
- FullUserRecord user = getFullUserRecordLocked(userId);
- if (user != null) {
- if (user.mFullUserId == userId) {
- user.destroySessionsForUserLocked(USER_ALL);
- mUserRecords.remove(userId);
- } else {
- user.destroySessionsForUserLocked(userId);
- }
- }
- mSession2TokensPerUser.remove(userId);
- updateUser();
- }
- }
-
- @Override
- public void monitor() {
- synchronized (mLock) {
- // Check for deadlock
- }
+ mImpl.onSessionPlaybackTypeChanged(record);
}
protected void enforcePhoneStatePermission(int pid, int uid) {
- if (getContext().checkPermission(android.Manifest.permission.MODIFY_PHONE_STATE, pid, uid)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Must hold the MODIFY_PHONE_STATE permission.");
- }
+ mImpl.enforcePhoneStatePermission(pid, uid);
}
void sessionDied(MediaSessionRecord session) {
- synchronized (mLock) {
- destroySessionLocked(session);
- }
+ mImpl.sessionDied(session);
}
void destroySession(MediaSessionRecord session) {
- synchronized (mLock) {
- destroySessionLocked(session);
- }
- }
-
- private void updateUser() {
- synchronized (mLock) {
- UserManager manager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
- mFullUserIds.clear();
- List<UserInfo> allUsers = manager.getUsers();
- if (allUsers != null) {
- for (UserInfo userInfo : allUsers) {
- if (userInfo.isManagedProfile()) {
- mFullUserIds.put(userInfo.id, userInfo.profileGroupId);
- } else {
- mFullUserIds.put(userInfo.id, userInfo.id);
- if (mUserRecords.get(userInfo.id) == null) {
- mUserRecords.put(userInfo.id, new FullUserRecord(userInfo.id));
- }
- }
- if (mSession2TokensPerUser.get(userInfo.id) == null) {
- mSession2TokensPerUser.put(userInfo.id, new ArrayList<>());
- }
- }
- }
- // Ensure that the current full user exists.
- int currentFullUserId = ActivityManager.getCurrentUser();
- mCurrentFullUserRecord = mUserRecords.get(currentFullUserId);
- if (mCurrentFullUserRecord == null) {
- Log.w(TAG, "Cannot find FullUserInfo for the current user " + currentFullUserId);
- mCurrentFullUserRecord = new FullUserRecord(currentFullUserId);
- mUserRecords.put(currentFullUserId, mCurrentFullUserRecord);
- if (mSession2TokensPerUser.get(currentFullUserId) == null) {
- mSession2TokensPerUser.put(currentFullUserId, new ArrayList<>());
- }
- }
- mFullUserIds.put(currentFullUserId, currentFullUserId);
- }
- }
-
- private void updateActiveSessionListeners() {
- synchronized (mLock) {
- for (int i = mSessionsListeners.size() - 1; i >= 0; i--) {
- SessionsListenerRecord listener = mSessionsListeners.get(i);
- try {
- enforceMediaPermissions(listener.componentName, listener.pid, listener.uid,
- listener.userId);
- } catch (SecurityException e) {
- Log.i(TAG, "ActiveSessionsListener " + listener.componentName
- + " is no longer authorized. Disconnecting.");
- mSessionsListeners.remove(i);
- try {
- listener.listener
- .onActiveSessionsChanged(new ArrayList<MediaSession.Token>());
- } catch (Exception e1) {
- // ignore
- }
- }
- }
- }
- }
-
- /*
- * When a session is removed several things need to happen.
- * 1. We need to remove it from the relevant user.
- * 2. We need to remove it from the priority stack.
- * 3. We need to remove it from all sessions.
- * 4. If this is the system priority session we need to clear it.
- * 5. We need to unlink to death from the cb binder
- * 6. We need to tell the session to do any final cleanup (onDestroy)
- */
- private void destroySessionLocked(MediaSessionRecord session) {
- if (DEBUG) {
- Log.d(TAG, "Destroying " + session);
- }
- FullUserRecord user = getFullUserRecordLocked(session.getUserId());
- if (mGlobalPrioritySession == session) {
- mGlobalPrioritySession = null;
- if (session.isActive() && user != null) {
- user.pushAddressedPlayerChangedLocked();
- }
- } else {
- if (user != null) {
- user.mPriorityStack.removeSession(session);
- }
- }
-
- try {
- session.getCallback().getBinder().unlinkToDeath(session, 0);
- } catch (Exception e) {
- // ignore exceptions while destroying a session.
- }
- session.onDestroy();
- mHandler.postSessionsChanged(session.getUserId());
- }
-
- private void enforcePackageName(String packageName, int uid) {
- if (TextUtils.isEmpty(packageName)) {
- throw new IllegalArgumentException("packageName may not be empty");
- }
- String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
- final int packageCount = packages.length;
- for (int i = 0; i < packageCount; i++) {
- if (packageName.equals(packages[i])) {
- return;
- }
- }
- throw new IllegalArgumentException("packageName is not owned by the calling process");
- }
-
- /**
- * Checks a caller's authorization to register an IRemoteControlDisplay.
- * Authorization is granted if one of the following is true:
- * <ul>
- * <li>the caller has android.Manifest.permission.MEDIA_CONTENT_CONTROL
- * permission</li>
- * <li>the caller's listener is one of the enabled notification listeners
- * for the caller's user</li>
- * </ul>
- */
- private void enforceMediaPermissions(ComponentName compName, int pid, int uid,
- int resolvedUserId) {
- if (isCurrentVolumeController(pid, uid)) return;
- if (getContext()
- .checkPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid)
- != PackageManager.PERMISSION_GRANTED
- && !isEnabledNotificationListener(compName, UserHandle.getUserId(uid),
- resolvedUserId)) {
- throw new SecurityException("Missing permission to control media.");
- }
- }
-
- private boolean isCurrentVolumeController(int pid, int uid) {
- return getContext().checkPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
- pid, uid) == PackageManager.PERMISSION_GRANTED;
- }
-
- private void enforceSystemUiPermission(String action, int pid, int uid) {
- if (!isCurrentVolumeController(pid, uid)) {
- throw new SecurityException("Only system ui may " + action);
- }
- }
-
- /**
- * This checks if the component is an enabled notification listener for the
- * specified user. Enabled components may only operate on behalf of the user
- * they're running as.
- *
- * @param compName The component that is enabled.
- * @param userId The user id of the caller.
- * @param forUserId The user id they're making the request on behalf of.
- * @return True if the component is enabled, false otherwise
- */
- private boolean isEnabledNotificationListener(ComponentName compName, int userId,
- int forUserId) {
- if (userId != forUserId) {
- // You may not access another user's content as an enabled listener.
- return false;
- }
- if (DEBUG) {
- Log.d(TAG, "Checking if enabled notification listener " + compName);
- }
- if (compName != null) {
- try {
- return mNotificationManager.isNotificationListenerAccessGrantedForUser(
- compName, userId);
- } catch(RemoteException e) {
- Log.w(TAG, "Dead NotificationManager in isEnabledNotificationListener", e);
- }
- }
- return false;
- }
-
- private MediaSessionRecord createSessionInternal(int callerPid, int callerUid, int userId,
- String callerPackageName, SessionCallbackLink cb, String tag) throws RemoteException {
- synchronized (mLock) {
- return createSessionLocked(callerPid, callerUid, userId, callerPackageName, cb, tag);
- }
- }
-
- /*
- * When a session is created the following things need to happen.
- * 1. Its callback binder needs a link to death
- * 2. It needs to be added to all sessions.
- * 3. It needs to be added to the priority stack.
- * 4. It needs to be added to the relevant user record.
- */
- private MediaSessionRecord createSessionLocked(int callerPid, int callerUid, int userId,
- String callerPackageName, SessionCallbackLink cb, String tag) {
- FullUserRecord user = getFullUserRecordLocked(userId);
- if (user == null) {
- Log.wtf(TAG, "Request from invalid user: " + userId);
- throw new RuntimeException("Session request from invalid user.");
- }
-
- final MediaSessionRecord session = new MediaSessionRecord(callerPid, callerUid, userId,
- callerPackageName, cb, tag, this, mHandler.getLooper());
- try {
- cb.getBinder().linkToDeath(session, 0);
- } catch (RemoteException e) {
- throw new RuntimeException("Media Session owner died prematurely.", e);
- }
-
- user.mPriorityStack.addSession(session);
- mHandler.postSessionsChanged(userId);
-
- if (DEBUG) {
- Log.d(TAG, "Created session for " + callerPackageName + " with tag " + tag);
- }
- return session;
- }
-
- private int findIndexOfSessionsListenerLocked(IActiveSessionsListener listener) {
- for (int i = mSessionsListeners.size() - 1; i >= 0; i--) {
- if (mSessionsListeners.get(i).listener.asBinder() == listener.asBinder()) {
- return i;
- }
- }
- return -1;
- }
-
- private int findIndexOfSession2TokensListenerLocked(ISession2TokensListener listener) {
- for (int i = mSession2TokensListenerRecords.size() - 1; i >= 0; i--) {
- if (mSession2TokensListenerRecords.get(i).listener.asBinder() == listener.asBinder()) {
- return i;
- }
- }
- return -1;
- }
-
-
- private void pushSessionsChanged(int userId) {
- synchronized (mLock) {
- FullUserRecord user = getFullUserRecordLocked(userId);
- if (user == null) {
- Log.w(TAG, "pushSessionsChanged failed. No user with id=" + userId);
- return;
- }
- List<MediaSessionRecord> records = getActiveSessionsLocked(userId);
- int size = records.size();
- ArrayList<MediaSession.Token> tokens = new ArrayList<MediaSession.Token>();
- for (int i = 0; i < size; i++) {
- tokens.add(new MediaSession.Token(records.get(i).getControllerBinder()));
- }
- pushRemoteVolumeUpdateLocked(userId);
- for (int i = mSessionsListeners.size() - 1; i >= 0; i--) {
- SessionsListenerRecord record = mSessionsListeners.get(i);
- if (record.userId == USER_ALL || record.userId == userId) {
- try {
- record.listener.onActiveSessionsChanged(tokens);
- } catch (RemoteException e) {
- Log.w(TAG, "Dead ActiveSessionsListener in pushSessionsChanged, removing",
- e);
- mSessionsListeners.remove(i);
- }
- }
- }
- }
- }
-
- private void pushRemoteVolumeUpdateLocked(int userId) {
- if (mRvc != null) {
- try {
- FullUserRecord user = getFullUserRecordLocked(userId);
- if (user == null) {
- Log.w(TAG, "pushRemoteVolumeUpdateLocked failed. No user with id=" + userId);
- return;
- }
- MediaSessionRecord record = user.mPriorityStack.getDefaultRemoteSession(userId);
- mRvc.updateRemoteController(record == null ? null : record.getControllerBinder());
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error sending default remote volume to sys ui.", e);
- }
- }
+ mImpl.destroySession(session);
}
void pushSession2TokensChangedLocked(int userId) {
- List<Session2Token> allSession2Tokens = getSession2TokensLocked(USER_ALL);
- List<Session2Token> session2Tokens = getSession2TokensLocked(userId);
-
- for (int i = mSession2TokensListenerRecords.size() - 1; i >= 0; i--) {
- Session2TokensListenerRecord listenerRecord = mSession2TokensListenerRecords.get(i);
- try {
- if (listenerRecord.userId == USER_ALL) {
- listenerRecord.listener.onSession2TokensChanged(allSession2Tokens);
- } else if (listenerRecord.userId == userId) {
- listenerRecord.listener.onSession2TokensChanged(session2Tokens);
- }
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to notify Session2Token change. Removing listener.", e);
- mSession2TokensListenerRecords.remove(i);
- }
- }
+ mImpl.pushSession2TokensChangedLocked(userId);
}
/**
- * Called when the media button receiver for the {@param record} is changed.
- *
- * @param record the media session whose media button receiver is updated.
+ * Called when media button receiver changed.
*/
public void onMediaButtonReceiverChanged(MediaSessionRecord record) {
- synchronized (mLock) {
- FullUserRecord user = getFullUserRecordLocked(record.getUserId());
- MediaSessionRecord mediaButtonSession =
- user.mPriorityStack.getMediaButtonSession();
- if (record == mediaButtonSession) {
- user.rememberMediaButtonReceiverLocked(mediaButtonSession);
- }
- }
+ mImpl.onMediaButtonReceiverChanged(record);
}
- private String getCallingPackageName(int uid) {
- String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
- if (packages != null && packages.length > 0) {
- return packages[0];
- }
- return "";
- }
-
- private void dispatchVolumeKeyLongPressLocked(KeyEvent keyEvent) {
- if (mCurrentFullUserRecord.mOnVolumeKeyLongPressListener == null) {
- return;
- }
- try {
- mCurrentFullUserRecord.mOnVolumeKeyLongPressListener.onVolumeKeyLongPress(keyEvent);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to send " + keyEvent + " to volume key long-press listener");
- }
- }
-
- private FullUserRecord getFullUserRecordLocked(int userId) {
- int fullUserId = mFullUserIds.get(userId, -1);
- if (fullUserId < 0) {
- return null;
- }
- return mUserRecords.get(fullUserId);
- }
-
- /**
- * Information about a full user and its corresponding managed profiles.
- *
- * <p>Since the full user runs together with its managed profiles, a user wouldn't differentiate
- * them when he/she presses a media/volume button. So keeping media sessions for them in one
- * place makes more sense and increases the readability.</p>
- * <p>The contents of this object is guarded by {@link #mLock}.
- */
- final class FullUserRecord implements MediaSessionStack.OnMediaButtonSessionChangedListener {
- public static final int COMPONENT_TYPE_INVALID = 0;
- public static final int COMPONENT_TYPE_BROADCAST = 1;
- public static final int COMPONENT_TYPE_ACTIVITY = 2;
- public static final int COMPONENT_TYPE_SERVICE = 3;
- private static final String COMPONENT_NAME_USER_ID_DELIM = ",";
-
- private final int mFullUserId;
- private final MediaSessionStack mPriorityStack;
- private PendingIntent mLastMediaButtonReceiver;
- private ComponentName mRestoredMediaButtonReceiver;
- private int mRestoredMediaButtonReceiverComponentType;
- private int mRestoredMediaButtonReceiverUserId;
-
- private IOnVolumeKeyLongPressListener mOnVolumeKeyLongPressListener;
- private int mOnVolumeKeyLongPressListenerUid;
- private KeyEvent mInitialDownVolumeKeyEvent;
- private int mInitialDownVolumeStream;
- private boolean mInitialDownMusicOnly;
-
- private IOnMediaKeyListener mOnMediaKeyListener;
- private int mOnMediaKeyListenerUid;
- private ICallback mCallback;
-
- public FullUserRecord(int fullUserId) {
- mFullUserId = fullUserId;
- mPriorityStack = new MediaSessionStack(mAudioPlayerStateMonitor, this);
- // Restore the remembered media button receiver before the boot.
- String mediaButtonReceiverInfo = Settings.Secure.getStringForUser(mContentResolver,
- Settings.System.MEDIA_BUTTON_RECEIVER, mFullUserId);
- if (mediaButtonReceiverInfo == null) {
- return;
- }
- String[] tokens = mediaButtonReceiverInfo.split(COMPONENT_NAME_USER_ID_DELIM);
- if (tokens == null || (tokens.length != 2 && tokens.length != 3)) {
- return;
- }
- mRestoredMediaButtonReceiver = ComponentName.unflattenFromString(tokens[0]);
- mRestoredMediaButtonReceiverUserId = Integer.parseInt(tokens[1]);
- if (tokens.length == 3) {
- mRestoredMediaButtonReceiverComponentType = Integer.parseInt(tokens[2]);
- } else {
- mRestoredMediaButtonReceiverComponentType =
- getComponentType(mRestoredMediaButtonReceiver);
- }
- }
-
- public void destroySessionsForUserLocked(int userId) {
- List<MediaSessionRecord> sessions = mPriorityStack.getPriorityList(false, userId);
- for (MediaSessionRecord session : sessions) {
- MediaSessionService.this.destroySessionLocked(session);
- }
- }
-
- public void dumpLocked(PrintWriter pw, String prefix) {
- pw.print(prefix + "Record for full_user=" + mFullUserId);
- // Dump managed profile user ids associated with this user.
- int size = mFullUserIds.size();
- for (int i = 0; i < size; i++) {
- if (mFullUserIds.keyAt(i) != mFullUserIds.valueAt(i)
- && mFullUserIds.valueAt(i) == mFullUserId) {
- pw.print(", profile_user=" + mFullUserIds.keyAt(i));
- }
- }
- pw.println();
- String indent = prefix + " ";
- pw.println(indent + "Volume key long-press listener: " + mOnVolumeKeyLongPressListener);
- pw.println(indent + "Volume key long-press listener package: " +
- getCallingPackageName(mOnVolumeKeyLongPressListenerUid));
- pw.println(indent + "Media key listener: " + mOnMediaKeyListener);
- pw.println(indent + "Media key listener package: " +
- getCallingPackageName(mOnMediaKeyListenerUid));
- pw.println(indent + "Callback: " + mCallback);
- pw.println(indent + "Last MediaButtonReceiver: " + mLastMediaButtonReceiver);
- pw.println(indent + "Restored MediaButtonReceiver: " + mRestoredMediaButtonReceiver);
- pw.println(indent + "Restored MediaButtonReceiverComponentType: "
- + mRestoredMediaButtonReceiverComponentType);
- mPriorityStack.dump(pw, indent);
- pw.println(indent + "Session2Tokens:");
- for (int i = 0; i < mSession2TokensPerUser.size(); i++) {
- List<Session2Token> list = mSession2TokensPerUser.valueAt(i);
- if (list == null || list.size() == 0) {
- continue;
- }
- for (Session2Token token : list) {
- pw.println(indent + " " + token);
- }
- }
- }
-
- @Override
- public void onMediaButtonSessionChanged(MediaSessionRecord oldMediaButtonSession,
- MediaSessionRecord newMediaButtonSession) {
- if (DEBUG_KEY_EVENT) {
- Log.d(TAG, "Media button session is changed to " + newMediaButtonSession);
- }
- synchronized (mLock) {
- if (oldMediaButtonSession != null) {
- mHandler.postSessionsChanged(oldMediaButtonSession.getUserId());
- }
- if (newMediaButtonSession != null) {
- rememberMediaButtonReceiverLocked(newMediaButtonSession);
- mHandler.postSessionsChanged(newMediaButtonSession.getUserId());
- }
- pushAddressedPlayerChangedLocked();
- }
- }
-
- // Remember media button receiver and keep it in the persistent storage.
- public void rememberMediaButtonReceiverLocked(MediaSessionRecord record) {
- PendingIntent receiver = record.getMediaButtonReceiver();
- mLastMediaButtonReceiver = receiver;
- mRestoredMediaButtonReceiver = null;
- mRestoredMediaButtonReceiverComponentType = COMPONENT_TYPE_INVALID;
-
- String mediaButtonReceiverInfo = "";
- if (receiver != null) {
- ComponentName component = receiver.getIntent().getComponent();
- if (component != null
- && record.getPackageName().equals(component.getPackageName())) {
- String componentName = component.flattenToString();
- int componentType = getComponentType(component);
- mediaButtonReceiverInfo = String.join(COMPONENT_NAME_USER_ID_DELIM,
- componentName, String.valueOf(record.getUserId()),
- String.valueOf(componentType));
- }
- }
- Settings.Secure.putStringForUser(mContentResolver,
- Settings.System.MEDIA_BUTTON_RECEIVER, mediaButtonReceiverInfo,
- mFullUserId);
- }
-
- private void pushAddressedPlayerChangedLocked() {
- if (mCallback == null) {
- return;
- }
- try {
- MediaSessionRecord mediaButtonSession = getMediaButtonSessionLocked();
- if (mediaButtonSession != null) {
- mCallback.onAddressedPlayerChangedToMediaSession(
- new MediaSession.Token(mediaButtonSession.getControllerBinder()));
- } else if (mCurrentFullUserRecord.mLastMediaButtonReceiver != null) {
- mCallback.onAddressedPlayerChangedToMediaButtonReceiver(
- mCurrentFullUserRecord.mLastMediaButtonReceiver
- .getIntent().getComponent());
- } else if (mCurrentFullUserRecord.mRestoredMediaButtonReceiver != null) {
- mCallback.onAddressedPlayerChangedToMediaButtonReceiver(
- mCurrentFullUserRecord.mRestoredMediaButtonReceiver);
- }
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to pushAddressedPlayerChangedLocked", e);
- }
- }
-
- private MediaSessionRecord getMediaButtonSessionLocked() {
- return isGlobalPriorityActiveLocked()
- ? mGlobalPrioritySession : mPriorityStack.getMediaButtonSession();
- }
-
- private int getComponentType(@Nullable ComponentName componentName) {
- if (componentName == null) {
- return COMPONENT_TYPE_INVALID;
- }
- PackageManager pm = getContext().getPackageManager();
- try {
- ActivityInfo activityInfo = pm.getActivityInfo(componentName,
- PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
- | PackageManager.GET_ACTIVITIES);
- if (activityInfo != null) {
- return COMPONENT_TYPE_ACTIVITY;
- }
- } catch (NameNotFoundException e) {
- }
- try {
- ServiceInfo serviceInfo = pm.getServiceInfo(componentName,
- PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
- | PackageManager.GET_SERVICES);
- if (serviceInfo != null) {
- return COMPONENT_TYPE_SERVICE;
- }
- } catch (NameNotFoundException e) {
- }
- // Pick legacy behavior for BroadcastReceiver or unknown.
- return COMPONENT_TYPE_BROADCAST;
- }
- }
-
- final class SessionsListenerRecord implements IBinder.DeathRecipient {
- public final IActiveSessionsListener listener;
- public final ComponentName componentName;
- public final int userId;
- public final int pid;
- public final int uid;
-
- public SessionsListenerRecord(IActiveSessionsListener listener,
- ComponentName componentName,
- int userId, int pid, int uid) {
- this.listener = listener;
- this.componentName = componentName;
- this.userId = userId;
- this.pid = pid;
- this.uid = uid;
- }
-
- @Override
- public void binderDied() {
- synchronized (mLock) {
- mSessionsListeners.remove(this);
- }
- }
- }
-
- final class Session2TokensListenerRecord implements IBinder.DeathRecipient {
- public final ISession2TokensListener listener;
- public final int userId;
-
- Session2TokensListenerRecord(ISession2TokensListener listener,
- int userId) {
- this.listener = listener;
- this.userId = userId;
- }
-
- @Override
- public void binderDied() {
- synchronized (mLock) {
- mSession2TokensListenerRecords.remove(this);
- }
- }
- }
-
- final class SettingsObserver extends ContentObserver {
- private final Uri mSecureSettingsUri = Settings.Secure.getUriFor(
- Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
-
- private SettingsObserver() {
- super(null);
- }
-
- private void observe() {
- mContentResolver.registerContentObserver(mSecureSettingsUri,
- false, this, USER_ALL);
- }
-
- @Override
- public void onChange(boolean selfChange, Uri uri) {
- updateActiveSessionListeners();
- }
- }
-
- class SessionManagerImpl extends ISessionManager.Stub {
- private static final String EXTRA_WAKELOCK_ACQUIRED =
- "android.media.AudioService.WAKELOCK_ACQUIRED";
- private static final int WAKELOCK_RELEASE_ON_FINISHED = 1980; // magic number
-
- private boolean mVoiceButtonDown = false;
- private boolean mVoiceButtonHandled = false;
-
- @Override
- public ISession createSession(String packageName, SessionCallbackLink cb, String tag,
- int userId) throws RemoteException {
- final int pid = Binder.getCallingPid();
- final int uid = Binder.getCallingUid();
- final long token = Binder.clearCallingIdentity();
- try {
- enforcePackageName(packageName, uid);
- int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
- false /* allowAll */, true /* requireFull */, "createSession", packageName);
- if (cb == null) {
- throw new IllegalArgumentException("Controller callback cannot be null");
- }
- return createSessionInternal(pid, uid, resolvedUserId, packageName, cb, tag)
- .getSessionBinder();
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- @Override
- public void notifySession2Created(Session2Token sessionToken) throws RemoteException {
- final int pid = Binder.getCallingPid();
- final int uid = Binder.getCallingUid();
- final long token = Binder.clearCallingIdentity();
- try {
- if (DEBUG) {
- Log.d(TAG, "Session2 is created " + sessionToken);
- }
- if (uid != sessionToken.getUid()) {
- throw new SecurityException("Unexpected Session2Token's UID, expected=" + uid
- + " but actually=" + sessionToken.getUid());
- }
- Controller2Callback callback = new Controller2Callback(sessionToken);
- // Note: It's safe not to keep controller here because it wouldn't be GC'ed until
- // it's closed.
- // TODO: Keep controller as well for better readability
- // because the GC behavior isn't straightforward.
- MediaController2 controller = new MediaController2(getContext(), sessionToken,
- new HandlerExecutor(mHandler), callback);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- @Override
- public List<IBinder> getSessions(ComponentName componentName, int userId) {
- final int pid = Binder.getCallingPid();
- final int uid = Binder.getCallingUid();
- final long token = Binder.clearCallingIdentity();
-
- try {
- int resolvedUserId = verifySessionsRequest(componentName, userId, pid, uid);
- ArrayList<IBinder> binders = new ArrayList<IBinder>();
- synchronized (mLock) {
- List<MediaSessionRecord> records = getActiveSessionsLocked(resolvedUserId);
- for (MediaSessionRecord record : records) {
- binders.add(record.getControllerBinder().asBinder());
- }
- }
- return binders;
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- @Override
- public List<Session2Token> getSession2Tokens(int userId) {
- final int pid = Binder.getCallingPid();
- final int uid = Binder.getCallingUid();
- final long token = Binder.clearCallingIdentity();
-
- try {
- // Check that they can make calls on behalf of the user and
- // get the final user id
- int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
- true /* allowAll */, true /* requireFull */, "getSession2Tokens",
- null /* optional packageName */);
- List<Session2Token> result;
- synchronized (mLock) {
- result = getSession2TokensLocked(resolvedUserId);
- }
- return result;
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- @Override
- public void addSessionsListener(IActiveSessionsListener listener,
- ComponentName componentName, int userId) throws RemoteException {
- final int pid = Binder.getCallingPid();
- final int uid = Binder.getCallingUid();
- final long token = Binder.clearCallingIdentity();
-
- try {
- int resolvedUserId = verifySessionsRequest(componentName, userId, pid, uid);
- synchronized (mLock) {
- int index = findIndexOfSessionsListenerLocked(listener);
- if (index != -1) {
- Log.w(TAG, "ActiveSessionsListener is already added, ignoring");
- return;
- }
- SessionsListenerRecord record = new SessionsListenerRecord(listener,
- componentName, resolvedUserId, pid, uid);
- try {
- listener.asBinder().linkToDeath(record, 0);
- } catch (RemoteException e) {
- Log.e(TAG, "ActiveSessionsListener is dead, ignoring it", e);
- return;
- }
- mSessionsListeners.add(record);
- }
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- @Override
- public void removeSessionsListener(IActiveSessionsListener listener)
- throws RemoteException {
- synchronized (mLock) {
- int index = findIndexOfSessionsListenerLocked(listener);
- if (index != -1) {
- SessionsListenerRecord record = mSessionsListeners.remove(index);
- try {
- record.listener.asBinder().unlinkToDeath(record, 0);
- } catch (Exception e) {
- // ignore exceptions, the record is being removed
- }
- }
- }
- }
-
- @Override
- public void addSession2TokensListener(ISession2TokensListener listener,
- int userId) {
- final int pid = Binder.getCallingPid();
- final int uid = Binder.getCallingUid();
- final long token = Binder.clearCallingIdentity();
-
- try {
- // Check that they can make calls on behalf of the user and get the final user id.
- int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
- true /* allowAll */, true /* requireFull */, "addSession2TokensListener",
- null /* optional packageName */);
- synchronized (mLock) {
- int index = findIndexOfSession2TokensListenerLocked(listener);
- if (index >= 0) {
- Log.w(TAG, "addSession2TokensListener is already added, ignoring");
- return;
- }
- mSession2TokensListenerRecords.add(
- new Session2TokensListenerRecord(listener, resolvedUserId));
- }
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- @Override
- public void removeSession2TokensListener(ISession2TokensListener listener) {
- final int pid = Binder.getCallingPid();
- final int uid = Binder.getCallingUid();
- final long token = Binder.clearCallingIdentity();
-
- try {
- synchronized (mLock) {
- int index = findIndexOfSession2TokensListenerLocked(listener);
- if (index >= 0) {
- Session2TokensListenerRecord listenerRecord =
- mSession2TokensListenerRecords.remove(index);
- try {
- listenerRecord.listener.asBinder().unlinkToDeath(listenerRecord, 0);
- } catch (Exception e) {
- // Ignore exception.
- }
- }
- }
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- /**
- * Handles the dispatching of the media button events to one of the
- * registered listeners, or if there was none, broadcast an
- * ACTION_MEDIA_BUTTON intent to the rest of the system.
- *
- * @param packageName The caller package
- * @param asSystemService {@code true} if the event sent to the session as if it was come
- * from the system service instead of the app process. This helps sessions to
- * distinguish between the key injection by the app and key events from the
- * hardware devices. Should be used only when the volume key events aren't handled
- * by foreground activity. {@code false} otherwise to tell session about the real
- * caller.
- * @param keyEvent a non-null KeyEvent whose key code is one of the
- * supported media buttons
- * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held
- * while this key event is dispatched.
- */
- @Override
- public void dispatchMediaKeyEvent(String packageName, boolean asSystemService,
- KeyEvent keyEvent, boolean needWakeLock) {
- if (keyEvent == null || !KeyEvent.isMediaSessionKey(keyEvent.getKeyCode())) {
- Log.w(TAG, "Attempted to dispatch null or non-media key event.");
- return;
- }
-
- final int pid = Binder.getCallingPid();
- final int uid = Binder.getCallingUid();
- final long token = Binder.clearCallingIdentity();
- try {
- if (DEBUG) {
- Log.d(TAG, "dispatchMediaKeyEvent, pkg=" + packageName + " pid=" + pid
- + ", uid=" + uid + ", asSystem=" + asSystemService + ", event="
- + keyEvent);
- }
- if (!isUserSetupComplete()) {
- // Global media key handling can have the side-effect of starting new
- // activities which is undesirable while setup is in progress.
- Slog.i(TAG, "Not dispatching media key event because user "
- + "setup is in progress.");
- return;
- }
-
- synchronized (mLock) {
- boolean isGlobalPriorityActive = isGlobalPriorityActiveLocked();
- if (isGlobalPriorityActive && uid != Process.SYSTEM_UID) {
- // Prevent dispatching key event through reflection while the global
- // priority session is active.
- Slog.i(TAG, "Only the system can dispatch media key event "
- + "to the global priority session.");
- return;
- }
- if (!isGlobalPriorityActive) {
- if (mCurrentFullUserRecord.mOnMediaKeyListener != null) {
- if (DEBUG_KEY_EVENT) {
- Log.d(TAG, "Send " + keyEvent + " to the media key listener");
- }
- try {
- mCurrentFullUserRecord.mOnMediaKeyListener.onMediaKey(keyEvent,
- new MediaKeyListenerResultReceiver(packageName, pid, uid,
- asSystemService, keyEvent, needWakeLock));
- return;
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to send " + keyEvent
- + " to the media key listener");
- }
- }
- }
- if (!isGlobalPriorityActive && isVoiceKey(keyEvent.getKeyCode())) {
- handleVoiceKeyEventLocked(packageName, pid, uid, asSystemService, keyEvent,
- needWakeLock);
- } else {
- dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService,
- keyEvent, needWakeLock);
- }
- }
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- @Override
- public void setCallback(ICallback callback) {
- final int pid = Binder.getCallingPid();
- final int uid = Binder.getCallingUid();
- final long token = Binder.clearCallingIdentity();
- try {
- if (!UserHandle.isSameApp(uid, Process.BLUETOOTH_UID)) {
- throw new SecurityException("Only Bluetooth service processes can set"
- + " Callback");
- }
- synchronized (mLock) {
- int userId = UserHandle.getUserId(uid);
- FullUserRecord user = getFullUserRecordLocked(userId);
- if (user == null || user.mFullUserId != userId) {
- Log.w(TAG, "Only the full user can set the callback"
- + ", userId=" + userId);
- return;
- }
- user.mCallback = callback;
- Log.d(TAG, "The callback " + user.mCallback
- + " is set by " + getCallingPackageName(uid));
- if (user.mCallback == null) {
- return;
- }
- try {
- user.mCallback.asBinder().linkToDeath(
- new IBinder.DeathRecipient() {
- @Override
- public void binderDied() {
- synchronized (mLock) {
- user.mCallback = null;
- }
- }
- }, 0);
- user.pushAddressedPlayerChangedLocked();
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to set callback", e);
- user.mCallback = null;
- }
- }
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- @Override
- public void setOnVolumeKeyLongPressListener(IOnVolumeKeyLongPressListener listener) {
- final int pid = Binder.getCallingPid();
- final int uid = Binder.getCallingUid();
- final long token = Binder.clearCallingIdentity();
- try {
- // Enforce SET_VOLUME_KEY_LONG_PRESS_LISTENER permission.
- if (getContext().checkPermission(
- android.Manifest.permission.SET_VOLUME_KEY_LONG_PRESS_LISTENER, pid, uid)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Must hold the SET_VOLUME_KEY_LONG_PRESS_LISTENER" +
- " permission.");
- }
-
- synchronized (mLock) {
- int userId = UserHandle.getUserId(uid);
- FullUserRecord user = getFullUserRecordLocked(userId);
- if (user == null || user.mFullUserId != userId) {
- Log.w(TAG, "Only the full user can set the volume key long-press listener"
- + ", userId=" + userId);
- return;
- }
- if (user.mOnVolumeKeyLongPressListener != null &&
- user.mOnVolumeKeyLongPressListenerUid != uid) {
- Log.w(TAG, "The volume key long-press listener cannot be reset"
- + " by another app , mOnVolumeKeyLongPressListener="
- + user.mOnVolumeKeyLongPressListenerUid
- + ", uid=" + uid);
- return;
- }
-
- user.mOnVolumeKeyLongPressListener = listener;
- user.mOnVolumeKeyLongPressListenerUid = uid;
-
- Log.d(TAG, "The volume key long-press listener "
- + listener + " is set by " + getCallingPackageName(uid));
-
- if (user.mOnVolumeKeyLongPressListener != null) {
- try {
- user.mOnVolumeKeyLongPressListener.asBinder().linkToDeath(
- new IBinder.DeathRecipient() {
- @Override
- public void binderDied() {
- synchronized (mLock) {
- user.mOnVolumeKeyLongPressListener = null;
- }
- }
- }, 0);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to set death recipient "
- + user.mOnVolumeKeyLongPressListener);
- user.mOnVolumeKeyLongPressListener = null;
- }
- }
- }
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- @Override
- public void setOnMediaKeyListener(IOnMediaKeyListener listener) {
- final int pid = Binder.getCallingPid();
- final int uid = Binder.getCallingUid();
- final long token = Binder.clearCallingIdentity();
- try {
- // Enforce SET_MEDIA_KEY_LISTENER permission.
- if (getContext().checkPermission(
- android.Manifest.permission.SET_MEDIA_KEY_LISTENER, pid, uid)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Must hold the SET_MEDIA_KEY_LISTENER" +
- " permission.");
- }
-
- synchronized (mLock) {
- int userId = UserHandle.getUserId(uid);
- FullUserRecord user = getFullUserRecordLocked(userId);
- if (user == null || user.mFullUserId != userId) {
- Log.w(TAG, "Only the full user can set the media key listener"
- + ", userId=" + userId);
- return;
- }
- if (user.mOnMediaKeyListener != null && user.mOnMediaKeyListenerUid != uid) {
- Log.w(TAG, "The media key listener cannot be reset by another app. "
- + ", mOnMediaKeyListenerUid=" + user.mOnMediaKeyListenerUid
- + ", uid=" + uid);
- return;
- }
-
- user.mOnMediaKeyListener = listener;
- user.mOnMediaKeyListenerUid = uid;
-
- Log.d(TAG, "The media key listener " + user.mOnMediaKeyListener
- + " is set by " + getCallingPackageName(uid));
-
- if (user.mOnMediaKeyListener != null) {
- try {
- user.mOnMediaKeyListener.asBinder().linkToDeath(
- new IBinder.DeathRecipient() {
- @Override
- public void binderDied() {
- synchronized (mLock) {
- user.mOnMediaKeyListener = null;
- }
- }
- }, 0);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to set death recipient " + user.mOnMediaKeyListener);
- user.mOnMediaKeyListener = null;
- }
- }
- }
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- /**
- * Handles the dispatching of the volume button events to one of the
- * registered listeners. If there's a volume key long-press listener and
- * there's no active global priority session, long-pressess will be sent to the
- * long-press listener instead of adjusting volume.
- *
- * @param packageName The caller's package name, obtained by Context#getPackageName()
- * @param opPackageName The caller's op package name, obtained by Context#getOpPackageName()
- * @param asSystemService {@code true} if the event sent to the session as if it was come
- * from the system service instead of the app process. This helps sessions to
- * distinguish between the key injection by the app and key events from the
- * hardware devices. Should be used only when the volume key events aren't handled
- * by foreground activity. {@code false} otherwise to tell session about the real
- * caller.
- * @param keyEvent a non-null KeyEvent whose key code is one of the
- * {@link KeyEvent#KEYCODE_VOLUME_UP},
- * {@link KeyEvent#KEYCODE_VOLUME_DOWN},
- * or {@link KeyEvent#KEYCODE_VOLUME_MUTE}.
- * @param stream stream type to adjust volume.
- * @param musicOnly true if both UI nor haptic feedback aren't needed when adjust volume.
- */
- @Override
- public void dispatchVolumeKeyEvent(String packageName, String opPackageName,
- boolean asSystemService, KeyEvent keyEvent, int stream, boolean musicOnly) {
- if (keyEvent == null ||
- (keyEvent.getKeyCode() != KeyEvent.KEYCODE_VOLUME_UP
- && keyEvent.getKeyCode() != KeyEvent.KEYCODE_VOLUME_DOWN
- && keyEvent.getKeyCode() != KeyEvent.KEYCODE_VOLUME_MUTE)) {
- Log.w(TAG, "Attempted to dispatch null or non-volume key event.");
- return;
- }
-
- final int pid = Binder.getCallingPid();
- final int uid = Binder.getCallingUid();
- final long token = Binder.clearCallingIdentity();
-
- if (DEBUG_KEY_EVENT) {
- Log.d(TAG, "dispatchVolumeKeyEvent, pkg=" + packageName + ", pid=" + pid + ", uid="
- + uid + ", asSystem=" + asSystemService + ", event=" + keyEvent);
- }
-
- try {
- synchronized (mLock) {
- if (isGlobalPriorityActiveLocked()
- || mCurrentFullUserRecord.mOnVolumeKeyLongPressListener == null) {
- dispatchVolumeKeyEventLocked(packageName, opPackageName, pid, uid,
- asSystemService, keyEvent, stream, musicOnly);
- } else {
- // TODO: Consider the case when both volume up and down keys are pressed
- // at the same time.
- if (keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
- if (keyEvent.getRepeatCount() == 0) {
- // Keeps the copy of the KeyEvent because it can be reused.
- mCurrentFullUserRecord.mInitialDownVolumeKeyEvent =
- KeyEvent.obtain(keyEvent);
- mCurrentFullUserRecord.mInitialDownVolumeStream = stream;
- mCurrentFullUserRecord.mInitialDownMusicOnly = musicOnly;
- mHandler.sendMessageDelayed(
- mHandler.obtainMessage(
- MessageHandler.MSG_VOLUME_INITIAL_DOWN,
- mCurrentFullUserRecord.mFullUserId, 0),
- mLongPressTimeout);
- }
- if (keyEvent.getRepeatCount() > 0 || keyEvent.isLongPress()) {
- mHandler.removeMessages(MessageHandler.MSG_VOLUME_INITIAL_DOWN);
- if (mCurrentFullUserRecord.mInitialDownVolumeKeyEvent != null) {
- dispatchVolumeKeyLongPressLocked(
- mCurrentFullUserRecord.mInitialDownVolumeKeyEvent);
- // Mark that the key is already handled.
- mCurrentFullUserRecord.mInitialDownVolumeKeyEvent = null;
- }
- dispatchVolumeKeyLongPressLocked(keyEvent);
- }
- } else { // if up
- mHandler.removeMessages(MessageHandler.MSG_VOLUME_INITIAL_DOWN);
- if (mCurrentFullUserRecord.mInitialDownVolumeKeyEvent != null
- && mCurrentFullUserRecord.mInitialDownVolumeKeyEvent
- .getDownTime() == keyEvent.getDownTime()) {
- // Short-press. Should change volume.
- dispatchVolumeKeyEventLocked(packageName, opPackageName, pid, uid,
- asSystemService,
- mCurrentFullUserRecord.mInitialDownVolumeKeyEvent,
- mCurrentFullUserRecord.mInitialDownVolumeStream,
- mCurrentFullUserRecord.mInitialDownMusicOnly);
- dispatchVolumeKeyEventLocked(packageName, opPackageName, pid, uid,
- asSystemService, keyEvent, stream, musicOnly);
- } else {
- dispatchVolumeKeyLongPressLocked(keyEvent);
- }
- }
- }
- }
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- private void dispatchVolumeKeyEventLocked(String packageName, String opPackageName, int pid,
- int uid, boolean asSystemService, KeyEvent keyEvent, int stream,
- boolean musicOnly) {
- boolean down = keyEvent.getAction() == KeyEvent.ACTION_DOWN;
- boolean up = keyEvent.getAction() == KeyEvent.ACTION_UP;
- int direction = 0;
- boolean isMute = false;
- switch (keyEvent.getKeyCode()) {
- case KeyEvent.KEYCODE_VOLUME_UP:
- direction = AudioManager.ADJUST_RAISE;
- break;
- case KeyEvent.KEYCODE_VOLUME_DOWN:
- direction = AudioManager.ADJUST_LOWER;
- break;
- case KeyEvent.KEYCODE_VOLUME_MUTE:
- isMute = true;
- break;
- }
- if (down || up) {
- int flags = AudioManager.FLAG_FROM_KEY;
- if (musicOnly) {
- // This flag is used when the screen is off to only affect active media.
- flags |= AudioManager.FLAG_ACTIVE_MEDIA_ONLY;
- } else {
- // These flags are consistent with the home screen
- if (up) {
- flags |= AudioManager.FLAG_PLAY_SOUND | AudioManager.FLAG_VIBRATE;
- } else {
- flags |= AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_VIBRATE;
- }
- }
- if (direction != 0) {
- // If this is action up we want to send a beep for non-music events
- if (up) {
- direction = 0;
- }
- dispatchAdjustVolumeLocked(packageName, opPackageName, pid, uid,
- asSystemService, stream, direction, flags);
- } else if (isMute) {
- if (down && keyEvent.getRepeatCount() == 0) {
- dispatchAdjustVolumeLocked(packageName, opPackageName, pid, uid,
- asSystemService, stream, AudioManager.ADJUST_TOGGLE_MUTE, flags);
- }
- }
- }
- }
-
- @Override
- public void dispatchAdjustVolume(String packageName, String opPackageName,
- int suggestedStream, int delta, int flags) {
- final int pid = Binder.getCallingPid();
- final int uid = Binder.getCallingUid();
- final long token = Binder.clearCallingIdentity();
- try {
- synchronized (mLock) {
- dispatchAdjustVolumeLocked(packageName, opPackageName, pid, uid, false,
- suggestedStream, delta, flags);
- }
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- @Override
- public void setRemoteVolumeController(IRemoteVolumeController rvc) {
- final int pid = Binder.getCallingPid();
- final int uid = Binder.getCallingUid();
- final long token = Binder.clearCallingIdentity();
- try {
- enforceSystemUiPermission("listen for volume changes", pid, uid);
- mRvc = rvc;
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- @Override
- public boolean isGlobalPriorityActive() {
- synchronized (mLock) {
- return isGlobalPriorityActiveLocked();
- }
- }
-
- @Override
- public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
- if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return;
-
- pw.println("MEDIA SESSION SERVICE (dumpsys media_session)");
- pw.println();
-
- synchronized (mLock) {
- pw.println(mSessionsListeners.size() + " sessions listeners.");
- pw.println("Global priority session is " + mGlobalPrioritySession);
- if (mGlobalPrioritySession != null) {
- mGlobalPrioritySession.dump(pw, " ");
- }
- pw.println("User Records:");
- int count = mUserRecords.size();
- for (int i = 0; i < count; i++) {
- mUserRecords.valueAt(i).dumpLocked(pw, "");
- }
- mAudioPlayerStateMonitor.dump(getContext(), pw, "");
- }
- }
-
- /**
- * Returns if the controller's package is trusted (i.e. has either MEDIA_CONTENT_CONTROL
- * permission or an enabled notification listener)
- *
- * @param controllerPackageName package name of the controller app
- * @param controllerPid pid of the controller app
- * @param controllerUid uid of the controller app
- */
- @Override
- public boolean isTrusted(String controllerPackageName, int controllerPid, int controllerUid)
- throws RemoteException {
- final int uid = Binder.getCallingUid();
- final long token = Binder.clearCallingIdentity();
- try {
- // Don't perform sanity check between controllerPackageName and controllerUid.
- // When an (activity|service) runs on the another apps process by specifying
- // android:process in the AndroidManifest.xml, then PID and UID would have the
- // running process' information instead of the (activity|service) that has created
- // MediaController.
- // Note that we can use Context#getOpPackageName() instead of
- // Context#getPackageName() for getting package name that matches with the PID/UID,
- // but it doesn't tell which package has created the MediaController, so useless.
- return hasMediaControlPermission(UserHandle.getUserId(uid), controllerPackageName,
- controllerPid, controllerUid);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- // For MediaSession
- private int verifySessionsRequest(ComponentName componentName, int userId, final int pid,
- final int uid) {
- String packageName = null;
- if (componentName != null) {
- // If they gave us a component name verify they own the
- // package
- packageName = componentName.getPackageName();
- enforcePackageName(packageName, uid);
- }
- // Check that they can make calls on behalf of the user and
- // get the final user id
- int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
- true /* allowAll */, true /* requireFull */, "getSessions", packageName);
- // Check if they have the permissions or their component is
- // enabled for the user they're calling from.
- enforceMediaPermissions(componentName, pid, uid, resolvedUserId);
- return resolvedUserId;
- }
-
- private boolean hasMediaControlPermission(int resolvedUserId, String packageName,
- int pid, int uid) throws RemoteException {
- // Allow API calls from the System UI
- if (isCurrentVolumeController(pid, uid)) {
- return true;
- }
-
- // Check if it's system server or has MEDIA_CONTENT_CONTROL.
- // Note that system server doesn't have MEDIA_CONTENT_CONTROL, so we need extra
- // check here.
- if (uid == Process.SYSTEM_UID || getContext().checkPermission(
- android.Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid)
- == PackageManager.PERMISSION_GRANTED) {
- return true;
- } else if (DEBUG) {
- Log.d(TAG, packageName + " (uid=" + uid + ") hasn't granted MEDIA_CONTENT_CONTROL");
- }
-
- // You may not access another user's content as an enabled listener.
- final int userId = UserHandle.getUserId(uid);
- if (resolvedUserId != userId) {
- return false;
- }
-
- // TODO(jaewan): (Post-P) Propose NotificationManager#hasEnabledNotificationListener(
- // String pkgName) to notification team for optimization
- final List<ComponentName> enabledNotificationListeners =
- mNotificationManager.getEnabledNotificationListeners(userId);
- if (enabledNotificationListeners != null) {
- for (int i = 0; i < enabledNotificationListeners.size(); i++) {
- if (TextUtils.equals(packageName,
- enabledNotificationListeners.get(i).getPackageName())) {
- return true;
- }
- }
- }
- if (DEBUG) {
- Log.d(TAG, packageName + " (uid=" + uid + ") doesn't have an enabled "
- + "notification listener");
- }
- return false;
- }
-
- private void dispatchAdjustVolumeLocked(String packageName, String opPackageName, int pid,
- int uid, boolean asSystemService, int suggestedStream, int direction, int flags) {
- MediaSessionRecord session = isGlobalPriorityActiveLocked() ? mGlobalPrioritySession
- : mCurrentFullUserRecord.mPriorityStack.getDefaultVolumeSession();
-
- boolean preferSuggestedStream = false;
- if (isValidLocalStreamType(suggestedStream)
- && AudioSystem.isStreamActive(suggestedStream, 0)) {
- preferSuggestedStream = true;
- }
- if (DEBUG_KEY_EVENT) {
- Log.d(TAG, "Adjusting " + session + " by " + direction + ". flags="
- + flags + ", suggestedStream=" + suggestedStream
- + ", preferSuggestedStream=" + preferSuggestedStream);
- }
- if (session == null || preferSuggestedStream) {
- if ((flags & AudioManager.FLAG_ACTIVE_MEDIA_ONLY) != 0
- && !AudioSystem.isStreamActive(AudioManager.STREAM_MUSIC, 0)) {
- if (DEBUG) {
- Log.d(TAG, "No active session to adjust, skipping media only volume event");
- }
- return;
- }
-
- // Execute mAudioService.adjustSuggestedStreamVolume() on
- // handler thread of MediaSessionService.
- // This will release the MediaSessionService.mLock sooner and avoid
- // a potential deadlock between MediaSessionService.mLock and
- // ActivityManagerService lock.
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- final String callingOpPackageName;
- final int callingUid;
- if (asSystemService) {
- callingOpPackageName = getContext().getOpPackageName();
- callingUid = Process.myUid();
- } else {
- callingOpPackageName = opPackageName;
- callingUid = uid;
- }
- try {
- mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(suggestedStream,
- direction, flags, callingOpPackageName, callingUid);
- } catch (SecurityException | IllegalArgumentException e) {
- Log.e(TAG, "Cannot adjust volume: direction=" + direction
- + ", suggestedStream=" + suggestedStream + ", flags=" + flags
- + ", packageName=" + packageName + ", uid=" + uid
- + ", asSystemService=" + asSystemService, e);
- }
- }
- });
- } else {
- session.adjustVolume(packageName, opPackageName, pid, uid, null, asSystemService,
- direction, flags, true);
- }
- }
-
- private void handleVoiceKeyEventLocked(String packageName, int pid, int uid,
- boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock) {
- int action = keyEvent.getAction();
- boolean isLongPress = (keyEvent.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0;
- if (action == KeyEvent.ACTION_DOWN) {
- if (keyEvent.getRepeatCount() == 0) {
- mVoiceButtonDown = true;
- mVoiceButtonHandled = false;
- } else if (mVoiceButtonDown && !mVoiceButtonHandled && isLongPress) {
- mVoiceButtonHandled = true;
- startVoiceInput(needWakeLock);
- }
- } else if (action == KeyEvent.ACTION_UP) {
- if (mVoiceButtonDown) {
- mVoiceButtonDown = false;
- if (!mVoiceButtonHandled && !keyEvent.isCanceled()) {
- // Resend the down then send this event through
- KeyEvent downEvent = KeyEvent.changeAction(keyEvent, KeyEvent.ACTION_DOWN);
- dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService,
- downEvent, needWakeLock);
- dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService,
- keyEvent, needWakeLock);
- }
- }
- }
- }
-
- private void dispatchMediaKeyEventLocked(String packageName, int pid, int uid,
- boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock) {
- MediaSessionRecord session = mCurrentFullUserRecord.getMediaButtonSessionLocked();
- if (session != null) {
- if (DEBUG_KEY_EVENT) {
- Log.d(TAG, "Sending " + keyEvent + " to " + session);
- }
- if (needWakeLock) {
- mKeyEventReceiver.aquireWakeLockLocked();
- }
- // If we don't need a wakelock use -1 as the id so we won't release it later.
- session.sendMediaButton(packageName, pid, uid, asSystemService, keyEvent,
- needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
- mKeyEventReceiver);
- if (mCurrentFullUserRecord.mCallback != null) {
- try {
- mCurrentFullUserRecord.mCallback.onMediaKeyEventDispatchedToMediaSession(
- keyEvent, new MediaSession.Token(session.getControllerBinder()));
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to send callback", e);
- }
- }
- } else if (mCurrentFullUserRecord.mLastMediaButtonReceiver != null
- || mCurrentFullUserRecord.mRestoredMediaButtonReceiver != null) {
- if (needWakeLock) {
- mKeyEventReceiver.aquireWakeLockLocked();
- }
- Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
- mediaButtonIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
- mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
- // TODO: Find a way to also send PID/UID in secure way.
- String callerPackageName =
- (asSystemService) ? getContext().getPackageName() : packageName;
- mediaButtonIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, callerPackageName);
- try {
- if (mCurrentFullUserRecord.mLastMediaButtonReceiver != null) {
- PendingIntent receiver = mCurrentFullUserRecord.mLastMediaButtonReceiver;
- if (DEBUG_KEY_EVENT) {
- Log.d(TAG, "Sending " + keyEvent
- + " to the last known PendingIntent " + receiver);
- }
- receiver.send(getContext(),
- needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
- mediaButtonIntent, mKeyEventReceiver, mHandler);
- if (mCurrentFullUserRecord.mCallback != null) {
- ComponentName componentName = mCurrentFullUserRecord
- .mLastMediaButtonReceiver.getIntent().getComponent();
- if (componentName != null) {
- mCurrentFullUserRecord.mCallback
- .onMediaKeyEventDispatchedToMediaButtonReceiver(
- keyEvent, componentName);
- }
- }
- } else {
- ComponentName receiver =
- mCurrentFullUserRecord.mRestoredMediaButtonReceiver;
- int componentType = mCurrentFullUserRecord
- .mRestoredMediaButtonReceiverComponentType;
- UserHandle userHandle = UserHandle.of(mCurrentFullUserRecord
- .mRestoredMediaButtonReceiverUserId);
- if (DEBUG_KEY_EVENT) {
- Log.d(TAG, "Sending " + keyEvent + " to the restored intent "
- + receiver + ", type=" + componentType);
- }
- mediaButtonIntent.setComponent(receiver);
- try {
- switch (componentType) {
- case FullUserRecord.COMPONENT_TYPE_ACTIVITY:
- getContext().startActivityAsUser(mediaButtonIntent, userHandle);
- break;
- case FullUserRecord.COMPONENT_TYPE_SERVICE:
- getContext().startForegroundServiceAsUser(mediaButtonIntent,
- userHandle);
- break;
- default:
- // Legacy behavior for other cases.
- getContext().sendBroadcastAsUser(mediaButtonIntent, userHandle);
- }
- } catch (Exception e) {
- Log.w(TAG, "Error sending media button to the restored intent "
- + receiver + ", type=" + componentType, e);
- }
- if (mCurrentFullUserRecord.mCallback != null) {
- mCurrentFullUserRecord.mCallback
- .onMediaKeyEventDispatchedToMediaButtonReceiver(
- keyEvent, receiver);
- }
- }
- } catch (CanceledException e) {
- Log.i(TAG, "Error sending key event to media button receiver "
- + mCurrentFullUserRecord.mLastMediaButtonReceiver, e);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to send callback", e);
- }
- }
- }
-
- private void startVoiceInput(boolean needWakeLock) {
- Intent voiceIntent = null;
- // select which type of search to launch:
- // - screen on and device unlocked: action is ACTION_WEB_SEARCH
- // - device locked or screen off: action is
- // ACTION_VOICE_SEARCH_HANDS_FREE
- // with EXTRA_SECURE set to true if the device is securely locked
- PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE);
- boolean isLocked = mKeyguardManager != null && mKeyguardManager.isKeyguardLocked();
- if (!isLocked && pm.isScreenOn()) {
- voiceIntent = new Intent(android.speech.RecognizerIntent.ACTION_WEB_SEARCH);
- Log.i(TAG, "voice-based interactions: about to use ACTION_WEB_SEARCH");
- } else {
- voiceIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
- voiceIntent.putExtra(RecognizerIntent.EXTRA_SECURE,
- isLocked && mKeyguardManager.isKeyguardSecure());
- Log.i(TAG, "voice-based interactions: about to use ACTION_VOICE_SEARCH_HANDS_FREE");
- }
- // start the search activity
- if (needWakeLock) {
- mMediaEventWakeLock.acquire();
- }
- try {
- if (voiceIntent != null) {
- voiceIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
- if (DEBUG) Log.d(TAG, "voiceIntent: " + voiceIntent);
- getContext().startActivityAsUser(voiceIntent, UserHandle.CURRENT);
- }
- } catch (ActivityNotFoundException e) {
- Log.w(TAG, "No activity for search: " + e);
- } finally {
- if (needWakeLock) {
- mMediaEventWakeLock.release();
- }
- }
- }
-
- private boolean isVoiceKey(int keyCode) {
- return keyCode == KeyEvent.KEYCODE_HEADSETHOOK
- || (!mHasFeatureLeanback && keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
- }
-
- private boolean isUserSetupComplete() {
- return Settings.Secure.getIntForUser(getContext().getContentResolver(),
- Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
- }
-
- // we only handle public stream types, which are 0-5
- private boolean isValidLocalStreamType(int streamType) {
- return streamType >= AudioManager.STREAM_VOICE_CALL
- && streamType <= AudioManager.STREAM_NOTIFICATION;
- }
-
- private class MediaKeyListenerResultReceiver extends ResultReceiver implements Runnable {
- private final String mPackageName;
- private final int mPid;
- private final int mUid;
- private final boolean mAsSystemService;
- private final KeyEvent mKeyEvent;
- private final boolean mNeedWakeLock;
- private boolean mHandled;
-
- private MediaKeyListenerResultReceiver(String packageName, int pid, int uid,
- boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock) {
- super(mHandler);
- mHandler.postDelayed(this, MEDIA_KEY_LISTENER_TIMEOUT);
- mPackageName = packageName;
- mPid = pid;
- mUid = uid;
- mAsSystemService = asSystemService;
- mKeyEvent = keyEvent;
- mNeedWakeLock = needWakeLock;
- }
-
- @Override
- public void run() {
- Log.d(TAG, "The media key listener is timed-out for " + mKeyEvent);
- dispatchMediaKeyEvent();
- }
-
- @Override
- protected void onReceiveResult(int resultCode, Bundle resultData) {
- if (resultCode == MediaSessionManager.RESULT_MEDIA_KEY_HANDLED) {
- mHandled = true;
- mHandler.removeCallbacks(this);
- return;
- }
- dispatchMediaKeyEvent();
- }
-
- private void dispatchMediaKeyEvent() {
- if (mHandled) {
- return;
- }
- mHandled = true;
- mHandler.removeCallbacks(this);
- synchronized (mLock) {
- if (!isGlobalPriorityActiveLocked()
- && isVoiceKey(mKeyEvent.getKeyCode())) {
- handleVoiceKeyEventLocked(mPackageName, mPid, mUid, mAsSystemService,
- mKeyEvent, mNeedWakeLock);
- } else {
- dispatchMediaKeyEventLocked(mPackageName, mPid, mUid, mAsSystemService,
- mKeyEvent, mNeedWakeLock);
- }
- }
- }
- }
-
- private KeyEventWakeLockReceiver mKeyEventReceiver = new KeyEventWakeLockReceiver(mHandler);
-
- class KeyEventWakeLockReceiver extends ResultReceiver implements Runnable,
- PendingIntent.OnFinished {
- private final Handler mHandler;
- private int mRefCount = 0;
- private int mLastTimeoutId = 0;
-
- public KeyEventWakeLockReceiver(Handler handler) {
- super(handler);
- mHandler = handler;
- }
-
- public void onTimeout() {
- synchronized (mLock) {
- if (mRefCount == 0) {
- // We've already released it, so just return
- return;
- }
- mLastTimeoutId++;
- mRefCount = 0;
- releaseWakeLockLocked();
- }
- }
-
- public void aquireWakeLockLocked() {
- if (mRefCount == 0) {
- mMediaEventWakeLock.acquire();
- }
- mRefCount++;
- mHandler.removeCallbacks(this);
- mHandler.postDelayed(this, WAKELOCK_TIMEOUT);
-
- }
-
- @Override
- public void run() {
- onTimeout();
- }
-
- @Override
- protected void onReceiveResult(int resultCode, Bundle resultData) {
- if (resultCode < mLastTimeoutId) {
- // Ignore results from calls that were before the last
- // timeout, just in case.
- return;
- } else {
- synchronized (mLock) {
- if (mRefCount > 0) {
- mRefCount--;
- if (mRefCount == 0) {
- releaseWakeLockLocked();
- }
- }
- }
- }
- }
-
- private void releaseWakeLockLocked() {
- mMediaEventWakeLock.release();
- mHandler.removeCallbacks(this);
- }
-
- @Override
- public void onSendFinished(PendingIntent pendingIntent, Intent intent, int resultCode,
- String resultData, Bundle resultExtras) {
- onReceiveResult(resultCode, null);
- }
- };
-
- BroadcastReceiver mKeyEventDone = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (intent == null) {
- return;
- }
- Bundle extras = intent.getExtras();
- if (extras == null) {
- return;
- }
- synchronized (mLock) {
- if (extras.containsKey(EXTRA_WAKELOCK_ACQUIRED)
- && mMediaEventWakeLock.isHeld()) {
- mMediaEventWakeLock.release();
- }
- }
- }
- };
- }
-
- final class MessageHandler extends Handler {
- private static final int MSG_SESSIONS_CHANGED = 1;
- private static final int MSG_VOLUME_INITIAL_DOWN = 2;
- private final SparseArray<Integer> mIntegerCache = new SparseArray<>();
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_SESSIONS_CHANGED:
- pushSessionsChanged((int) msg.obj);
- break;
- case MSG_VOLUME_INITIAL_DOWN:
- synchronized (mLock) {
- FullUserRecord user = mUserRecords.get((int) msg.arg1);
- if (user != null && user.mInitialDownVolumeKeyEvent != null) {
- dispatchVolumeKeyLongPressLocked(user.mInitialDownVolumeKeyEvent);
- // Mark that the key is already handled.
- user.mInitialDownVolumeKeyEvent = null;
- }
- }
- break;
- }
- }
-
- public void postSessionsChanged(int userId) {
- // Use object instead of the arguments when posting message to remove pending requests.
- Integer userIdInteger = mIntegerCache.get(userId);
- if (userIdInteger == null) {
- userIdInteger = Integer.valueOf(userId);
- mIntegerCache.put(userId, userIdInteger);
- }
- removeMessages(MSG_SESSIONS_CHANGED, userIdInteger);
- obtainMessage(MSG_SESSIONS_CHANGED, userIdInteger).sendToTarget();
- }
- }
-
- private class Controller2Callback extends MediaController2.ControllerCallback {
- private final Session2Token mToken;
-
- Controller2Callback(Session2Token token) {
- mToken = token;
- }
-
- @Override
- public void onConnected(MediaController2 controller, Session2CommandGroup allowedCommands) {
- synchronized (mLock) {
- int userId = UserHandle.getUserId(mToken.getUid());
- mSession2TokensPerUser.get(userId).add(mToken);
- pushSession2TokensChangedLocked(userId);
- }
- }
-
- @Override
- public void onDisconnected(MediaController2 controller) {
- synchronized (mLock) {
- int userId = UserHandle.getUserId(mToken.getUid());
- mSession2TokensPerUser.get(userId).remove(mToken);
- pushSession2TokensChangedLocked(userId);
- }
- }
+ abstract static class ServiceImpl {
+ public abstract void onStart();
+ public abstract void notifyRemoteVolumeChanged(int flags, MediaSessionRecord session);
+ public abstract void onSessionPlaystateChanged(
+ MediaSessionRecord record, int oldState, int newState);
+ public abstract void onSessionPlaybackTypeChanged(MediaSessionRecord record);
+ public abstract void onStartUser(int userId);
+ public abstract void onSwitchUser(int userId);
+ public abstract void monitor();
+ public abstract void onMediaButtonReceiverChanged(MediaSessionRecord record);
+ protected abstract void enforcePhoneStatePermission(int pid, int uid);
+ abstract void updateSession(MediaSessionRecord record);
+ abstract void setGlobalPrioritySession(MediaSessionRecord record);
+ abstract List<Session2Token> getSession2TokensLocked(int userId);
+ abstract void onStopUser(int userId);
+ abstract void sessionDied(MediaSessionRecord session);
+ abstract void destroySession(MediaSessionRecord session);
+ abstract void pushSession2TokensChangedLocked(int userId);
+ abstract Context getContext();
+ abstract IBinder getServiceBinder();
}
}
diff --git a/services/core/java/com/android/server/media/MediaSessionServiceImpl.java b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
new file mode 100644
index 0000000..f374c6d
--- /dev/null
+++ b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
@@ -0,0 +1,2142 @@
+/*
+ * 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.server.media;
+
+import static android.os.UserHandle.USER_ALL;
+
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.INotificationManager;
+import android.app.KeyguardManager;
+import android.app.PendingIntent;
+import android.app.PendingIntent.CanceledException;
+import android.content.ActivityNotFoundException;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ServiceInfo;
+import android.content.pm.UserInfo;
+import android.database.ContentObserver;
+import android.media.AudioManager;
+import android.media.AudioManagerInternal;
+import android.media.AudioPlaybackConfiguration;
+import android.media.AudioSystem;
+import android.media.IAudioService;
+import android.media.IRemoteVolumeController;
+import android.media.MediaController2;
+import android.media.Session2CommandGroup;
+import android.media.Session2Token;
+import android.media.session.IActiveSessionsListener;
+import android.media.session.ICallback;
+import android.media.session.IOnMediaKeyListener;
+import android.media.session.IOnVolumeKeyLongPressListener;
+import android.media.session.ISession;
+import android.media.session.ISession2TokensListener;
+import android.media.session.ISessionManager;
+import android.media.session.MediaSession;
+import android.media.session.MediaSessionManager;
+import android.media.session.SessionCallbackLink;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerExecutor;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.speech.RecognizerIntent;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
+import android.view.KeyEvent;
+import android.view.ViewConfiguration;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.DumpUtils;
+import com.android.server.LocalServices;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * System implementation of MediaSessionManager
+ */
+public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl {
+ private static final String TAG = "MediaSessionService";
+ static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ // Leave log for key event always.
+ private static final boolean DEBUG_KEY_EVENT = true;
+
+ private static final int WAKELOCK_TIMEOUT = 5000;
+ private static final int MEDIA_KEY_LISTENER_TIMEOUT = 1000;
+
+ private final Context mContext;
+ private final SessionManagerImpl mSessionManagerImpl;
+ private final MessageHandler mHandler = new MessageHandler();
+ private final PowerManager.WakeLock mMediaEventWakeLock;
+ private final int mLongPressTimeout;
+ private final INotificationManager mNotificationManager;
+ private final Object mLock = new Object();
+ // Keeps the full user id for each user.
+ @GuardedBy("mLock")
+ private final SparseIntArray mFullUserIds = new SparseIntArray();
+ @GuardedBy("mLock")
+ private final SparseArray<FullUserRecord> mUserRecords = new SparseArray<FullUserRecord>();
+ @GuardedBy("mLock")
+ private final ArrayList<SessionsListenerRecord> mSessionsListeners =
+ new ArrayList<SessionsListenerRecord>();
+ // Map user id as index to list of Session2Tokens
+ // TODO: Keep session2 info in MediaSessionStack for prioritizing both session1 and session2 in
+ // one place.
+ @GuardedBy("mLock")
+ private final SparseArray<List<Session2Token>> mSession2TokensPerUser = new SparseArray<>();
+ @GuardedBy("mLock")
+ private final List<Session2TokensListenerRecord> mSession2TokensListenerRecords =
+ new ArrayList<>();
+
+ private KeyguardManager mKeyguardManager;
+ private IAudioService mAudioService;
+ private AudioManagerInternal mAudioManagerInternal;
+ private ActivityManager mActivityManager;
+ private ContentResolver mContentResolver;
+ private SettingsObserver mSettingsObserver;
+ private boolean mHasFeatureLeanback;
+
+ // The FullUserRecord of the current users. (i.e. The foreground user that isn't a profile)
+ // It's always not null after the MediaSessionService is started.
+ private FullUserRecord mCurrentFullUserRecord;
+ private MediaSessionRecord mGlobalPrioritySession;
+ private AudioPlayerStateMonitor mAudioPlayerStateMonitor;
+
+ // Used to notify system UI when remote volume was changed. TODO find a
+ // better way to handle this.
+ private IRemoteVolumeController mRvc;
+
+ public MediaSessionServiceImpl(Context context) {
+ mContext = context;
+ mSessionManagerImpl = new SessionManagerImpl();
+ PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+ mMediaEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleMediaEvent");
+ mLongPressTimeout = ViewConfiguration.getLongPressTimeout();
+ mNotificationManager = INotificationManager.Stub.asInterface(
+ ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+ }
+
+ Context getContext() {
+ return mContext;
+ }
+
+ IBinder getServiceBinder() {
+ return mSessionManagerImpl;
+ }
+
+ @Override
+ public void onStart() {
+ mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
+ mAudioService = getAudioService();
+ mAudioManagerInternal = LocalServices.getService(AudioManagerInternal.class);
+ mActivityManager =
+ (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
+ mAudioPlayerStateMonitor = AudioPlayerStateMonitor.getInstance();
+ mAudioPlayerStateMonitor.registerListener(
+ (config, isRemoved) -> {
+ if (isRemoved || !config.isActive() || config.getPlayerType()
+ == AudioPlaybackConfiguration.PLAYER_TYPE_JAM_SOUNDPOOL) {
+ return;
+ }
+ synchronized (mLock) {
+ FullUserRecord user = getFullUserRecordLocked(
+ UserHandle.getUserId(config.getClientUid()));
+ if (user != null) {
+ user.mPriorityStack.updateMediaButtonSessionIfNeeded();
+ }
+ }
+ }, null /* handler */);
+ mAudioPlayerStateMonitor.registerSelfIntoAudioServiceIfNeeded(mAudioService);
+ mContentResolver = mContext.getContentResolver();
+ mSettingsObserver = new SettingsObserver();
+ mSettingsObserver.observe();
+ mHasFeatureLeanback = mContext.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_LEANBACK);
+
+ updateUser();
+ }
+
+ private IAudioService getAudioService() {
+ IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
+ return IAudioService.Stub.asInterface(b);
+ }
+
+ private boolean isGlobalPriorityActiveLocked() {
+ return mGlobalPrioritySession != null && mGlobalPrioritySession.isActive();
+ }
+
+ @Override
+ public void updateSession(MediaSessionRecord record) {
+ synchronized (mLock) {
+ FullUserRecord user = getFullUserRecordLocked(record.getUserId());
+ if (user == null) {
+ Log.w(TAG, "Unknown session updated. Ignoring.");
+ return;
+ }
+ if ((record.getFlags() & MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0) {
+ if (DEBUG_KEY_EVENT) {
+ Log.d(TAG, "Global priority session is updated, active=" + record.isActive());
+ }
+ user.pushAddressedPlayerChangedLocked();
+ } else {
+ if (!user.mPriorityStack.contains(record)) {
+ Log.w(TAG, "Unknown session updated. Ignoring.");
+ return;
+ }
+ user.mPriorityStack.onSessionStateChange(record);
+ }
+ mHandler.postSessionsChanged(record.getUserId());
+ }
+ }
+
+ @Override
+ public void setGlobalPrioritySession(MediaSessionRecord record) {
+ synchronized (mLock) {
+ FullUserRecord user = getFullUserRecordLocked(record.getUserId());
+ if (mGlobalPrioritySession != record) {
+ Log.d(TAG, "Global priority session is changed from " + mGlobalPrioritySession
+ + " to " + record);
+ mGlobalPrioritySession = record;
+ if (user != null && user.mPriorityStack.contains(record)) {
+ // Handle the global priority session separately.
+ // Otherwise, it can be the media button session regardless of the active state
+ // because it or other system components might have been the lastly played media
+ // app.
+ user.mPriorityStack.removeSession(record);
+ }
+ }
+ }
+ }
+
+ private List<MediaSessionRecord> getActiveSessionsLocked(int userId) {
+ List<MediaSessionRecord> records = new ArrayList<>();
+ if (userId == USER_ALL) {
+ int size = mUserRecords.size();
+ for (int i = 0; i < size; i++) {
+ records.addAll(mUserRecords.valueAt(i).mPriorityStack.getActiveSessions(userId));
+ }
+ } else {
+ FullUserRecord user = getFullUserRecordLocked(userId);
+ if (user == null) {
+ Log.w(TAG, "getSessions failed. Unknown user " + userId);
+ return records;
+ }
+ records.addAll(user.mPriorityStack.getActiveSessions(userId));
+ }
+
+ // Return global priority session at the first whenever it's asked.
+ if (isGlobalPriorityActiveLocked()
+ && (userId == USER_ALL || userId == mGlobalPrioritySession.getUserId())) {
+ records.add(0, mGlobalPrioritySession);
+ }
+ return records;
+ }
+
+ List<Session2Token> getSession2TokensLocked(int userId) {
+ List<Session2Token> list = new ArrayList<>();
+ if (userId == USER_ALL) {
+ for (int i = 0; i < mSession2TokensPerUser.size(); i++) {
+ list.addAll(mSession2TokensPerUser.valueAt(i));
+ }
+ } else {
+ list.addAll(mSession2TokensPerUser.get(userId));
+ }
+ return list;
+ }
+
+ /**
+ * Tells the system UI that volume has changed on an active remote session.
+ */
+ public void notifyRemoteVolumeChanged(int flags, MediaSessionRecord session) {
+ if (mRvc == null || !session.isActive()) {
+ return;
+ }
+ try {
+ mRvc.remoteVolumeChanged(session.getControllerBinder(), flags);
+ } catch (Exception e) {
+ Log.wtf(TAG, "Error sending volume change to system UI.", e);
+ }
+ }
+
+ @Override
+ public void onSessionPlaystateChanged(MediaSessionRecord record, int oldState, int newState) {
+ synchronized (mLock) {
+ FullUserRecord user = getFullUserRecordLocked(record.getUserId());
+ if (user == null || !user.mPriorityStack.contains(record)) {
+ Log.d(TAG, "Unknown session changed playback state. Ignoring.");
+ return;
+ }
+ user.mPriorityStack.onPlaystateChanged(record, oldState, newState);
+ }
+ }
+
+ @Override
+ public void onSessionPlaybackTypeChanged(MediaSessionRecord record) {
+ synchronized (mLock) {
+ FullUserRecord user = getFullUserRecordLocked(record.getUserId());
+ if (user == null || !user.mPriorityStack.contains(record)) {
+ Log.d(TAG, "Unknown session changed playback type. Ignoring.");
+ return;
+ }
+ pushRemoteVolumeUpdateLocked(record.getUserId());
+ }
+ }
+
+ @Override
+ public void onStartUser(int userId) {
+ if (DEBUG) Log.d(TAG, "onStartUser: " + userId);
+ updateUser();
+ }
+
+ @Override
+ public void onSwitchUser(int userId) {
+ if (DEBUG) Log.d(TAG, "onSwitchUser: " + userId);
+ updateUser();
+ }
+
+ // Called when the user with the userId is removed.
+ @Override
+ public void onStopUser(int userId) {
+ if (DEBUG) Log.d(TAG, "onStopUser: " + userId);
+ synchronized (mLock) {
+ // TODO: Also handle removing user in updateUser() because adding/switching user is
+ // handled in updateUser().
+ FullUserRecord user = getFullUserRecordLocked(userId);
+ if (user != null) {
+ if (user.mFullUserId == userId) {
+ user.destroySessionsForUserLocked(USER_ALL);
+ mUserRecords.remove(userId);
+ } else {
+ user.destroySessionsForUserLocked(userId);
+ }
+ }
+ mSession2TokensPerUser.remove(userId);
+ updateUser();
+ }
+ }
+
+ @Override
+ public void monitor() {
+ synchronized (mLock) {
+ // Check for deadlock
+ }
+ }
+
+ protected void enforcePhoneStatePermission(int pid, int uid) {
+ if (mContext.checkPermission(android.Manifest.permission.MODIFY_PHONE_STATE, pid, uid)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Must hold the MODIFY_PHONE_STATE permission.");
+ }
+ }
+
+ void sessionDied(MediaSessionRecord session) {
+ synchronized (mLock) {
+ destroySessionLocked(session);
+ }
+ }
+
+ void destroySession(MediaSessionRecord session) {
+ synchronized (mLock) {
+ destroySessionLocked(session);
+ }
+ }
+
+ private void updateUser() {
+ synchronized (mLock) {
+ UserManager manager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ mFullUserIds.clear();
+ List<UserInfo> allUsers = manager.getUsers();
+ if (allUsers != null) {
+ for (UserInfo userInfo : allUsers) {
+ if (userInfo.isManagedProfile()) {
+ mFullUserIds.put(userInfo.id, userInfo.profileGroupId);
+ } else {
+ mFullUserIds.put(userInfo.id, userInfo.id);
+ if (mUserRecords.get(userInfo.id) == null) {
+ mUserRecords.put(userInfo.id, new FullUserRecord(userInfo.id));
+ }
+ }
+ if (mSession2TokensPerUser.get(userInfo.id) == null) {
+ mSession2TokensPerUser.put(userInfo.id, new ArrayList<>());
+ }
+ }
+ }
+ // Ensure that the current full user exists.
+ int currentFullUserId = ActivityManager.getCurrentUser();
+ mCurrentFullUserRecord = mUserRecords.get(currentFullUserId);
+ if (mCurrentFullUserRecord == null) {
+ Log.w(TAG, "Cannot find FullUserInfo for the current user " + currentFullUserId);
+ mCurrentFullUserRecord = new FullUserRecord(currentFullUserId);
+ mUserRecords.put(currentFullUserId, mCurrentFullUserRecord);
+ if (mSession2TokensPerUser.get(currentFullUserId) == null) {
+ mSession2TokensPerUser.put(currentFullUserId, new ArrayList<>());
+ }
+ }
+ mFullUserIds.put(currentFullUserId, currentFullUserId);
+ }
+ }
+
+ private void updateActiveSessionListeners() {
+ synchronized (mLock) {
+ for (int i = mSessionsListeners.size() - 1; i >= 0; i--) {
+ SessionsListenerRecord listener = mSessionsListeners.get(i);
+ try {
+ enforceMediaPermissions(listener.componentName, listener.pid, listener.uid,
+ listener.userId);
+ } catch (SecurityException e) {
+ Log.i(TAG, "ActiveSessionsListener " + listener.componentName
+ + " is no longer authorized. Disconnecting.");
+ mSessionsListeners.remove(i);
+ try {
+ listener.listener
+ .onActiveSessionsChanged(new ArrayList<MediaSession.Token>());
+ } catch (Exception e1) {
+ // ignore
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ * When a session is removed several things need to happen.
+ * 1. We need to remove it from the relevant user.
+ * 2. We need to remove it from the priority stack.
+ * 3. We need to remove it from all sessions.
+ * 4. If this is the system priority session we need to clear it.
+ * 5. We need to unlink to death from the cb binder
+ * 6. We need to tell the session to do any final cleanup (onDestroy)
+ */
+ private void destroySessionLocked(MediaSessionRecord session) {
+ if (DEBUG) {
+ Log.d(TAG, "Destroying " + session);
+ }
+ FullUserRecord user = getFullUserRecordLocked(session.getUserId());
+ if (mGlobalPrioritySession == session) {
+ mGlobalPrioritySession = null;
+ if (session.isActive() && user != null) {
+ user.pushAddressedPlayerChangedLocked();
+ }
+ } else {
+ if (user != null) {
+ user.mPriorityStack.removeSession(session);
+ }
+ }
+
+ try {
+ session.getCallback().getBinder().unlinkToDeath(session, 0);
+ } catch (Exception e) {
+ // ignore exceptions while destroying a session.
+ }
+ session.onDestroy();
+ mHandler.postSessionsChanged(session.getUserId());
+ }
+
+ private void enforcePackageName(String packageName, int uid) {
+ if (TextUtils.isEmpty(packageName)) {
+ throw new IllegalArgumentException("packageName may not be empty");
+ }
+ String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
+ final int packageCount = packages.length;
+ for (int i = 0; i < packageCount; i++) {
+ if (packageName.equals(packages[i])) {
+ return;
+ }
+ }
+ throw new IllegalArgumentException("packageName is not owned by the calling process");
+ }
+
+ /**
+ * Checks a caller's authorization to register an IRemoteControlDisplay.
+ * Authorization is granted if one of the following is true:
+ * <ul>
+ * <li>the caller has android.Manifest.permission.MEDIA_CONTENT_CONTROL
+ * permission</li>
+ * <li>the caller's listener is one of the enabled notification listeners
+ * for the caller's user</li>
+ * </ul>
+ */
+ private void enforceMediaPermissions(ComponentName compName, int pid, int uid,
+ int resolvedUserId) {
+ if (isCurrentVolumeController(pid, uid)) return;
+ if (mContext
+ .checkPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid)
+ != PackageManager.PERMISSION_GRANTED
+ && !isEnabledNotificationListener(compName, UserHandle.getUserId(uid),
+ resolvedUserId)) {
+ throw new SecurityException("Missing permission to control media.");
+ }
+ }
+
+ private boolean isCurrentVolumeController(int pid, int uid) {
+ return mContext.checkPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
+ pid, uid) == PackageManager.PERMISSION_GRANTED;
+ }
+
+ private void enforceSystemUiPermission(String action, int pid, int uid) {
+ if (!isCurrentVolumeController(pid, uid)) {
+ throw new SecurityException("Only system ui may " + action);
+ }
+ }
+
+ /**
+ * This checks if the component is an enabled notification listener for the
+ * specified user. Enabled components may only operate on behalf of the user
+ * they're running as.
+ *
+ * @param compName The component that is enabled.
+ * @param userId The user id of the caller.
+ * @param forUserId The user id they're making the request on behalf of.
+ * @return True if the component is enabled, false otherwise
+ */
+ private boolean isEnabledNotificationListener(ComponentName compName, int userId,
+ int forUserId) {
+ if (userId != forUserId) {
+ // You may not access another user's content as an enabled listener.
+ return false;
+ }
+ if (DEBUG) {
+ Log.d(TAG, "Checking if enabled notification listener " + compName);
+ }
+ if (compName != null) {
+ try {
+ return mNotificationManager.isNotificationListenerAccessGrantedForUser(
+ compName, userId);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Dead NotificationManager in isEnabledNotificationListener", e);
+ }
+ }
+ return false;
+ }
+
+ private MediaSessionRecord createSessionInternal(int callerPid, int callerUid, int userId,
+ String callerPackageName, SessionCallbackLink cb, String tag) throws RemoteException {
+ synchronized (mLock) {
+ return createSessionLocked(callerPid, callerUid, userId, callerPackageName, cb, tag);
+ }
+ }
+
+ /*
+ * When a session is created the following things need to happen.
+ * 1. Its callback binder needs a link to death
+ * 2. It needs to be added to all sessions.
+ * 3. It needs to be added to the priority stack.
+ * 4. It needs to be added to the relevant user record.
+ */
+ private MediaSessionRecord createSessionLocked(int callerPid, int callerUid, int userId,
+ String callerPackageName, SessionCallbackLink cb, String tag) {
+ FullUserRecord user = getFullUserRecordLocked(userId);
+ if (user == null) {
+ Log.wtf(TAG, "Request from invalid user: " + userId);
+ throw new RuntimeException("Session request from invalid user.");
+ }
+
+ final MediaSessionRecord session = new MediaSessionRecord(callerPid, callerUid, userId,
+ callerPackageName, cb, tag, this, mHandler.getLooper());
+ try {
+ cb.getBinder().linkToDeath(session, 0);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Media Session owner died prematurely.", e);
+ }
+
+ user.mPriorityStack.addSession(session);
+ mHandler.postSessionsChanged(userId);
+
+ if (DEBUG) {
+ Log.d(TAG, "Created session for " + callerPackageName + " with tag " + tag);
+ }
+ return session;
+ }
+
+ private int findIndexOfSessionsListenerLocked(IActiveSessionsListener listener) {
+ for (int i = mSessionsListeners.size() - 1; i >= 0; i--) {
+ if (mSessionsListeners.get(i).listener.asBinder() == listener.asBinder()) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ private int findIndexOfSession2TokensListenerLocked(ISession2TokensListener listener) {
+ for (int i = mSession2TokensListenerRecords.size() - 1; i >= 0; i--) {
+ if (mSession2TokensListenerRecords.get(i).listener.asBinder() == listener.asBinder()) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+
+ private void pushSessionsChanged(int userId) {
+ synchronized (mLock) {
+ FullUserRecord user = getFullUserRecordLocked(userId);
+ if (user == null) {
+ Log.w(TAG, "pushSessionsChanged failed. No user with id=" + userId);
+ return;
+ }
+ List<MediaSessionRecord> records = getActiveSessionsLocked(userId);
+ int size = records.size();
+ ArrayList<MediaSession.Token> tokens = new ArrayList<MediaSession.Token>();
+ for (int i = 0; i < size; i++) {
+ tokens.add(new MediaSession.Token(records.get(i).getControllerBinder()));
+ }
+ pushRemoteVolumeUpdateLocked(userId);
+ for (int i = mSessionsListeners.size() - 1; i >= 0; i--) {
+ SessionsListenerRecord record = mSessionsListeners.get(i);
+ if (record.userId == USER_ALL || record.userId == userId) {
+ try {
+ record.listener.onActiveSessionsChanged(tokens);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Dead ActiveSessionsListener in pushSessionsChanged, removing",
+ e);
+ mSessionsListeners.remove(i);
+ }
+ }
+ }
+ }
+ }
+
+ private void pushRemoteVolumeUpdateLocked(int userId) {
+ if (mRvc != null) {
+ try {
+ FullUserRecord user = getFullUserRecordLocked(userId);
+ if (user == null) {
+ Log.w(TAG, "pushRemoteVolumeUpdateLocked failed. No user with id=" + userId);
+ return;
+ }
+ MediaSessionRecord record = user.mPriorityStack.getDefaultRemoteSession(userId);
+ mRvc.updateRemoteController(record == null ? null : record.getControllerBinder());
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Error sending default remote volume to sys ui.", e);
+ }
+ }
+ }
+
+ void pushSession2TokensChangedLocked(int userId) {
+ List<Session2Token> allSession2Tokens = getSession2TokensLocked(USER_ALL);
+ List<Session2Token> session2Tokens = getSession2TokensLocked(userId);
+
+ for (int i = mSession2TokensListenerRecords.size() - 1; i >= 0; i--) {
+ Session2TokensListenerRecord listenerRecord = mSession2TokensListenerRecords.get(i);
+ try {
+ if (listenerRecord.userId == USER_ALL) {
+ listenerRecord.listener.onSession2TokensChanged(allSession2Tokens);
+ } else if (listenerRecord.userId == userId) {
+ listenerRecord.listener.onSession2TokensChanged(session2Tokens);
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to notify Session2Token change. Removing listener.", e);
+ mSession2TokensListenerRecords.remove(i);
+ }
+ }
+ }
+
+ /**
+ * Called when the media button receiver for the {@code record} is changed.
+ *
+ * @param record the media session whose media button receiver is updated.
+ */
+ public void onMediaButtonReceiverChanged(MediaSessionRecord record) {
+ synchronized (mLock) {
+ FullUserRecord user = getFullUserRecordLocked(record.getUserId());
+ MediaSessionRecord mediaButtonSession =
+ user.mPriorityStack.getMediaButtonSession();
+ if (record == mediaButtonSession) {
+ user.rememberMediaButtonReceiverLocked(mediaButtonSession);
+ }
+ }
+ }
+
+ private String getCallingPackageName(int uid) {
+ String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
+ if (packages != null && packages.length > 0) {
+ return packages[0];
+ }
+ return "";
+ }
+
+ private void dispatchVolumeKeyLongPressLocked(KeyEvent keyEvent) {
+ if (mCurrentFullUserRecord.mOnVolumeKeyLongPressListener == null) {
+ return;
+ }
+ try {
+ mCurrentFullUserRecord.mOnVolumeKeyLongPressListener.onVolumeKeyLongPress(keyEvent);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to send " + keyEvent + " to volume key long-press listener");
+ }
+ }
+
+ private FullUserRecord getFullUserRecordLocked(int userId) {
+ int fullUserId = mFullUserIds.get(userId, -1);
+ if (fullUserId < 0) {
+ return null;
+ }
+ return mUserRecords.get(fullUserId);
+ }
+
+ /**
+ * Information about a full user and its corresponding managed profiles.
+ *
+ * <p>Since the full user runs together with its managed profiles, a user wouldn't differentiate
+ * them when he/she presses a media/volume button. So keeping media sessions for them in one
+ * place makes more sense and increases the readability.</p>
+ * <p>The contents of this object is guarded by {@link #mLock}.
+ */
+ final class FullUserRecord implements MediaSessionStack.OnMediaButtonSessionChangedListener {
+ public static final int COMPONENT_TYPE_INVALID = 0;
+ public static final int COMPONENT_TYPE_BROADCAST = 1;
+ public static final int COMPONENT_TYPE_ACTIVITY = 2;
+ public static final int COMPONENT_TYPE_SERVICE = 3;
+ private static final String COMPONENT_NAME_USER_ID_DELIM = ",";
+
+ private final int mFullUserId;
+ private final MediaSessionStack mPriorityStack;
+ private PendingIntent mLastMediaButtonReceiver;
+ private ComponentName mRestoredMediaButtonReceiver;
+ private int mRestoredMediaButtonReceiverComponentType;
+ private int mRestoredMediaButtonReceiverUserId;
+
+ private IOnVolumeKeyLongPressListener mOnVolumeKeyLongPressListener;
+ private int mOnVolumeKeyLongPressListenerUid;
+ private KeyEvent mInitialDownVolumeKeyEvent;
+ private int mInitialDownVolumeStream;
+ private boolean mInitialDownMusicOnly;
+
+ private IOnMediaKeyListener mOnMediaKeyListener;
+ private int mOnMediaKeyListenerUid;
+ private ICallback mCallback;
+
+ FullUserRecord(int fullUserId) {
+ mFullUserId = fullUserId;
+ mPriorityStack = new MediaSessionStack(mAudioPlayerStateMonitor, this);
+ // Restore the remembered media button receiver before the boot.
+ String mediaButtonReceiverInfo = Settings.Secure.getStringForUser(mContentResolver,
+ Settings.System.MEDIA_BUTTON_RECEIVER, mFullUserId);
+ if (mediaButtonReceiverInfo == null) {
+ return;
+ }
+ String[] tokens = mediaButtonReceiverInfo.split(COMPONENT_NAME_USER_ID_DELIM);
+ if (tokens == null || (tokens.length != 2 && tokens.length != 3)) {
+ return;
+ }
+ mRestoredMediaButtonReceiver = ComponentName.unflattenFromString(tokens[0]);
+ mRestoredMediaButtonReceiverUserId = Integer.parseInt(tokens[1]);
+ if (tokens.length == 3) {
+ mRestoredMediaButtonReceiverComponentType = Integer.parseInt(tokens[2]);
+ } else {
+ mRestoredMediaButtonReceiverComponentType =
+ getComponentType(mRestoredMediaButtonReceiver);
+ }
+ }
+
+ public void destroySessionsForUserLocked(int userId) {
+ List<MediaSessionRecord> sessions = mPriorityStack.getPriorityList(false, userId);
+ for (MediaSessionRecord session : sessions) {
+ MediaSessionServiceImpl.this.destroySessionLocked(session);
+ }
+ }
+
+ public void dumpLocked(PrintWriter pw, String prefix) {
+ pw.print(prefix + "Record for full_user=" + mFullUserId);
+ // Dump managed profile user ids associated with this user.
+ int size = mFullUserIds.size();
+ for (int i = 0; i < size; i++) {
+ if (mFullUserIds.keyAt(i) != mFullUserIds.valueAt(i)
+ && mFullUserIds.valueAt(i) == mFullUserId) {
+ pw.print(", profile_user=" + mFullUserIds.keyAt(i));
+ }
+ }
+ pw.println();
+ String indent = prefix + " ";
+ pw.println(indent + "Volume key long-press listener: " + mOnVolumeKeyLongPressListener);
+ pw.println(indent + "Volume key long-press listener package: "
+ + getCallingPackageName(mOnVolumeKeyLongPressListenerUid));
+ pw.println(indent + "Media key listener: " + mOnMediaKeyListener);
+ pw.println(indent + "Media key listener package: "
+ + getCallingPackageName(mOnMediaKeyListenerUid));
+ pw.println(indent + "Callback: " + mCallback);
+ pw.println(indent + "Last MediaButtonReceiver: " + mLastMediaButtonReceiver);
+ pw.println(indent + "Restored MediaButtonReceiver: " + mRestoredMediaButtonReceiver);
+ pw.println(indent + "Restored MediaButtonReceiverComponentType: "
+ + mRestoredMediaButtonReceiverComponentType);
+ mPriorityStack.dump(pw, indent);
+ pw.println(indent + "Session2Tokens:");
+ for (int i = 0; i < mSession2TokensPerUser.size(); i++) {
+ List<Session2Token> list = mSession2TokensPerUser.valueAt(i);
+ if (list == null || list.size() == 0) {
+ continue;
+ }
+ for (Session2Token token : list) {
+ pw.println(indent + " " + token);
+ }
+ }
+ }
+
+ @Override
+ public void onMediaButtonSessionChanged(MediaSessionRecord oldMediaButtonSession,
+ MediaSessionRecord newMediaButtonSession) {
+ if (DEBUG_KEY_EVENT) {
+ Log.d(TAG, "Media button session is changed to " + newMediaButtonSession);
+ }
+ synchronized (mLock) {
+ if (oldMediaButtonSession != null) {
+ mHandler.postSessionsChanged(oldMediaButtonSession.getUserId());
+ }
+ if (newMediaButtonSession != null) {
+ rememberMediaButtonReceiverLocked(newMediaButtonSession);
+ mHandler.postSessionsChanged(newMediaButtonSession.getUserId());
+ }
+ pushAddressedPlayerChangedLocked();
+ }
+ }
+
+ // Remember media button receiver and keep it in the persistent storage.
+ public void rememberMediaButtonReceiverLocked(MediaSessionRecord record) {
+ PendingIntent receiver = record.getMediaButtonReceiver();
+ mLastMediaButtonReceiver = receiver;
+ mRestoredMediaButtonReceiver = null;
+ mRestoredMediaButtonReceiverComponentType = COMPONENT_TYPE_INVALID;
+
+ String mediaButtonReceiverInfo = "";
+ if (receiver != null) {
+ ComponentName component = receiver.getIntent().getComponent();
+ if (component != null
+ && record.getPackageName().equals(component.getPackageName())) {
+ String componentName = component.flattenToString();
+ int componentType = getComponentType(component);
+ mediaButtonReceiverInfo = String.join(COMPONENT_NAME_USER_ID_DELIM,
+ componentName, String.valueOf(record.getUserId()),
+ String.valueOf(componentType));
+ }
+ }
+ Settings.Secure.putStringForUser(mContentResolver,
+ Settings.System.MEDIA_BUTTON_RECEIVER, mediaButtonReceiverInfo,
+ mFullUserId);
+ }
+
+ private void pushAddressedPlayerChangedLocked() {
+ if (mCallback == null) {
+ return;
+ }
+ try {
+ MediaSessionRecord mediaButtonSession = getMediaButtonSessionLocked();
+ if (mediaButtonSession != null) {
+ mCallback.onAddressedPlayerChangedToMediaSession(
+ new MediaSession.Token(mediaButtonSession.getControllerBinder()));
+ } else if (mCurrentFullUserRecord.mLastMediaButtonReceiver != null) {
+ mCallback.onAddressedPlayerChangedToMediaButtonReceiver(
+ mCurrentFullUserRecord.mLastMediaButtonReceiver
+ .getIntent().getComponent());
+ } else if (mCurrentFullUserRecord.mRestoredMediaButtonReceiver != null) {
+ mCallback.onAddressedPlayerChangedToMediaButtonReceiver(
+ mCurrentFullUserRecord.mRestoredMediaButtonReceiver);
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to pushAddressedPlayerChangedLocked", e);
+ }
+ }
+
+ private MediaSessionRecord getMediaButtonSessionLocked() {
+ return isGlobalPriorityActiveLocked()
+ ? mGlobalPrioritySession : mPriorityStack.getMediaButtonSession();
+ }
+
+ private int getComponentType(@Nullable ComponentName componentName) {
+ if (componentName == null) {
+ return COMPONENT_TYPE_INVALID;
+ }
+ PackageManager pm = mContext.getPackageManager();
+ try {
+ ActivityInfo activityInfo = pm.getActivityInfo(componentName,
+ PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+ | PackageManager.GET_ACTIVITIES);
+ if (activityInfo != null) {
+ return COMPONENT_TYPE_ACTIVITY;
+ }
+ } catch (NameNotFoundException e) {
+ }
+ try {
+ ServiceInfo serviceInfo = pm.getServiceInfo(componentName,
+ PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+ | PackageManager.GET_SERVICES);
+ if (serviceInfo != null) {
+ return COMPONENT_TYPE_SERVICE;
+ }
+ } catch (NameNotFoundException e) {
+ }
+ // Pick legacy behavior for BroadcastReceiver or unknown.
+ return COMPONENT_TYPE_BROADCAST;
+ }
+ }
+
+ final class SessionsListenerRecord implements IBinder.DeathRecipient {
+ public final IActiveSessionsListener listener;
+ public final ComponentName componentName;
+ public final int userId;
+ public final int pid;
+ public final int uid;
+
+ SessionsListenerRecord(IActiveSessionsListener listener,
+ ComponentName componentName,
+ int userId, int pid, int uid) {
+ this.listener = listener;
+ this.componentName = componentName;
+ this.userId = userId;
+ this.pid = pid;
+ this.uid = uid;
+ }
+
+ @Override
+ public void binderDied() {
+ synchronized (mLock) {
+ mSessionsListeners.remove(this);
+ }
+ }
+ }
+
+ final class Session2TokensListenerRecord implements IBinder.DeathRecipient {
+ public final ISession2TokensListener listener;
+ public final int userId;
+
+ Session2TokensListenerRecord(ISession2TokensListener listener,
+ int userId) {
+ this.listener = listener;
+ this.userId = userId;
+ }
+
+ @Override
+ public void binderDied() {
+ synchronized (mLock) {
+ mSession2TokensListenerRecords.remove(this);
+ }
+ }
+ }
+
+ final class SettingsObserver extends ContentObserver {
+ private final Uri mSecureSettingsUri = Settings.Secure.getUriFor(
+ Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
+
+ private SettingsObserver() {
+ super(null);
+ }
+
+ private void observe() {
+ mContentResolver.registerContentObserver(mSecureSettingsUri,
+ false, this, USER_ALL);
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ updateActiveSessionListeners();
+ }
+ }
+
+ class SessionManagerImpl extends ISessionManager.Stub {
+ private static final String EXTRA_WAKELOCK_ACQUIRED =
+ "android.media.AudioService.WAKELOCK_ACQUIRED";
+ private static final int WAKELOCK_RELEASE_ON_FINISHED = 1980; // magic number
+
+ private boolean mVoiceButtonDown = false;
+ private boolean mVoiceButtonHandled = false;
+
+ @Override
+ public ISession createSession(String packageName, SessionCallbackLink cb, String tag,
+ int userId) throws RemoteException {
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ enforcePackageName(packageName, uid);
+ int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
+ false /* allowAll */, true /* requireFull */, "createSession", packageName);
+ if (cb == null) {
+ throw new IllegalArgumentException("Controller callback cannot be null");
+ }
+ return createSessionInternal(pid, uid, resolvedUserId, packageName, cb, tag)
+ .getSessionBinder();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void notifySession2Created(Session2Token sessionToken) throws RemoteException {
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ if (DEBUG) {
+ Log.d(TAG, "Session2 is created " + sessionToken);
+ }
+ if (uid != sessionToken.getUid()) {
+ throw new SecurityException("Unexpected Session2Token's UID, expected=" + uid
+ + " but actually=" + sessionToken.getUid());
+ }
+ Controller2Callback callback = new Controller2Callback(sessionToken);
+ // Note: It's safe not to keep controller here because it wouldn't be GC'ed until
+ // it's closed.
+ // TODO: Keep controller as well for better readability
+ // because the GC behavior isn't straightforward.
+ MediaController2 controller = new MediaController2(mContext, sessionToken,
+ new HandlerExecutor(mHandler), callback);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public List<IBinder> getSessions(ComponentName componentName, int userId) {
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+
+ try {
+ int resolvedUserId = verifySessionsRequest(componentName, userId, pid, uid);
+ ArrayList<IBinder> binders = new ArrayList<IBinder>();
+ synchronized (mLock) {
+ List<MediaSessionRecord> records = getActiveSessionsLocked(resolvedUserId);
+ for (MediaSessionRecord record : records) {
+ binders.add(record.getControllerBinder().asBinder());
+ }
+ }
+ return binders;
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public List<Session2Token> getSession2Tokens(int userId) {
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+
+ try {
+ // Check that they can make calls on behalf of the user and
+ // get the final user id
+ int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
+ true /* allowAll */, true /* requireFull */, "getSession2Tokens",
+ null /* optional packageName */);
+ List<Session2Token> result;
+ synchronized (mLock) {
+ result = getSession2TokensLocked(resolvedUserId);
+ }
+ return result;
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void addSessionsListener(IActiveSessionsListener listener,
+ ComponentName componentName, int userId) throws RemoteException {
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+
+ try {
+ int resolvedUserId = verifySessionsRequest(componentName, userId, pid, uid);
+ synchronized (mLock) {
+ int index = findIndexOfSessionsListenerLocked(listener);
+ if (index != -1) {
+ Log.w(TAG, "ActiveSessionsListener is already added, ignoring");
+ return;
+ }
+ SessionsListenerRecord record = new SessionsListenerRecord(listener,
+ componentName, resolvedUserId, pid, uid);
+ try {
+ listener.asBinder().linkToDeath(record, 0);
+ } catch (RemoteException e) {
+ Log.e(TAG, "ActiveSessionsListener is dead, ignoring it", e);
+ return;
+ }
+ mSessionsListeners.add(record);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void removeSessionsListener(IActiveSessionsListener listener)
+ throws RemoteException {
+ synchronized (mLock) {
+ int index = findIndexOfSessionsListenerLocked(listener);
+ if (index != -1) {
+ SessionsListenerRecord record = mSessionsListeners.remove(index);
+ try {
+ record.listener.asBinder().unlinkToDeath(record, 0);
+ } catch (Exception e) {
+ // ignore exceptions, the record is being removed
+ }
+ }
+ }
+ }
+
+ @Override
+ public void addSession2TokensListener(ISession2TokensListener listener,
+ int userId) {
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+
+ try {
+ // Check that they can make calls on behalf of the user and get the final user id.
+ int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
+ true /* allowAll */, true /* requireFull */, "addSession2TokensListener",
+ null /* optional packageName */);
+ synchronized (mLock) {
+ int index = findIndexOfSession2TokensListenerLocked(listener);
+ if (index >= 0) {
+ Log.w(TAG, "addSession2TokensListener is already added, ignoring");
+ return;
+ }
+ mSession2TokensListenerRecords.add(
+ new Session2TokensListenerRecord(listener, resolvedUserId));
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void removeSession2TokensListener(ISession2TokensListener listener) {
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+
+ try {
+ synchronized (mLock) {
+ int index = findIndexOfSession2TokensListenerLocked(listener);
+ if (index >= 0) {
+ Session2TokensListenerRecord listenerRecord =
+ mSession2TokensListenerRecords.remove(index);
+ try {
+ listenerRecord.listener.asBinder().unlinkToDeath(listenerRecord, 0);
+ } catch (Exception e) {
+ // Ignore exception.
+ }
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ /**
+ * Handles the dispatching of the media button events to one of the
+ * registered listeners, or if there was none, broadcast an
+ * ACTION_MEDIA_BUTTON intent to the rest of the system.
+ *
+ * @param packageName The caller package
+ * @param asSystemService {@code true} if the event sent to the session as if it was come
+ * from the system service instead of the app process. This helps sessions to
+ * distinguish between the key injection by the app and key events from the
+ * hardware devices. Should be used only when the volume key events aren't handled
+ * by foreground activity. {@code false} otherwise to tell session about the real
+ * caller.
+ * @param keyEvent a non-null KeyEvent whose key code is one of the
+ * supported media buttons
+ * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held
+ * while this key event is dispatched.
+ */
+ @Override
+ public void dispatchMediaKeyEvent(String packageName, boolean asSystemService,
+ KeyEvent keyEvent, boolean needWakeLock) {
+ if (keyEvent == null || !KeyEvent.isMediaSessionKey(keyEvent.getKeyCode())) {
+ Log.w(TAG, "Attempted to dispatch null or non-media key event.");
+ return;
+ }
+
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ if (DEBUG) {
+ Log.d(TAG, "dispatchMediaKeyEvent, pkg=" + packageName + " pid=" + pid
+ + ", uid=" + uid + ", asSystem=" + asSystemService + ", event="
+ + keyEvent);
+ }
+ if (!isUserSetupComplete()) {
+ // Global media key handling can have the side-effect of starting new
+ // activities which is undesirable while setup is in progress.
+ Slog.i(TAG, "Not dispatching media key event because user "
+ + "setup is in progress.");
+ return;
+ }
+
+ synchronized (mLock) {
+ boolean isGlobalPriorityActive = isGlobalPriorityActiveLocked();
+ if (isGlobalPriorityActive && uid != Process.SYSTEM_UID) {
+ // Prevent dispatching key event through reflection while the global
+ // priority session is active.
+ Slog.i(TAG, "Only the system can dispatch media key event "
+ + "to the global priority session.");
+ return;
+ }
+ if (!isGlobalPriorityActive) {
+ if (mCurrentFullUserRecord.mOnMediaKeyListener != null) {
+ if (DEBUG_KEY_EVENT) {
+ Log.d(TAG, "Send " + keyEvent + " to the media key listener");
+ }
+ try {
+ mCurrentFullUserRecord.mOnMediaKeyListener.onMediaKey(keyEvent,
+ new MediaKeyListenerResultReceiver(packageName, pid, uid,
+ asSystemService, keyEvent, needWakeLock));
+ return;
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to send " + keyEvent
+ + " to the media key listener");
+ }
+ }
+ }
+ if (!isGlobalPriorityActive && isVoiceKey(keyEvent.getKeyCode())) {
+ handleVoiceKeyEventLocked(packageName, pid, uid, asSystemService, keyEvent,
+ needWakeLock);
+ } else {
+ dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService,
+ keyEvent, needWakeLock);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void setCallback(ICallback callback) {
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ if (!UserHandle.isSameApp(uid, Process.BLUETOOTH_UID)) {
+ throw new SecurityException("Only Bluetooth service processes can set"
+ + " Callback");
+ }
+ synchronized (mLock) {
+ int userId = UserHandle.getUserId(uid);
+ FullUserRecord user = getFullUserRecordLocked(userId);
+ if (user == null || user.mFullUserId != userId) {
+ Log.w(TAG, "Only the full user can set the callback"
+ + ", userId=" + userId);
+ return;
+ }
+ user.mCallback = callback;
+ Log.d(TAG, "The callback " + user.mCallback
+ + " is set by " + getCallingPackageName(uid));
+ if (user.mCallback == null) {
+ return;
+ }
+ try {
+ user.mCallback.asBinder().linkToDeath(
+ new IBinder.DeathRecipient() {
+ @Override
+ public void binderDied() {
+ synchronized (mLock) {
+ user.mCallback = null;
+ }
+ }
+ }, 0);
+ user.pushAddressedPlayerChangedLocked();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to set callback", e);
+ user.mCallback = null;
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void setOnVolumeKeyLongPressListener(IOnVolumeKeyLongPressListener listener) {
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ // Enforce SET_VOLUME_KEY_LONG_PRESS_LISTENER permission.
+ if (mContext.checkPermission(
+ android.Manifest.permission.SET_VOLUME_KEY_LONG_PRESS_LISTENER, pid, uid)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Must hold the SET_VOLUME_KEY_LONG_PRESS_LISTENER"
+ + " permission.");
+ }
+
+ synchronized (mLock) {
+ int userId = UserHandle.getUserId(uid);
+ FullUserRecord user = getFullUserRecordLocked(userId);
+ if (user == null || user.mFullUserId != userId) {
+ Log.w(TAG, "Only the full user can set the volume key long-press listener"
+ + ", userId=" + userId);
+ return;
+ }
+ if (user.mOnVolumeKeyLongPressListener != null
+ && user.mOnVolumeKeyLongPressListenerUid != uid) {
+ Log.w(TAG, "The volume key long-press listener cannot be reset"
+ + " by another app , mOnVolumeKeyLongPressListener="
+ + user.mOnVolumeKeyLongPressListenerUid
+ + ", uid=" + uid);
+ return;
+ }
+
+ user.mOnVolumeKeyLongPressListener = listener;
+ user.mOnVolumeKeyLongPressListenerUid = uid;
+
+ Log.d(TAG, "The volume key long-press listener "
+ + listener + " is set by " + getCallingPackageName(uid));
+
+ if (user.mOnVolumeKeyLongPressListener != null) {
+ try {
+ user.mOnVolumeKeyLongPressListener.asBinder().linkToDeath(
+ new IBinder.DeathRecipient() {
+ @Override
+ public void binderDied() {
+ synchronized (mLock) {
+ user.mOnVolumeKeyLongPressListener = null;
+ }
+ }
+ }, 0);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to set death recipient "
+ + user.mOnVolumeKeyLongPressListener);
+ user.mOnVolumeKeyLongPressListener = null;
+ }
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void setOnMediaKeyListener(IOnMediaKeyListener listener) {
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ // Enforce SET_MEDIA_KEY_LISTENER permission.
+ if (mContext.checkPermission(
+ android.Manifest.permission.SET_MEDIA_KEY_LISTENER, pid, uid)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Must hold the SET_MEDIA_KEY_LISTENER permission.");
+ }
+
+ synchronized (mLock) {
+ int userId = UserHandle.getUserId(uid);
+ FullUserRecord user = getFullUserRecordLocked(userId);
+ if (user == null || user.mFullUserId != userId) {
+ Log.w(TAG, "Only the full user can set the media key listener"
+ + ", userId=" + userId);
+ return;
+ }
+ if (user.mOnMediaKeyListener != null && user.mOnMediaKeyListenerUid != uid) {
+ Log.w(TAG, "The media key listener cannot be reset by another app. "
+ + ", mOnMediaKeyListenerUid=" + user.mOnMediaKeyListenerUid
+ + ", uid=" + uid);
+ return;
+ }
+
+ user.mOnMediaKeyListener = listener;
+ user.mOnMediaKeyListenerUid = uid;
+
+ Log.d(TAG, "The media key listener " + user.mOnMediaKeyListener
+ + " is set by " + getCallingPackageName(uid));
+
+ if (user.mOnMediaKeyListener != null) {
+ try {
+ user.mOnMediaKeyListener.asBinder().linkToDeath(
+ new IBinder.DeathRecipient() {
+ @Override
+ public void binderDied() {
+ synchronized (mLock) {
+ user.mOnMediaKeyListener = null;
+ }
+ }
+ }, 0);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to set death recipient " + user.mOnMediaKeyListener);
+ user.mOnMediaKeyListener = null;
+ }
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ /**
+ * Handles the dispatching of the volume button events to one of the
+ * registered listeners. If there's a volume key long-press listener and
+ * there's no active global priority session, long-pressess will be sent to the
+ * long-press listener instead of adjusting volume.
+ *
+ * @param packageName The caller's package name, obtained by Context#getPackageName()
+ * @param opPackageName The caller's op package name, obtained by Context#getOpPackageName()
+ * @param asSystemService {@code true} if the event sent to the session as if it was come
+ * from the system service instead of the app process. This helps sessions to
+ * distinguish between the key injection by the app and key events from the
+ * hardware devices. Should be used only when the volume key events aren't handled
+ * by foreground activity. {@code false} otherwise to tell session about the real
+ * caller.
+ * @param keyEvent a non-null KeyEvent whose key code is one of the
+ * {@link KeyEvent#KEYCODE_VOLUME_UP},
+ * {@link KeyEvent#KEYCODE_VOLUME_DOWN},
+ * or {@link KeyEvent#KEYCODE_VOLUME_MUTE}.
+ * @param stream stream type to adjust volume.
+ * @param musicOnly true if both UI nor haptic feedback aren't needed when adjust volume.
+ */
+ @Override
+ public void dispatchVolumeKeyEvent(String packageName, String opPackageName,
+ boolean asSystemService, KeyEvent keyEvent, int stream, boolean musicOnly) {
+ if (keyEvent == null
+ || (keyEvent.getKeyCode() != KeyEvent.KEYCODE_VOLUME_UP
+ && keyEvent.getKeyCode() != KeyEvent.KEYCODE_VOLUME_DOWN
+ && keyEvent.getKeyCode() != KeyEvent.KEYCODE_VOLUME_MUTE)) {
+ Log.w(TAG, "Attempted to dispatch null or non-volume key event.");
+ return;
+ }
+
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+
+ if (DEBUG_KEY_EVENT) {
+ Log.d(TAG, "dispatchVolumeKeyEvent, pkg=" + packageName + ", pid=" + pid + ", uid="
+ + uid + ", asSystem=" + asSystemService + ", event=" + keyEvent);
+ }
+
+ try {
+ synchronized (mLock) {
+ if (isGlobalPriorityActiveLocked()
+ || mCurrentFullUserRecord.mOnVolumeKeyLongPressListener == null) {
+ dispatchVolumeKeyEventLocked(packageName, opPackageName, pid, uid,
+ asSystemService, keyEvent, stream, musicOnly);
+ } else {
+ // TODO: Consider the case when both volume up and down keys are pressed
+ // at the same time.
+ if (keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
+ if (keyEvent.getRepeatCount() == 0) {
+ // Keeps the copy of the KeyEvent because it can be reused.
+ mCurrentFullUserRecord.mInitialDownVolumeKeyEvent =
+ KeyEvent.obtain(keyEvent);
+ mCurrentFullUserRecord.mInitialDownVolumeStream = stream;
+ mCurrentFullUserRecord.mInitialDownMusicOnly = musicOnly;
+ mHandler.sendMessageDelayed(
+ mHandler.obtainMessage(
+ MessageHandler.MSG_VOLUME_INITIAL_DOWN,
+ mCurrentFullUserRecord.mFullUserId, 0),
+ mLongPressTimeout);
+ }
+ if (keyEvent.getRepeatCount() > 0 || keyEvent.isLongPress()) {
+ mHandler.removeMessages(MessageHandler.MSG_VOLUME_INITIAL_DOWN);
+ if (mCurrentFullUserRecord.mInitialDownVolumeKeyEvent != null) {
+ dispatchVolumeKeyLongPressLocked(
+ mCurrentFullUserRecord.mInitialDownVolumeKeyEvent);
+ // Mark that the key is already handled.
+ mCurrentFullUserRecord.mInitialDownVolumeKeyEvent = null;
+ }
+ dispatchVolumeKeyLongPressLocked(keyEvent);
+ }
+ } else { // if up
+ mHandler.removeMessages(MessageHandler.MSG_VOLUME_INITIAL_DOWN);
+ if (mCurrentFullUserRecord.mInitialDownVolumeKeyEvent != null
+ && mCurrentFullUserRecord.mInitialDownVolumeKeyEvent
+ .getDownTime() == keyEvent.getDownTime()) {
+ // Short-press. Should change volume.
+ dispatchVolumeKeyEventLocked(packageName, opPackageName, pid, uid,
+ asSystemService,
+ mCurrentFullUserRecord.mInitialDownVolumeKeyEvent,
+ mCurrentFullUserRecord.mInitialDownVolumeStream,
+ mCurrentFullUserRecord.mInitialDownMusicOnly);
+ dispatchVolumeKeyEventLocked(packageName, opPackageName, pid, uid,
+ asSystemService, keyEvent, stream, musicOnly);
+ } else {
+ dispatchVolumeKeyLongPressLocked(keyEvent);
+ }
+ }
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ private void dispatchVolumeKeyEventLocked(String packageName, String opPackageName, int pid,
+ int uid, boolean asSystemService, KeyEvent keyEvent, int stream,
+ boolean musicOnly) {
+ boolean down = keyEvent.getAction() == KeyEvent.ACTION_DOWN;
+ boolean up = keyEvent.getAction() == KeyEvent.ACTION_UP;
+ int direction = 0;
+ boolean isMute = false;
+ switch (keyEvent.getKeyCode()) {
+ case KeyEvent.KEYCODE_VOLUME_UP:
+ direction = AudioManager.ADJUST_RAISE;
+ break;
+ case KeyEvent.KEYCODE_VOLUME_DOWN:
+ direction = AudioManager.ADJUST_LOWER;
+ break;
+ case KeyEvent.KEYCODE_VOLUME_MUTE:
+ isMute = true;
+ break;
+ }
+ if (down || up) {
+ int flags = AudioManager.FLAG_FROM_KEY;
+ if (musicOnly) {
+ // This flag is used when the screen is off to only affect active media.
+ flags |= AudioManager.FLAG_ACTIVE_MEDIA_ONLY;
+ } else {
+ // These flags are consistent with the home screen
+ if (up) {
+ flags |= AudioManager.FLAG_PLAY_SOUND | AudioManager.FLAG_VIBRATE;
+ } else {
+ flags |= AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_VIBRATE;
+ }
+ }
+ if (direction != 0) {
+ // If this is action up we want to send a beep for non-music events
+ if (up) {
+ direction = 0;
+ }
+ dispatchAdjustVolumeLocked(packageName, opPackageName, pid, uid,
+ asSystemService, stream, direction, flags);
+ } else if (isMute) {
+ if (down && keyEvent.getRepeatCount() == 0) {
+ dispatchAdjustVolumeLocked(packageName, opPackageName, pid, uid,
+ asSystemService, stream, AudioManager.ADJUST_TOGGLE_MUTE, flags);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void dispatchAdjustVolume(String packageName, String opPackageName,
+ int suggestedStream, int delta, int flags) {
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ dispatchAdjustVolumeLocked(packageName, opPackageName, pid, uid, false,
+ suggestedStream, delta, flags);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void setRemoteVolumeController(IRemoteVolumeController rvc) {
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ enforceSystemUiPermission("listen for volume changes", pid, uid);
+ mRvc = rvc;
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public boolean isGlobalPriorityActive() {
+ synchronized (mLock) {
+ return isGlobalPriorityActiveLocked();
+ }
+ }
+
+ @Override
+ public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
+ if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+
+ pw.println("MEDIA SESSION SERVICE (dumpsys media_session)");
+ pw.println();
+
+ synchronized (mLock) {
+ pw.println(mSessionsListeners.size() + " sessions listeners.");
+ pw.println("Global priority session is " + mGlobalPrioritySession);
+ if (mGlobalPrioritySession != null) {
+ mGlobalPrioritySession.dump(pw, " ");
+ }
+ pw.println("User Records:");
+ int count = mUserRecords.size();
+ for (int i = 0; i < count; i++) {
+ mUserRecords.valueAt(i).dumpLocked(pw, "");
+ }
+ mAudioPlayerStateMonitor.dump(mContext, pw, "");
+ }
+ }
+
+ /**
+ * Returns if the controller's package is trusted (i.e. has either MEDIA_CONTENT_CONTROL
+ * permission or an enabled notification listener)
+ *
+ * @param controllerPackageName package name of the controller app
+ * @param controllerPid pid of the controller app
+ * @param controllerUid uid of the controller app
+ */
+ @Override
+ public boolean isTrusted(String controllerPackageName, int controllerPid, int controllerUid)
+ throws RemoteException {
+ final int uid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ // Don't perform sanity check between controllerPackageName and controllerUid.
+ // When an (activity|service) runs on the another apps process by specifying
+ // android:process in the AndroidManifest.xml, then PID and UID would have the
+ // running process' information instead of the (activity|service) that has created
+ // MediaController.
+ // Note that we can use Context#getOpPackageName() instead of
+ // Context#getPackageName() for getting package name that matches with the PID/UID,
+ // but it doesn't tell which package has created the MediaController, so useless.
+ return hasMediaControlPermission(UserHandle.getUserId(uid), controllerPackageName,
+ controllerPid, controllerUid);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ // For MediaSession
+ private int verifySessionsRequest(ComponentName componentName, int userId, final int pid,
+ final int uid) {
+ String packageName = null;
+ if (componentName != null) {
+ // If they gave us a component name verify they own the
+ // package
+ packageName = componentName.getPackageName();
+ enforcePackageName(packageName, uid);
+ }
+ // Check that they can make calls on behalf of the user and
+ // get the final user id
+ int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
+ true /* allowAll */, true /* requireFull */, "getSessions", packageName);
+ // Check if they have the permissions or their component is
+ // enabled for the user they're calling from.
+ enforceMediaPermissions(componentName, pid, uid, resolvedUserId);
+ return resolvedUserId;
+ }
+
+ private boolean hasMediaControlPermission(int resolvedUserId, String packageName,
+ int pid, int uid) throws RemoteException {
+ // Allow API calls from the System UI
+ if (isCurrentVolumeController(pid, uid)) {
+ return true;
+ }
+
+ // Check if it's system server or has MEDIA_CONTENT_CONTROL.
+ // Note that system server doesn't have MEDIA_CONTENT_CONTROL, so we need extra
+ // check here.
+ if (uid == Process.SYSTEM_UID || mContext.checkPermission(
+ android.Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid)
+ == PackageManager.PERMISSION_GRANTED) {
+ return true;
+ } else if (DEBUG) {
+ Log.d(TAG, packageName + " (uid=" + uid + ") hasn't granted MEDIA_CONTENT_CONTROL");
+ }
+
+ // You may not access another user's content as an enabled listener.
+ final int userId = UserHandle.getUserId(uid);
+ if (resolvedUserId != userId) {
+ return false;
+ }
+
+ // TODO(jaewan): (Post-P) Propose NotificationManager#hasEnabledNotificationListener(
+ // String pkgName) to notification team for optimization
+ final List<ComponentName> enabledNotificationListeners =
+ mNotificationManager.getEnabledNotificationListeners(userId);
+ if (enabledNotificationListeners != null) {
+ for (int i = 0; i < enabledNotificationListeners.size(); i++) {
+ if (TextUtils.equals(packageName,
+ enabledNotificationListeners.get(i).getPackageName())) {
+ return true;
+ }
+ }
+ }
+ if (DEBUG) {
+ Log.d(TAG, packageName + " (uid=" + uid + ") doesn't have an enabled "
+ + "notification listener");
+ }
+ return false;
+ }
+
+ private void dispatchAdjustVolumeLocked(String packageName, String opPackageName, int pid,
+ int uid, boolean asSystemService, int suggestedStream, int direction, int flags) {
+ MediaSessionRecord session = isGlobalPriorityActiveLocked() ? mGlobalPrioritySession
+ : mCurrentFullUserRecord.mPriorityStack.getDefaultVolumeSession();
+
+ boolean preferSuggestedStream = false;
+ if (isValidLocalStreamType(suggestedStream)
+ && AudioSystem.isStreamActive(suggestedStream, 0)) {
+ preferSuggestedStream = true;
+ }
+ if (DEBUG_KEY_EVENT) {
+ Log.d(TAG, "Adjusting " + session + " by " + direction + ". flags="
+ + flags + ", suggestedStream=" + suggestedStream
+ + ", preferSuggestedStream=" + preferSuggestedStream);
+ }
+ if (session == null || preferSuggestedStream) {
+ if ((flags & AudioManager.FLAG_ACTIVE_MEDIA_ONLY) != 0
+ && !AudioSystem.isStreamActive(AudioManager.STREAM_MUSIC, 0)) {
+ if (DEBUG) {
+ Log.d(TAG, "No active session to adjust, skipping media only volume event");
+ }
+ return;
+ }
+
+ // Execute mAudioService.adjustSuggestedStreamVolume() on
+ // handler thread of MediaSessionService.
+ // This will release the MediaSessionService.mLock sooner and avoid
+ // a potential deadlock between MediaSessionService.mLock and
+ // ActivityManagerService lock.
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ final String callingOpPackageName;
+ final int callingUid;
+ if (asSystemService) {
+ callingOpPackageName = mContext.getOpPackageName();
+ callingUid = Process.myUid();
+ } else {
+ callingOpPackageName = opPackageName;
+ callingUid = uid;
+ }
+ try {
+ mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(suggestedStream,
+ direction, flags, callingOpPackageName, callingUid);
+ } catch (SecurityException | IllegalArgumentException e) {
+ Log.e(TAG, "Cannot adjust volume: direction=" + direction
+ + ", suggestedStream=" + suggestedStream + ", flags=" + flags
+ + ", packageName=" + packageName + ", uid=" + uid
+ + ", asSystemService=" + asSystemService, e);
+ }
+ }
+ });
+ } else {
+ session.adjustVolume(packageName, opPackageName, pid, uid, null, asSystemService,
+ direction, flags, true);
+ }
+ }
+
+ private void handleVoiceKeyEventLocked(String packageName, int pid, int uid,
+ boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock) {
+ int action = keyEvent.getAction();
+ boolean isLongPress = (keyEvent.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0;
+ if (action == KeyEvent.ACTION_DOWN) {
+ if (keyEvent.getRepeatCount() == 0) {
+ mVoiceButtonDown = true;
+ mVoiceButtonHandled = false;
+ } else if (mVoiceButtonDown && !mVoiceButtonHandled && isLongPress) {
+ mVoiceButtonHandled = true;
+ startVoiceInput(needWakeLock);
+ }
+ } else if (action == KeyEvent.ACTION_UP) {
+ if (mVoiceButtonDown) {
+ mVoiceButtonDown = false;
+ if (!mVoiceButtonHandled && !keyEvent.isCanceled()) {
+ // Resend the down then send this event through
+ KeyEvent downEvent = KeyEvent.changeAction(keyEvent, KeyEvent.ACTION_DOWN);
+ dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService,
+ downEvent, needWakeLock);
+ dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService,
+ keyEvent, needWakeLock);
+ }
+ }
+ }
+ }
+
+ private void dispatchMediaKeyEventLocked(String packageName, int pid, int uid,
+ boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock) {
+ MediaSessionRecord session = mCurrentFullUserRecord.getMediaButtonSessionLocked();
+ if (session != null) {
+ if (DEBUG_KEY_EVENT) {
+ Log.d(TAG, "Sending " + keyEvent + " to " + session);
+ }
+ if (needWakeLock) {
+ mKeyEventReceiver.aquireWakeLockLocked();
+ }
+ // If we don't need a wakelock use -1 as the id so we won't release it later.
+ session.sendMediaButton(packageName, pid, uid, asSystemService, keyEvent,
+ needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
+ mKeyEventReceiver);
+ if (mCurrentFullUserRecord.mCallback != null) {
+ try {
+ mCurrentFullUserRecord.mCallback.onMediaKeyEventDispatchedToMediaSession(
+ keyEvent, new MediaSession.Token(session.getControllerBinder()));
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to send callback", e);
+ }
+ }
+ } else if (mCurrentFullUserRecord.mLastMediaButtonReceiver != null
+ || mCurrentFullUserRecord.mRestoredMediaButtonReceiver != null) {
+ if (needWakeLock) {
+ mKeyEventReceiver.aquireWakeLockLocked();
+ }
+ Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
+ mediaButtonIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
+ // TODO: Find a way to also send PID/UID in secure way.
+ String callerPackageName =
+ (asSystemService) ? mContext.getPackageName() : packageName;
+ mediaButtonIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, callerPackageName);
+ try {
+ if (mCurrentFullUserRecord.mLastMediaButtonReceiver != null) {
+ PendingIntent receiver = mCurrentFullUserRecord.mLastMediaButtonReceiver;
+ if (DEBUG_KEY_EVENT) {
+ Log.d(TAG, "Sending " + keyEvent
+ + " to the last known PendingIntent " + receiver);
+ }
+ receiver.send(mContext,
+ needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
+ mediaButtonIntent, mKeyEventReceiver, mHandler);
+ if (mCurrentFullUserRecord.mCallback != null) {
+ ComponentName componentName = mCurrentFullUserRecord
+ .mLastMediaButtonReceiver.getIntent().getComponent();
+ if (componentName != null) {
+ mCurrentFullUserRecord.mCallback
+ .onMediaKeyEventDispatchedToMediaButtonReceiver(
+ keyEvent, componentName);
+ }
+ }
+ } else {
+ ComponentName receiver =
+ mCurrentFullUserRecord.mRestoredMediaButtonReceiver;
+ int componentType = mCurrentFullUserRecord
+ .mRestoredMediaButtonReceiverComponentType;
+ UserHandle userHandle = UserHandle.of(mCurrentFullUserRecord
+ .mRestoredMediaButtonReceiverUserId);
+ if (DEBUG_KEY_EVENT) {
+ Log.d(TAG, "Sending " + keyEvent + " to the restored intent "
+ + receiver + ", type=" + componentType);
+ }
+ mediaButtonIntent.setComponent(receiver);
+ try {
+ switch (componentType) {
+ case FullUserRecord.COMPONENT_TYPE_ACTIVITY:
+ mContext.startActivityAsUser(mediaButtonIntent, userHandle);
+ break;
+ case FullUserRecord.COMPONENT_TYPE_SERVICE:
+ mContext.startForegroundServiceAsUser(mediaButtonIntent,
+ userHandle);
+ break;
+ default:
+ // Legacy behavior for other cases.
+ mContext.sendBroadcastAsUser(mediaButtonIntent, userHandle);
+ }
+ } catch (Exception e) {
+ Log.w(TAG, "Error sending media button to the restored intent "
+ + receiver + ", type=" + componentType, e);
+ }
+ if (mCurrentFullUserRecord.mCallback != null) {
+ mCurrentFullUserRecord.mCallback
+ .onMediaKeyEventDispatchedToMediaButtonReceiver(
+ keyEvent, receiver);
+ }
+ }
+ } catch (CanceledException e) {
+ Log.i(TAG, "Error sending key event to media button receiver "
+ + mCurrentFullUserRecord.mLastMediaButtonReceiver, e);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to send callback", e);
+ }
+ }
+ }
+
+ private void startVoiceInput(boolean needWakeLock) {
+ Intent voiceIntent = null;
+ // select which type of search to launch:
+ // - screen on and device unlocked: action is ACTION_WEB_SEARCH
+ // - device locked or screen off: action is
+ // ACTION_VOICE_SEARCH_HANDS_FREE
+ // with EXTRA_SECURE set to true if the device is securely locked
+ PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+ boolean isLocked = mKeyguardManager != null && mKeyguardManager.isKeyguardLocked();
+ if (!isLocked && pm.isScreenOn()) {
+ voiceIntent = new Intent(android.speech.RecognizerIntent.ACTION_WEB_SEARCH);
+ Log.i(TAG, "voice-based interactions: about to use ACTION_WEB_SEARCH");
+ } else {
+ voiceIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
+ voiceIntent.putExtra(RecognizerIntent.EXTRA_SECURE,
+ isLocked && mKeyguardManager.isKeyguardSecure());
+ Log.i(TAG, "voice-based interactions: about to use ACTION_VOICE_SEARCH_HANDS_FREE");
+ }
+ // start the search activity
+ if (needWakeLock) {
+ mMediaEventWakeLock.acquire();
+ }
+ try {
+ if (voiceIntent != null) {
+ voiceIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ if (DEBUG) Log.d(TAG, "voiceIntent: " + voiceIntent);
+ mContext.startActivityAsUser(voiceIntent, UserHandle.CURRENT);
+ }
+ } catch (ActivityNotFoundException e) {
+ Log.w(TAG, "No activity for search: " + e);
+ } finally {
+ if (needWakeLock) {
+ mMediaEventWakeLock.release();
+ }
+ }
+ }
+
+ private boolean isVoiceKey(int keyCode) {
+ return keyCode == KeyEvent.KEYCODE_HEADSETHOOK
+ || (!mHasFeatureLeanback && keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
+ }
+
+ private boolean isUserSetupComplete() {
+ return Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
+ }
+
+ // we only handle public stream types, which are 0-5
+ private boolean isValidLocalStreamType(int streamType) {
+ return streamType >= AudioManager.STREAM_VOICE_CALL
+ && streamType <= AudioManager.STREAM_NOTIFICATION;
+ }
+
+ private class MediaKeyListenerResultReceiver extends ResultReceiver implements Runnable {
+ private final String mPackageName;
+ private final int mPid;
+ private final int mUid;
+ private final boolean mAsSystemService;
+ private final KeyEvent mKeyEvent;
+ private final boolean mNeedWakeLock;
+ private boolean mHandled;
+
+ private MediaKeyListenerResultReceiver(String packageName, int pid, int uid,
+ boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock) {
+ super(mHandler);
+ mHandler.postDelayed(this, MEDIA_KEY_LISTENER_TIMEOUT);
+ mPackageName = packageName;
+ mPid = pid;
+ mUid = uid;
+ mAsSystemService = asSystemService;
+ mKeyEvent = keyEvent;
+ mNeedWakeLock = needWakeLock;
+ }
+
+ @Override
+ public void run() {
+ Log.d(TAG, "The media key listener is timed-out for " + mKeyEvent);
+ dispatchMediaKeyEvent();
+ }
+
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ if (resultCode == MediaSessionManager.RESULT_MEDIA_KEY_HANDLED) {
+ mHandled = true;
+ mHandler.removeCallbacks(this);
+ return;
+ }
+ dispatchMediaKeyEvent();
+ }
+
+ private void dispatchMediaKeyEvent() {
+ if (mHandled) {
+ return;
+ }
+ mHandled = true;
+ mHandler.removeCallbacks(this);
+ synchronized (mLock) {
+ if (!isGlobalPriorityActiveLocked()
+ && isVoiceKey(mKeyEvent.getKeyCode())) {
+ handleVoiceKeyEventLocked(mPackageName, mPid, mUid, mAsSystemService,
+ mKeyEvent, mNeedWakeLock);
+ } else {
+ dispatchMediaKeyEventLocked(mPackageName, mPid, mUid, mAsSystemService,
+ mKeyEvent, mNeedWakeLock);
+ }
+ }
+ }
+ }
+
+ private KeyEventWakeLockReceiver mKeyEventReceiver = new KeyEventWakeLockReceiver(mHandler);
+
+ class KeyEventWakeLockReceiver extends ResultReceiver implements Runnable,
+ PendingIntent.OnFinished {
+ private final Handler mHandler;
+ private int mRefCount = 0;
+ private int mLastTimeoutId = 0;
+
+ KeyEventWakeLockReceiver(Handler handler) {
+ super(handler);
+ mHandler = handler;
+ }
+
+ public void onTimeout() {
+ synchronized (mLock) {
+ if (mRefCount == 0) {
+ // We've already released it, so just return
+ return;
+ }
+ mLastTimeoutId++;
+ mRefCount = 0;
+ releaseWakeLockLocked();
+ }
+ }
+
+ public void aquireWakeLockLocked() {
+ if (mRefCount == 0) {
+ mMediaEventWakeLock.acquire();
+ }
+ mRefCount++;
+ mHandler.removeCallbacks(this);
+ mHandler.postDelayed(this, WAKELOCK_TIMEOUT);
+
+ }
+
+ @Override
+ public void run() {
+ onTimeout();
+ }
+
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ if (resultCode < mLastTimeoutId) {
+ // Ignore results from calls that were before the last
+ // timeout, just in case.
+ return;
+ } else {
+ synchronized (mLock) {
+ if (mRefCount > 0) {
+ mRefCount--;
+ if (mRefCount == 0) {
+ releaseWakeLockLocked();
+ }
+ }
+ }
+ }
+ }
+
+ private void releaseWakeLockLocked() {
+ mMediaEventWakeLock.release();
+ mHandler.removeCallbacks(this);
+ }
+
+ @Override
+ public void onSendFinished(PendingIntent pendingIntent, Intent intent, int resultCode,
+ String resultData, Bundle resultExtras) {
+ onReceiveResult(resultCode, null);
+ }
+ };
+
+ BroadcastReceiver mKeyEventDone = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent == null) {
+ return;
+ }
+ Bundle extras = intent.getExtras();
+ if (extras == null) {
+ return;
+ }
+ synchronized (mLock) {
+ if (extras.containsKey(EXTRA_WAKELOCK_ACQUIRED)
+ && mMediaEventWakeLock.isHeld()) {
+ mMediaEventWakeLock.release();
+ }
+ }
+ }
+ };
+ }
+
+ final class MessageHandler extends Handler {
+ private static final int MSG_SESSIONS_CHANGED = 1;
+ private static final int MSG_VOLUME_INITIAL_DOWN = 2;
+ private final SparseArray<Integer> mIntegerCache = new SparseArray<>();
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_SESSIONS_CHANGED:
+ pushSessionsChanged((int) msg.obj);
+ break;
+ case MSG_VOLUME_INITIAL_DOWN:
+ synchronized (mLock) {
+ FullUserRecord user = mUserRecords.get((int) msg.arg1);
+ if (user != null && user.mInitialDownVolumeKeyEvent != null) {
+ dispatchVolumeKeyLongPressLocked(user.mInitialDownVolumeKeyEvent);
+ // Mark that the key is already handled.
+ user.mInitialDownVolumeKeyEvent = null;
+ }
+ }
+ break;
+ }
+ }
+
+ public void postSessionsChanged(int userId) {
+ // Use object instead of the arguments when posting message to remove pending requests.
+ Integer userIdInteger = mIntegerCache.get(userId);
+ if (userIdInteger == null) {
+ userIdInteger = Integer.valueOf(userId);
+ mIntegerCache.put(userId, userIdInteger);
+ }
+ removeMessages(MSG_SESSIONS_CHANGED, userIdInteger);
+ obtainMessage(MSG_SESSIONS_CHANGED, userIdInteger).sendToTarget();
+ }
+ }
+
+ private class Controller2Callback extends MediaController2.ControllerCallback {
+ private final Session2Token mToken;
+
+ Controller2Callback(Session2Token token) {
+ mToken = token;
+ }
+
+ @Override
+ public void onConnected(MediaController2 controller, Session2CommandGroup allowedCommands) {
+ synchronized (mLock) {
+ int userId = UserHandle.getUserId(mToken.getUid());
+ mSession2TokensPerUser.get(userId).add(mToken);
+ pushSession2TokensChangedLocked(userId);
+ }
+ }
+
+ @Override
+ public void onDisconnected(MediaController2 controller) {
+ synchronized (mLock) {
+ int userId = UserHandle.getUserId(mToken.getUid());
+ mSession2TokensPerUser.get(userId).remove(mToken);
+ pushSession2TokensChangedLocked(userId);
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/media/RemoteDisplayProviderWatcher.java b/services/core/java/com/android/server/media/RemoteDisplayProviderWatcher.java
index 6a5f563..64c451d 100644
--- a/services/core/java/com/android/server/media/RemoteDisplayProviderWatcher.java
+++ b/services/core/java/com/android/server/media/RemoteDisplayProviderWatcher.java
@@ -159,12 +159,13 @@
+ serviceInfo.packageName + "/" + serviceInfo.name);
return false;
}
- if (!hasCaptureVideoPermission(serviceInfo.packageName)) {
- // If the service does not have permission to capture video then it
- // isn't going to be terribly useful as a remote display, is it?
- // Kind of makes you wonder what it's doing there in the first place.
+ if (mPackageManager.checkPermission(Manifest.permission.REMOTE_DISPLAY_PROVIDER,
+ serviceInfo.packageName) != PackageManager.PERMISSION_GRANTED) {
+ // If the service does not have this permission then the system will not bind to it.
+ // This is to prevent non privileged apps declaring themselves as remote display
+ // providers just to be bound to by the system and keep their process alive.
Slog.w(TAG, "Ignoring remote display provider service because it does not "
- + "have the CAPTURE_VIDEO_OUTPUT or CAPTURE_SECURE_VIDEO_OUTPUT "
+ + "have the REMOTE_DISPLAY_PROVIDER "
+ "permission: " + serviceInfo.packageName + "/" + serviceInfo.name);
return false;
}
@@ -172,18 +173,6 @@
return true;
}
- private boolean hasCaptureVideoPermission(String packageName) {
- if (mPackageManager.checkPermission(Manifest.permission.CAPTURE_VIDEO_OUTPUT,
- packageName) == PackageManager.PERMISSION_GRANTED) {
- return true;
- }
- if (mPackageManager.checkPermission(Manifest.permission.CAPTURE_SECURE_VIDEO_OUTPUT,
- packageName) == PackageManager.PERMISSION_GRANTED) {
- return true;
- }
- return false;
- }
-
private int findProvider(String packageName, String className) {
int count = mProviders.size();
for (int i = 0; i < count; i++) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 20eebe7..7323e93 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2311,22 +2311,22 @@
}
@Override
- public boolean areAppOverlaysAllowed(String pkg) {
- return areAppOverlaysAllowedForPackage(pkg, Binder.getCallingUid());
+ public boolean areBubblesAllowed(String pkg) {
+ return areBubblesAllowedForPackage(pkg, Binder.getCallingUid());
}
@Override
- public boolean areAppOverlaysAllowedForPackage(String pkg, int uid) {
- enforceSystemOrSystemUIOrSamePackage("Caller not system or systemui or same package",
- pkg);
- return mPreferencesHelper.areAppOverlaysAllowed(pkg, uid);
+ public boolean areBubblesAllowedForPackage(String pkg, int uid) {
+ enforceSystemOrSystemUIOrSamePackage(pkg,
+ "Caller not system or systemui or same package");
+ return mPreferencesHelper.areBubblessAllowed(pkg, uid);
}
@Override
- public void setAppOverlaysAllowed(String pkg, int uid, boolean allowed) {
+ public void setBubblesAllowed(String pkg, int uid, boolean allowed) {
checkCallerIsSystem();
- mPreferencesHelper.setAppOverlaysAllowed(pkg, uid, allowed);
+ mPreferencesHelper.setBubblesAllowed(pkg, uid, allowed);
handleSavePolicyFile();
}
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 28f6972..7a21aa2 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -81,7 +81,7 @@
private static final String ATT_NAME = "name";
private static final String ATT_UID = "uid";
private static final String ATT_ID = "id";
- private static final String ATT_APP_OVERLAY = "overlay";
+ private static final String ATT_ALLOW_BUBBLE = "allow_bubble";
private static final String ATT_PRIORITY = "priority";
private static final String ATT_VISIBILITY = "visibility";
private static final String ATT_IMPORTANCE = "importance";
@@ -94,8 +94,9 @@
private static final int DEFAULT_VISIBILITY = NotificationManager.VISIBILITY_NO_OVERRIDE;
private static final int DEFAULT_IMPORTANCE = NotificationManager.IMPORTANCE_UNSPECIFIED;
private static final boolean DEFAULT_SHOW_BADGE = true;
- private static final boolean DEFAULT_ALLOW_APP_OVERLAY = true;
+ private static final boolean DEFAULT_ALLOW_BUBBLE = true;
private static final boolean DEFAULT_OEM_LOCKED_IMPORTANCE = false;
+
/**
* Default value for what fields are user locked. See {@link LockableAppFields} for all lockable
* fields.
@@ -108,7 +109,7 @@
@IntDef({LockableAppFields.USER_LOCKED_IMPORTANCE})
public @interface LockableAppFields {
int USER_LOCKED_IMPORTANCE = 0x00000001;
- int USER_LOCKED_APP_OVERLAY = 0x00000002;
+ int USER_LOCKED_BUBBLE = 0x00000002;
}
// pkg|uid => PackagePreferences
@@ -176,7 +177,7 @@
XmlUtils.readBooleanAttribute(
parser, ATT_SHOW_BADGE, DEFAULT_SHOW_BADGE),
XmlUtils.readBooleanAttribute(
- parser, ATT_APP_OVERLAY, DEFAULT_ALLOW_APP_OVERLAY));
+ parser, ATT_ALLOW_BUBBLE, DEFAULT_ALLOW_BUBBLE));
r.importance = XmlUtils.readIntAttribute(
parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE);
r.priority = XmlUtils.readIntAttribute(
@@ -272,11 +273,11 @@
private PackagePreferences getOrCreatePackagePreferences(String pkg, int uid) {
return getOrCreatePackagePreferences(pkg, uid,
DEFAULT_IMPORTANCE, DEFAULT_PRIORITY, DEFAULT_VISIBILITY, DEFAULT_SHOW_BADGE,
- DEFAULT_ALLOW_APP_OVERLAY);
+ DEFAULT_ALLOW_BUBBLE);
}
private PackagePreferences getOrCreatePackagePreferences(String pkg, int uid, int importance,
- int priority, int visibility, boolean showBadge, boolean allowAppOverlay) {
+ int priority, int visibility, boolean showBadge, boolean allowBubble) {
final String key = packagePreferencesKey(pkg, uid);
synchronized (mPackagePreferences) {
PackagePreferences
@@ -290,7 +291,7 @@
r.priority = priority;
r.visibility = visibility;
r.showBadge = showBadge;
- r.appOverlay = allowAppOverlay;
+ r.allowBubble = allowBubble;
try {
createDefaultChannelIfNeeded(r);
@@ -392,7 +393,7 @@
|| r.channels.size() > 0
|| r.groups.size() > 0
|| r.delegate != null
- || r.appOverlay != DEFAULT_ALLOW_APP_OVERLAY;
+ || r.allowBubble != DEFAULT_ALLOW_BUBBLE;
if (hasNonDefaultSettings) {
out.startTag(null, TAG_PACKAGE);
out.attribute(null, ATT_NAME, r.pkg);
@@ -405,8 +406,8 @@
if (r.visibility != DEFAULT_VISIBILITY) {
out.attribute(null, ATT_VISIBILITY, Integer.toString(r.visibility));
}
- if (r.appOverlay != DEFAULT_ALLOW_APP_OVERLAY) {
- out.attribute(null, ATT_APP_OVERLAY, Boolean.toString(r.appOverlay));
+ if (r.allowBubble != DEFAULT_ALLOW_BUBBLE) {
+ out.attribute(null, ATT_ALLOW_BUBBLE, Boolean.toString(r.allowBubble));
}
out.attribute(null, ATT_SHOW_BADGE, Boolean.toString(r.showBadge));
out.attribute(null, ATT_APP_USER_LOCKED_FIELDS,
@@ -452,14 +453,28 @@
out.endTag(null, TAG_RANKING);
}
- public void setAppOverlaysAllowed(String pkg, int uid, boolean allowed) {
+ /**
+ * Sets whether bubbles are allowed.
+ *
+ * @param pkg the package to allow or not allow bubbles for.
+ * @param uid the uid to allow or not allow bubbles for.
+ * @param allowed whether bubbles are allowed.
+ */
+ public void setBubblesAllowed(String pkg, int uid, boolean allowed) {
PackagePreferences p = getOrCreatePackagePreferences(pkg, uid);
- p.appOverlay = allowed;
- p.lockedAppFields = p.lockedAppFields | LockableAppFields.USER_LOCKED_APP_OVERLAY;
+ p.allowBubble = allowed;
+ p.lockedAppFields = p.lockedAppFields | LockableAppFields.USER_LOCKED_BUBBLE;
}
- public boolean areAppOverlaysAllowed(String pkg, int uid) {
- return getOrCreatePackagePreferences(pkg, uid).appOverlay;
+ /**
+ * Whether bubbles are allowed.
+ *
+ * @param pkg the package to check if bubbles are allowed for
+ * @param uid the uid to check if bubbles are allowed for.
+ * @return whether bubbles are allowed.
+ */
+ public boolean areBubblessAllowed(String pkg, int uid) {
+ return getOrCreatePackagePreferences(pkg, uid).allowBubble;
}
public int getAppLockedFields(String pkg, int uid) {
@@ -1232,8 +1247,8 @@
if (original.canShowBadge() != update.canShowBadge()) {
update.lockFields(NotificationChannel.USER_LOCKED_SHOW_BADGE);
}
- if (original.isAppOverlayAllowed() != update.isAppOverlayAllowed()) {
- update.lockFields(NotificationChannel.USER_LOCKED_ALLOW_APP_OVERLAY);
+ if (original.isBubbleAllowed() != update.isBubbleAllowed()) {
+ update.lockFields(NotificationChannel.USER_LOCKED_ALLOW_BUBBLE);
}
}
@@ -1654,7 +1669,7 @@
int priority = DEFAULT_PRIORITY;
int visibility = DEFAULT_VISIBILITY;
boolean showBadge = DEFAULT_SHOW_BADGE;
- boolean appOverlay = DEFAULT_ALLOW_APP_OVERLAY;
+ boolean allowBubble = DEFAULT_ALLOW_BUBBLE;
int lockedAppFields = DEFAULT_LOCKED_APP_FIELDS;
boolean oemLockedImportance = DEFAULT_OEM_LOCKED_IMPORTANCE;
List<String> futureOemLockedChannels = new ArrayList<>();
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 945d7ad..6baf12c 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -239,6 +239,7 @@
import android.os.storage.StorageManagerInternal;
import android.os.storage.VolumeInfo;
import android.os.storage.VolumeRecord;
+import android.permission.PermissionControllerManager;
import android.provider.MediaStore;
import android.provider.Settings.Global;
import android.provider.Settings.Secure;
@@ -317,7 +318,6 @@
import com.android.server.pm.permission.PermissionManagerInternal.PermissionCallback;
import com.android.server.pm.permission.PermissionManagerService;
import com.android.server.pm.permission.PermissionsState;
-import com.android.server.pm.permission.PermissionsState.PermissionState;
import com.android.server.security.VerityUtils;
import com.android.server.storage.DeviceStorageMonitorInternal;
import com.android.server.wm.ActivityTaskManagerInternal;
@@ -370,6 +370,7 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -443,6 +444,8 @@
private static final boolean ENABLE_FREE_CACHE_V2 =
SystemProperties.getBoolean("fw.free_cache_v2", true);
+ private static final long BACKUP_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(60);
+
private static final int RADIO_UID = Process.PHONE_UID;
private static final int LOG_UID = Process.LOG_UID;
private static final int NFC_UID = Process.NFC_UID;
@@ -19573,28 +19576,32 @@
throw new SecurityException("Only the system may call getPermissionGrantBackup()");
}
- ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
- try {
- final XmlSerializer serializer = new FastXmlSerializer();
- serializer.setOutput(dataStream, StandardCharsets.UTF_8.name());
- serializer.startDocument(null, true);
- serializer.startTag(null, TAG_PERMISSION_BACKUP);
+ AtomicReference<byte[]> backup = new AtomicReference<>();
+ mContext.getSystemService(PermissionControllerManager.class).getRuntimePermissionBackup(
+ UserHandle.of(userId), mContext.getMainExecutor(), (b) -> {
+ synchronized (backup) {
+ backup.set(b);
+ backup.notifyAll();
+ }
+ });
- synchronized (mPackages) {
- serializeRuntimePermissionGrantsLPr(serializer, userId);
- }
+ long start = System.currentTimeMillis();
+ synchronized (backup) {
+ while (backup.get() == null) {
+ long timeLeft = start + BACKUP_TIMEOUT_MILLIS - System.currentTimeMillis();
+ if (timeLeft <= 0) {
+ return null;
+ }
- serializer.endTag(null, TAG_PERMISSION_BACKUP);
- serializer.endDocument();
- serializer.flush();
- } catch (Exception e) {
- if (DEBUG_BACKUP) {
- Slog.e(TAG, "Unable to write default apps for backup", e);
+ try {
+ backup.wait(timeLeft);
+ } catch (InterruptedException ignored) {
+ return null;
+ }
}
- return null;
}
- return dataStream.toByteArray();
+ return backup.get();
}
@Override
@@ -19620,66 +19627,6 @@
}
@GuardedBy("mPackages")
- private void serializeRuntimePermissionGrantsLPr(XmlSerializer serializer, final int userId)
- throws IOException {
- serializer.startTag(null, TAG_ALL_GRANTS);
-
- final int N = mSettings.mPackages.size();
- for (int i = 0; i < N; i++) {
- final PackageSetting ps = mSettings.mPackages.valueAt(i);
- boolean pkgGrantsKnown = false;
-
- PermissionsState packagePerms = ps.getPermissionsState();
-
- for (PermissionState state : packagePerms.getRuntimePermissionStates(userId)) {
- final int grantFlags = state.getFlags();
- // only look at grants that are not system/policy fixed
- if ((grantFlags & SYSTEM_RUNTIME_GRANT_MASK) == 0) {
- final boolean isGranted = state.isGranted();
- // And only back up the user-twiddled state bits
- if (isGranted || (grantFlags & USER_RUNTIME_GRANT_MASK) != 0) {
- final String packageName = mSettings.mPackages.keyAt(i);
- if (!pkgGrantsKnown) {
- serializer.startTag(null, TAG_GRANT);
- serializer.attribute(null, ATTR_PACKAGE_NAME, packageName);
- pkgGrantsKnown = true;
- }
-
- final boolean userSet =
- (grantFlags & FLAG_PERMISSION_USER_SET) != 0;
- final boolean userFixed =
- (grantFlags & FLAG_PERMISSION_USER_FIXED) != 0;
- final boolean revoke =
- (grantFlags & FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0;
-
- serializer.startTag(null, TAG_PERMISSION);
- serializer.attribute(null, ATTR_PERMISSION_NAME, state.getName());
- if (isGranted) {
- serializer.attribute(null, ATTR_IS_GRANTED, "true");
- }
- if (userSet) {
- serializer.attribute(null, ATTR_USER_SET, "true");
- }
- if (userFixed) {
- serializer.attribute(null, ATTR_USER_FIXED, "true");
- }
- if (revoke) {
- serializer.attribute(null, ATTR_REVOKE_ON_UPGRADE, "true");
- }
- serializer.endTag(null, TAG_PERMISSION);
- }
- }
- }
-
- if (pkgGrantsKnown) {
- serializer.endTag(null, TAG_GRANT);
- }
- }
-
- serializer.endTag(null, TAG_ALL_GRANTS);
- }
-
- @GuardedBy("mPackages")
private void processRestoredPermissionGrantsLPr(XmlPullParser parser, int userId)
throws XmlPullParserException, IOException {
String pkgName = null;
@@ -23191,6 +23138,11 @@
}
@Override
+ public void setLocationExtraPackagesProvider(PackagesProvider provider) {
+ mDefaultPermissionPolicy.setLocationExtraPackagesProvider(provider);
+ }
+
+ @Override
public void setVoiceInteractionPackagesProvider(PackagesProvider provider) {
mDefaultPermissionPolicy.setVoiceInteractionPackagesProvider(provider);
}
diff --git a/services/core/java/com/android/server/pm/dex/DexLogger.java b/services/core/java/com/android/server/pm/dex/DexLogger.java
index 68a755b..78fa82c 100644
--- a/services/core/java/com/android/server/pm/dex/DexLogger.java
+++ b/services/core/java/com/android/server/pm/dex/DexLogger.java
@@ -28,7 +28,6 @@
import android.util.Slog;
import android.util.SparseArray;
-import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.pm.Installer;
import com.android.server.pm.Installer.InstallerException;
@@ -53,21 +52,18 @@
private final IPackageManager mPackageManager;
private final PackageDynamicCodeLoading mPackageDynamicCodeLoading;
- private final Object mInstallLock;
- @GuardedBy("mInstallLock")
private final Installer mInstaller;
- public DexLogger(IPackageManager pms, Installer installer, Object installLock) {
- this(pms, installer, installLock, new PackageDynamicCodeLoading());
+ public DexLogger(IPackageManager pms, Installer installer) {
+ this(pms, installer, new PackageDynamicCodeLoading());
}
@VisibleForTesting
- DexLogger(IPackageManager pms, Installer installer, Object installLock,
+ DexLogger(IPackageManager pms, Installer installer,
PackageDynamicCodeLoading packageDynamicCodeLoading) {
mPackageManager = pms;
mPackageDynamicCodeLoading = packageDynamicCodeLoading;
mInstaller = installer;
- mInstallLock = installLock;
}
public Set<String> getAllPackagesWithDynamicCodeLoading() {
@@ -131,14 +127,16 @@
}
byte[] hash = null;
- synchronized (mInstallLock) {
- try {
- hash = mInstaller.hashSecondaryDexFile(filePath, packageName, appInfo.uid,
- appInfo.volumeUuid, storageFlags);
- } catch (InstallerException e) {
- Slog.e(TAG, "Got InstallerException when hashing file " + filePath
- + ": " + e.getMessage());
- }
+ try {
+ // Note that we do not take the install lock here. Hashing should never interfere
+ // with app update/compilation/removal. We may get anomalous results if a file
+ // changes while we hash it, but that can happen anyway and is harmless for our
+ // purposes.
+ hash = mInstaller.hashSecondaryDexFile(filePath, packageName, appInfo.uid,
+ appInfo.volumeUuid, storageFlags);
+ } catch (InstallerException e) {
+ Slog.e(TAG, "Got InstallerException when hashing file " + filePath
+ + ": " + e.getMessage());
}
String fileName = new File(filePath).getName();
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index e57d9d7..b546836 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -129,7 +129,7 @@
mPackageDexOptimizer = pdo;
mInstaller = installer;
mInstallLock = installLock;
- mDexLogger = new DexLogger(pms, installer, installLock);
+ mDexLogger = new DexLogger(pms, installer);
}
public DexLogger getDexLogger() {
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 789664d..ceaf69d 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -225,6 +225,7 @@
private final Handler mHandler;
private PackagesProvider mLocationPackagesProvider;
+ private PackagesProvider mLocationExtraPackagesProvider;
private PackagesProvider mVoiceInteractionPackagesProvider;
private PackagesProvider mSmsAppPackagesProvider;
private PackagesProvider mDialerAppPackagesProvider;
@@ -270,6 +271,13 @@
}
}
+ /** Sets the provider for loction extra packages. */
+ public void setLocationExtraPackagesProvider(PackagesProvider provider) {
+ synchronized (mLock) {
+ mLocationExtraPackagesProvider = provider;
+ }
+ }
+
public void setVoiceInteractionPackagesProvider(PackagesProvider provider) {
synchronized (mLock) {
mVoiceInteractionPackagesProvider = provider;
@@ -403,6 +411,7 @@
Log.i(TAG, "Granting permissions to default platform handlers for user " + userId);
final PackagesProvider locationPackagesProvider;
+ final PackagesProvider locationExtraPackagesProvider;
final PackagesProvider voiceInteractionPackagesProvider;
final PackagesProvider smsAppPackagesProvider;
final PackagesProvider dialerAppPackagesProvider;
@@ -412,6 +421,7 @@
synchronized (mLock) {
locationPackagesProvider = mLocationPackagesProvider;
+ locationExtraPackagesProvider = mLocationExtraPackagesProvider;
voiceInteractionPackagesProvider = mVoiceInteractionPackagesProvider;
smsAppPackagesProvider = mSmsAppPackagesProvider;
dialerAppPackagesProvider = mDialerAppPackagesProvider;
@@ -424,6 +434,8 @@
? voiceInteractionPackagesProvider.getPackages(userId) : null;
String[] locationPackageNames = (locationPackagesProvider != null)
? locationPackagesProvider.getPackages(userId) : null;
+ String[] locationExtraPackageNames = (locationExtraPackagesProvider != null)
+ ? locationExtraPackagesProvider.getPackages(userId) : null;
String[] smsAppPackageNames = (smsAppPackagesProvider != null)
? smsAppPackagesProvider.getPackages(userId) : null;
String[] dialerAppPackageNames = (dialerAppPackagesProvider != null)
@@ -638,6 +650,12 @@
LOCATION_PERMISSIONS, ACTIVITY_RECOGNITION_PERMISSIONS);
}
}
+ if (locationExtraPackageNames != null) {
+ // Also grant location permission to location extra packages.
+ for (String packageName : locationExtraPackageNames) {
+ grantPermissionsToSystemPackage(packageName, userId, LOCATION_PERMISSIONS);
+ }
+ }
// Music
Intent musicIntent = new Intent(Intent.ACTION_VIEW)
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 2060aef..4bc2416 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -84,8 +84,10 @@
import static android.view.WindowManagerGlobal.ADD_PERMISSION_DENIED;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVERED;
-import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVER_ABSENT;
-import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_UNCOVERED;
+import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs
+ .CAMERA_LENS_COVER_ABSENT;
+import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs
+ .CAMERA_LENS_UNCOVERED;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_CLOSED;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN;
import static com.android.server.wm.WindowManagerPolicyProto.KEYGUARD_DELEGATE;
@@ -808,6 +810,13 @@
}
};
+ private Runnable mPossibleVeryLongPressReboot = new Runnable() {
+ @Override
+ public void run() {
+ mActivityManagerInternal.prepareForPossibleShutdown();
+ }
+ };
+
private void handleRingerChordGesture() {
if (mRingerToggleChord == VOLUME_HUSH_OFF) {
return;
@@ -953,6 +962,8 @@
// Inform the StatusBar; but do not allow it to consume the event.
sendSystemKeyToStatusBarAsync(event.getKeyCode());
+ schedulePossibleVeryLongPressReboot();
+
// If the power key has still not yet been handled, then detect short
// press, long press, or multi press and decide what to do.
mPowerKeyHandled = hungUp || mScreenshotChordVolumeDownKeyTriggered
@@ -1056,6 +1067,7 @@
if (hasVeryLongPressOnPowerBehavior()) {
mHandler.removeMessages(MSG_POWER_VERY_LONG_PRESS);
}
+ cancelPossibleVeryLongPressReboot();
}
private void cancelPendingBackKeyAction() {
@@ -4901,6 +4913,15 @@
}
}
+ private void schedulePossibleVeryLongPressReboot() {
+ mHandler.removeCallbacks(mPossibleVeryLongPressReboot);
+ mHandler.postDelayed(mPossibleVeryLongPressReboot, mVeryLongPressTimeout);
+ }
+
+ private void cancelPossibleVeryLongPressReboot() {
+ mHandler.removeCallbacks(mPossibleVeryLongPressReboot);
+ }
+
// TODO (multidisplay): Support multiple displays in WindowManagerPolicy.
private void updateScreenOffSleepToken(boolean acquire) {
if (acquire) {
diff --git a/services/core/java/com/android/server/role/RoleUserState.java b/services/core/java/com/android/server/role/RoleUserState.java
index 69e1449..02dcc49 100644
--- a/services/core/java/com/android/server/role/RoleUserState.java
+++ b/services/core/java/com/android/server/role/RoleUserState.java
@@ -193,14 +193,18 @@
*
* @param roleName the name of the role to query for
*
- * @return the set of role holders. {@code null} should not be returned and indicates an issue.
+ * @return the set of role holders, or {@code null} if and only if the role is not found
*/
@Nullable
public ArraySet<String> getRoleHolders(@NonNull String roleName) {
synchronized (mLock) {
throwIfDestroyedLocked();
- return new ArraySet<>(mRoles.get(roleName));
+ ArraySet<String> packageNames = mRoles.get(roleName);
+ if (packageNames == null) {
+ return null;
+ }
+ return new ArraySet<>(packageNames);
}
}
@@ -268,8 +272,7 @@
* @param roleName the name of the role to add the holder to
* @param packageName the package name of the new holder
*
- * @return {@code false} only if the set of role holders is null, which should not happen and
- * indicates an issue.
+ * @return {@code false} if and only if the role is not found
*/
@CheckResult
public boolean addRoleHolder(@NonNull String roleName, @NonNull String packageName) {
@@ -302,8 +305,7 @@
* @param roleName the name of the role to remove the holder from
* @param packageName the package name of the holder to remove
*
- * @return {@code false} only if the set of role holders is null, which should not happen and
- * indicates an issue.
+ * @return {@code false} if and only if the role is not found
*/
@CheckResult
public boolean removeRoleHolder(@NonNull String roleName, @NonNull String packageName) {
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 30aa528..4e71a05 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -43,6 +43,7 @@
import android.content.pm.UserInfo;
import android.hardware.fingerprint.FingerprintManager;
import android.net.ConnectivityManager;
+import android.net.INetworkStatsService;
import android.net.Network;
import android.net.NetworkRequest;
import android.net.NetworkStats;
@@ -90,7 +91,6 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.procstats.IProcessStats;
import com.android.internal.app.procstats.ProcessStats;
-import com.android.internal.net.NetworkStatsFactory;
import com.android.internal.os.BatterySipper;
import com.android.internal.os.BatteryStatsHelper;
import com.android.internal.os.BinderCallsStats.ExportedCallStat;
@@ -210,6 +210,7 @@
private final Context mContext;
private final AlarmManager mAlarmManager;
+ private final INetworkStatsService mNetworkStatsService;
@GuardedBy("sStatsdLock")
private static IStatsManager sStatsd;
private static final Object sStatsdLock = new Object();
@@ -257,6 +258,8 @@
super();
mContext = context;
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
+ mNetworkStatsService = INetworkStatsService.Stub.asInterface(
+ ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
mBaseDir.mkdirs();
mAppUpdateReceiver = new AppUpdateReceiver();
mUserUpdateReceiver = new BroadcastReceiver() {
@@ -788,14 +791,14 @@
if (ifaces.length == 0) {
return;
}
- NetworkStatsFactory nsf = new NetworkStatsFactory();
+ if (mNetworkStatsService == null) {
+ Slog.e(TAG, "NetworkStats Service is not available!");
+ return;
+ }
// Combine all the metrics per Uid into one record.
- NetworkStats stats =
- nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE,
- null)
- .groupedByUid();
+ NetworkStats stats = mNetworkStatsService.getDetailedUidStats(ifaces).groupedByUid();
addNetworkStats(tagId, pulledData, stats, false);
- } catch (java.io.IOException e) {
+ } catch (RemoteException e) {
Slog.e(TAG, "Pulling netstats for wifi bytes has error", e);
} finally {
Binder.restoreCallingIdentity(token);
@@ -812,12 +815,14 @@
if (ifaces.length == 0) {
return;
}
- NetworkStatsFactory nsf = new NetworkStatsFactory();
+ if (mNetworkStatsService == null) {
+ Slog.e(TAG, "NetworkStats Service is not available!");
+ return;
+ }
NetworkStats stats = rollupNetworkStatsByFGBG(
- nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE,
- null));
+ mNetworkStatsService.getDetailedUidStats(ifaces));
addNetworkStats(tagId, pulledData, stats, true);
- } catch (java.io.IOException e) {
+ } catch (RemoteException e) {
Slog.e(TAG, "Pulling netstats for wifi bytes w/ fg/bg has error", e);
} finally {
Binder.restoreCallingIdentity(token);
@@ -834,14 +839,14 @@
if (ifaces.length == 0) {
return;
}
- NetworkStatsFactory nsf = new NetworkStatsFactory();
+ if (mNetworkStatsService == null) {
+ Slog.e(TAG, "NetworkStats Service is not available!");
+ return;
+ }
// Combine all the metrics per Uid into one record.
- NetworkStats stats =
- nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE,
- null)
- .groupedByUid();
+ NetworkStats stats = mNetworkStatsService.getDetailedUidStats(ifaces).groupedByUid();
addNetworkStats(tagId, pulledData, stats, false);
- } catch (java.io.IOException e) {
+ } catch (RemoteException e) {
Slog.e(TAG, "Pulling netstats for mobile bytes has error", e);
} finally {
Binder.restoreCallingIdentity(token);
@@ -874,12 +879,14 @@
if (ifaces.length == 0) {
return;
}
- NetworkStatsFactory nsf = new NetworkStatsFactory();
+ if (mNetworkStatsService == null) {
+ Slog.e(TAG, "NetworkStats Service is not available!");
+ return;
+ }
NetworkStats stats = rollupNetworkStatsByFGBG(
- nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE,
- null));
+ mNetworkStatsService.getDetailedUidStats(ifaces));
addNetworkStats(tagId, pulledData, stats, true);
- } catch (java.io.IOException e) {
+ } catch (RemoteException e) {
Slog.e(TAG, "Pulling netstats for mobile bytes w/ fg/bg has error", e);
} finally {
Binder.restoreCallingIdentity(token);
@@ -2058,6 +2065,17 @@
mContext.unregisterReceiver(mShutdownEventReceiver);
cancelAnomalyAlarm();
cancelPullingAlarm();
+
+ BinderCallsStatsService.Internal binderStats =
+ LocalServices.getService(BinderCallsStatsService.Internal.class);
+ if (binderStats != null) {
+ binderStats.reset();
+ }
+
+ LooperStats looperStats = LocalServices.getService(LooperStats.class);
+ if (looperStats != null) {
+ looperStats.reset();
+ }
}
@Override
diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java
index 1f638c7..0616846 100644
--- a/services/core/java/com/android/server/wm/ActivityDisplay.java
+++ b/services/core/java/com/android/server/wm/ActivityDisplay.java
@@ -278,12 +278,12 @@
}
// Since positionChildAt() is called during the creation process of pinned stacks,
- // ActivityStack#getWindowContainerController() can be null. In this special case,
+ // ActivityStack#getStack() can be null. In this special case,
// since DisplayContest#positionStackAt() is called in TaskStack#onConfigurationChanged(),
// we don't have to call WindowContainerController#positionChildAt() here.
- if (stack.getWindowContainerController() != null && mDisplayContent != null) {
+ if (stack.getTaskStack() != null && mDisplayContent != null) {
mDisplayContent.positionStackAt(insertPosition,
- stack.getWindowContainerController().mContainer, includingParents);
+ stack.getTaskStack(), includingParents);
}
if (!wasContained) {
stack.setParent(this);
@@ -450,13 +450,12 @@
@VisibleForTesting
<T extends ActivityStack> T createStackUnchecked(int windowingMode, int activityType,
int stackId, boolean onTop) {
- if (windowingMode == WINDOWING_MODE_PINNED) {
- return (T) new PinnedActivityStack(this, stackId,
- mRootActivityContainer.mStackSupervisor, onTop);
+ if (windowingMode == WINDOWING_MODE_PINNED && activityType != ACTIVITY_TYPE_STANDARD) {
+ throw new IllegalArgumentException("Stack with windowing mode cannot with non standard "
+ + "activity type.");
}
return (T) new ActivityStack(this, stackId,
- mRootActivityContainer.mStackSupervisor, windowingMode, activityType,
- onTop);
+ mRootActivityContainer.mStackSupervisor, windowingMode, activityType, onTop);
}
/**
@@ -1019,8 +1018,8 @@
return mSplitScreenPrimaryStack != null;
}
- PinnedActivityStack getPinnedStack() {
- return (PinnedActivityStack) mPinnedStack;
+ ActivityStack getPinnedStack() {
+ return mPinnedStack;
}
boolean hasPinnedStack() {
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 4d7de905..891c3da 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -114,6 +114,7 @@
import android.app.ActivityOptions;
import android.app.AppGlobals;
import android.app.IActivityController;
+import android.app.RemoteAction;
import android.app.ResultInfo;
import android.app.WindowConfiguration.ActivityType;
import android.app.WindowConfiguration.WindowingMode;
@@ -173,8 +174,7 @@
/**
* State and management of a single stack of activities.
*/
-class ActivityStack<T extends StackWindowController> extends ConfigurationContainer
- implements StackWindowListener {
+class ActivityStack extends ConfigurationContainer {
private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStack" : TAG_ATM;
private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
private static final String TAG_APP = TAG + POSTFIX_APP;
@@ -297,8 +297,7 @@
static final int REMOVE_TASK_MODE_MOVING_TO_TOP = 2;
final ActivityTaskManagerService mService;
- private final WindowManagerService mWindowManager;
- T mWindowContainerController;
+ final WindowManagerService mWindowManager;
/**
* The back history of all previous (and possibly still
@@ -397,6 +396,9 @@
static final int DESTROY_ACTIVITIES_MSG = FIRST_ACTIVITY_STACK_MSG + 5;
static final int TRANSLUCENT_TIMEOUT_MSG = FIRST_ACTIVITY_STACK_MSG + 6;
+ // TODO: remove after unification.
+ TaskStack mTaskStack;
+
private static class ScheduleDestroyArgs {
final WindowProcessController mOwner;
final String mReason;
@@ -495,21 +497,30 @@
// stacks on a wrong display.
mDisplayId = display.mDisplayId;
setActivityType(activityType);
- mWindowContainerController = createStackWindowController(display.mDisplayId, onTop,
- mTmpRect2);
+ createTaskStack(display.mDisplayId, onTop, mTmpRect2);
setWindowingMode(windowingMode, false /* animate */, false /* showRecents */,
false /* enteringSplitScreenMode */, false /* deferEnsuringVisibility */,
true /* creating */);
display.addChild(this, onTop ? POSITION_TOP : POSITION_BOTTOM);
}
- T createStackWindowController(int displayId, boolean onTop, Rect outBounds) {
- return (T) new StackWindowController(mStackId, this, displayId, onTop, outBounds,
- mRootActivityContainer.mWindowManager);
+ void createTaskStack(int displayId, boolean onTop, Rect outBounds) {
+ final DisplayContent dc = mWindowManager.mRoot.getDisplayContent(displayId);
+ if (dc == null) {
+ throw new IllegalArgumentException("Trying to add stackId=" + mStackId
+ + " to unknown displayId=" + displayId);
+ }
+ mTaskStack = new TaskStack(mWindowManager, mStackId, this);
+ dc.setStackOnDisplay(mStackId, onTop, mTaskStack);
+ if (mTaskStack.matchParentBounds()) {
+ outBounds.setEmpty();
+ } else {
+ mTaskStack.getRawBounds(outBounds);
+ }
}
- T getWindowContainerController() {
- return mWindowContainerController;
+ TaskStack getTaskStack() {
+ return mTaskStack;
}
/**
@@ -553,6 +564,9 @@
if (display == null) {
return;
}
+ if (getTaskStack() == null) {
+ return;
+ }
// Update bounds if applicable
boolean hasNewOverrideBounds = false;
@@ -560,8 +574,7 @@
if (getRequestedOverrideWindowingMode() == WINDOWING_MODE_PINNED) {
// Pinned calculation already includes rotation
mTmpRect2.set(mTmpRect);
- hasNewOverrideBounds = getWindowContainerController().mContainer
- .calculatePinnedBoundsForConfigChange(mTmpRect2);
+ hasNewOverrideBounds = getTaskStack().calculatePinnedBoundsForConfigChange(mTmpRect2);
} else {
final int newRotation = getWindowConfiguration().getRotation();
if (!matchParentBounds()) {
@@ -588,7 +601,7 @@
|| getRequestedOverrideWindowingMode()
== WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
mTmpRect2.set(mTmpRect);
- getWindowContainerController().mContainer
+ getTaskStack()
.calculateDockedBoundsForConfigChange(newParentConfig, mTmpRect2);
hasNewOverrideBounds = true;
}
@@ -786,7 +799,11 @@
mTmpRect2.setEmpty();
if (windowingMode != WINDOWING_MODE_FULLSCREEN) {
- mWindowContainerController.getRawBounds(mTmpRect2);
+ if (mTaskStack.matchParentBounds()) {
+ mTmpRect2.setEmpty();
+ } else {
+ mTaskStack.getRawBounds(mTmpRect2);
+ }
}
if (!Objects.equals(getRequestedOverrideBounds(), mTmpRect2)) {
@@ -843,7 +860,12 @@
// Reparent the window container before we try to update the position when adding it to
// the new display below
mTmpRect2.setEmpty();
- mWindowContainerController.reparent(activityDisplay.mDisplayId, mTmpRect2, onTop);
+ if (mTaskStack == null) {
+ // TODO: Remove after unification.
+ Log.w(TAG, "Task stack is not valid when reparenting.");
+ } else {
+ mTaskStack.reparent(activityDisplay.mDisplayId, mTmpRect2, onTop);
+ }
setBounds(mTmpRect2.isEmpty() ? null : mTmpRect2);
activityDisplay.addChild(this, onTop ? POSITION_TOP : POSITION_BOTTOM);
if (!displayRemoved) {
@@ -876,8 +898,10 @@
/** Removes the stack completely. Also calls WindowManager to do the same on its side. */
void remove() {
removeFromDisplay();
- mWindowContainerController.removeContainer();
- mWindowContainerController = null;
+ if (mTaskStack != null) {
+ mTaskStack.removeIfPossible();
+ mTaskStack = null;
+ }
onParentChanged();
}
@@ -890,26 +914,35 @@
*/
void getStackDockedModeBounds(Rect dockedBounds, Rect currentTempTaskBounds,
Rect outStackBounds, Rect outTempTaskBounds) {
- mWindowContainerController.getStackDockedModeBounds(getParent().getConfiguration(),
- dockedBounds, currentTempTaskBounds,
- outStackBounds, outTempTaskBounds);
+ if (mTaskStack != null) {
+ mTaskStack.getStackDockedModeBoundsLocked(getParent().getConfiguration(), dockedBounds,
+ currentTempTaskBounds, outStackBounds, outTempTaskBounds);
+ } else {
+ outStackBounds.setEmpty();
+ outTempTaskBounds.setEmpty();
+ }
}
void prepareFreezingTaskBounds() {
- mWindowContainerController.prepareFreezingTaskBounds();
+ if (mTaskStack != null) {
+ // TODO: This cannot be false after unification.
+ mTaskStack.prepareFreezingTaskBounds();
+ }
}
void getWindowContainerBounds(Rect outBounds) {
- if (mWindowContainerController != null) {
- mWindowContainerController.getBounds(outBounds);
+ if (mTaskStack != null) {
+ mTaskStack.getBounds(outBounds);
return;
}
outBounds.setEmpty();
}
void positionChildWindowContainerAtTop(TaskRecord child) {
- mWindowContainerController.positionChildAtTop(child.getTask(),
- true /* includingParents */);
+ if (mTaskStack != null) {
+ // TODO: Remove after unification. This cannot be false after that.
+ mTaskStack.positionChildAtTop(child.getTask(), true /* includingParents */);
+ }
}
void positionChildWindowContainerAtBottom(TaskRecord child) {
@@ -918,14 +951,27 @@
// task to bottom, the next focusable stack on the same display should be focused.
final ActivityStack nextFocusableStack = getDisplay().getNextFocusableStack(
child.getStack(), true /* ignoreCurrent */);
- mWindowContainerController.positionChildAtBottom(child.getTask(),
- nextFocusableStack == null /* includingParents */);
+ if (mTaskStack != null) {
+ // TODO: Remove after unification. This cannot be false after that.
+ mTaskStack.positionChildAtBottom(child.getTask(),
+ nextFocusableStack == null /* includingParents */);
+ }
}
/**
* Returns whether to defer the scheduling of the multi-window mode.
*/
boolean deferScheduleMultiWindowModeChanged() {
+ if (inPinnedWindowingMode()) {
+ // For the pinned stack, the deferring of the multi-window mode changed is tied to the
+ // transition animation into picture-in-picture, and is called once the animation
+ // completes, or is interrupted in a way that would leave the stack in a non-fullscreen
+ // state.
+ // @see BoundsAnimationController
+ // @see BoundsAnimationControllerTests
+ if (getTaskStack() == null) return false;
+ return getTaskStack().deferScheduleMultiWindowModeChanged();
+ }
return false;
}
@@ -2994,7 +3040,10 @@
position = getAdjustedPositionForTask(task, position, null /* starting */);
mTaskHistory.remove(task);
mTaskHistory.add(position, task);
- mWindowContainerController.positionChildAt(task.getTask(), position);
+ if (mTaskStack != null) {
+ // TODO: this could not be false after unification.
+ mTaskStack.positionChildAt(task.getTask(), position);
+ }
updateTaskMovement(task, true);
}
@@ -4909,8 +4958,7 @@
}
// TODO: Figure-out a way to consolidate with resize() method below.
- @Override
- public void requestResize(Rect bounds) {
+ void requestResize(Rect bounds) {
mService.resizeStack(mStackId, bounds,
true /* allowResizeInDockedMode */, false /* preserveWindows */,
false /* animate */, -1 /* animationDuration */);
@@ -4948,7 +4996,8 @@
}
void onPipAnimationEndResize() {
- mWindowContainerController.onPipAnimationEndResize();
+ if (mTaskStack == null) return;
+ mTaskStack.onPipAnimationEndResize();
}
@@ -5494,6 +5543,65 @@
}
}
+
+ Rect getDefaultPictureInPictureBounds(float aspectRatio) {
+ if (getTaskStack() == null) return null;
+ return getTaskStack().getPictureInPictureBounds(aspectRatio, null /* currentStackBounds */);
+ }
+
+ void animateResizePinnedStack(Rect sourceHintBounds, Rect toBounds, int animationDuration,
+ boolean fromFullscreen) {
+ if (!inPinnedWindowingMode()) return;
+ if (skipResizeAnimation(toBounds == null /* toFullscreen */)) {
+ mService.moveTasksToFullscreenStack(mStackId, true /* onTop */);
+ } else {
+ if (getTaskStack() == null) return;
+ getTaskStack().animateResizePinnedStack(toBounds, sourceHintBounds,
+ animationDuration, fromFullscreen);
+ }
+ }
+
+ private boolean skipResizeAnimation(boolean toFullscreen) {
+ if (!toFullscreen) {
+ return false;
+ }
+ final Configuration parentConfig = getParent().getConfiguration();
+ final ActivityRecord top = topRunningNonOverlayTaskActivity();
+ return top != null && !top.isConfigurationCompatible(parentConfig);
+ }
+
+ void setPictureInPictureAspectRatio(float aspectRatio) {
+ if (getTaskStack() == null) return;
+ getTaskStack().setPictureInPictureAspectRatio(aspectRatio);
+ }
+
+ void setPictureInPictureActions(List<RemoteAction> actions) {
+ if (getTaskStack() == null) return;
+ getTaskStack().setPictureInPictureActions(actions);
+ }
+
+ boolean isAnimatingBoundsToFullscreen() {
+ if (getTaskStack() == null) return false;
+ return getTaskStack().isAnimatingBoundsToFullscreen();
+ }
+
+ public void updatePictureInPictureModeForPinnedStackAnimation(Rect targetStackBounds,
+ boolean forceUpdate) {
+ // It is guaranteed that the activities requiring the update will be in the pinned stack at
+ // this point (either reparented before the animation into PiP, or before reparenting after
+ // the animation out of PiP)
+ synchronized (mService.mGlobalLock) {
+ if (!isAttached()) {
+ return;
+ }
+ ArrayList<TaskRecord> tasks = getAllTasks();
+ for (int i = 0; i < tasks.size(); i++) {
+ mStackSupervisor.updatePictureInPictureMode(tasks.get(i), targetStackBounds,
+ forceUpdate);
+ }
+ }
+ }
+
public int getStackId() {
return mStackId;
}
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index a50ae84..a4cda5a 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -1674,8 +1674,8 @@
}
void resizePinnedStackLocked(Rect pinnedBounds, Rect tempPinnedTaskBounds) {
- // TODO(multi-display): Pinned stack display should be passed in.
- final PinnedActivityStack stack =
+ // TODO(multi-display): The display containing the stack should be passed in.
+ final ActivityStack stack =
mRootActivityContainer.getDefaultDisplay().getPinnedStack();
if (stack == null) {
Slog.w(TAG, "resizePinnedStackLocked: pinned stack not found");
@@ -1686,7 +1686,7 @@
// another AM call that is holding the AMS lock. In such a case, the pinnedBounds may be
// incorrect if AMS.resizeStackWithBoundsFromWindowManager() is already called while waiting
// for the AMS lock to be freed. So check and make sure these bounds are still good.
- final PinnedStackWindowController stackController = stack.getWindowContainerController();
+ final TaskStack stackController = stack.getTaskStack();
if (stackController.pinnedStackResizeDisallowed()) {
return;
}
@@ -1730,15 +1730,14 @@
* invisible as well and added to the stopping list. After which we process the
* stopping list by handling the idle.
*/
- final PinnedActivityStack pinnedStack = (PinnedActivityStack) stack;
- pinnedStack.mForceHidden = true;
- pinnedStack.ensureActivitiesVisibleLocked(null, 0, PRESERVE_WINDOWS);
- pinnedStack.mForceHidden = false;
+ stack.mForceHidden = true;
+ stack.ensureActivitiesVisibleLocked(null, 0, PRESERVE_WINDOWS);
+ stack.mForceHidden = false;
activityIdleInternalLocked(null, false /* fromTimeout */,
true /* processPausingActivites */, null /* configuration */);
// Move all the tasks to the bottom of the fullscreen stack
- moveTasksToFullscreenStackLocked(pinnedStack, !ON_TOP);
+ moveTasksToFullscreenStackLocked(stack, !ON_TOP);
} else {
for (int i = tasks.size() - 1; i >= 0; i--) {
removeTaskByIdLocked(tasks.get(i).taskId, true /* killProcess */,
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index ef3c8d5..916baa0 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -749,7 +749,7 @@
if (!abort) {
abort |= shouldAbortBackgroundActivityStart(callingUid, callingPid, callingPackage,
realCallingUid, callerApp, originatingPendingIntent,
- allowBackgroundActivityStart);
+ allowBackgroundActivityStart, intent);
}
// Merge the two options bundles, while realCallerOptions takes precedence.
@@ -898,7 +898,8 @@
private boolean shouldAbortBackgroundActivityStart(int callingUid, int callingPid,
final String callingPackage, int realCallingUid, WindowProcessController callerApp,
- PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) {
+ PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart,
+ Intent intent) {
if (mService.isBackgroundActivityStartsEnabled()) {
return false;
}
@@ -911,19 +912,24 @@
return false;
}
// don't abort if the callingUid is in the foreground or is a persistent system process
- if (isUidForeground(callingUid) || isUidPersistentSystemProcess(callingUid)) {
+ final boolean isCallingUidForeground = isUidForeground(callingUid);
+ final boolean isCallingUidPersistentSystemProcess = isUidPersistentSystemProcess(
+ callingUid);
+ if (isCallingUidForeground || isCallingUidPersistentSystemProcess) {
return false;
}
// take realCallingUid into consideration
+ final boolean isRealCallingUidForeground = isUidForeground(realCallingUid);
+ final boolean isRealCallingUidPersistentSystemProcess = isUidPersistentSystemProcess(
+ realCallingUid);
if (realCallingUid != callingUid) {
// don't abort if the realCallingUid is in the foreground and callingUid isn't
- if (isUidForeground(realCallingUid)) {
+ if (isRealCallingUidForeground) {
return false;
}
// if the realCallingUid is a persistent system process, abort if the IntentSender
// wasn't whitelisted to start an activity
- if (isUidPersistentSystemProcess(realCallingUid) && (originatingPendingIntent != null)
- && allowBackgroundActivityStart) {
+ if (isRealCallingUidPersistentSystemProcess && allowBackgroundActivityStart) {
return false;
}
}
@@ -941,6 +947,18 @@
return false;
}
// anything that has fallen through will currently be aborted
+ Slog.w(TAG, "Blocking background activity start [callingPackage: " + callingPackage
+ + "; callingUid: " + callingUid
+ + "; isCallingUidForeground: " + isCallingUidForeground
+ + "; isCallingUidPersistentSystemProcess: " + isCallingUidPersistentSystemProcess
+ + "; realCallingUid: " + realCallingUid
+ + "; isRealCallingUidForeground: " + isRealCallingUidForeground
+ + "; isRealCallingUidPersistentSystemProcess: "
+ + isRealCallingUidPersistentSystemProcess
+ + "; originatingPendingIntent: " + originatingPendingIntent
+ + "; isBgStartWhitelisted: " + allowBackgroundActivityStart
+ + "; intent: " + intent
+ + "]");
// TODO: remove this toast after feature development is done
mService.mUiHandler.post(() -> {
Toast.makeText(mService.mContext,
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index e82e748..6a495d4 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -82,13 +82,10 @@
import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.HOME_PROC;
import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.LAUNCHING_ACTIVITY;
import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.PREVIOUS_PROC;
-import static com.android.server.am.ActivityManagerServiceDumpProcessesProto
- .PREVIOUS_PROC_VISIBLE_TIME_MS;
+import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.PREVIOUS_PROC_VISIBLE_TIME_MS;
import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.SCREEN_COMPAT_PACKAGES;
-import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage
- .MODE;
-import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage
- .PACKAGE;
+import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage.MODE;
+import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage.PACKAGE;
import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
import static com.android.server.wm.ActivityStackSupervisor.DEFER_RESUME;
import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
@@ -210,6 +207,7 @@
import android.provider.Settings;
import android.service.voice.IVoiceInteractionSession;
import android.service.voice.VoiceInteractionManagerInternal;
+import android.sysprop.DisplayProperties;
import android.telecom.TelecomManager;
import android.text.TextUtils;
import android.text.format.Time;
@@ -245,7 +243,6 @@
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.internal.util.function.pooled.PooledLambda;
-import com.android.server.appop.AppOpsService;
import com.android.server.AttributeCache;
import com.android.server.LocalServices;
import com.android.server.SystemService;
@@ -261,6 +258,7 @@
import com.android.server.am.PendingIntentController;
import com.android.server.am.PendingIntentRecord;
import com.android.server.am.UserState;
+import com.android.server.appop.AppOpsService;
import com.android.server.firewall.IntentFirewall;
import com.android.server.pm.UserManagerService;
import com.android.server.uri.UriGrantsManagerInternal;
@@ -694,7 +692,7 @@
final boolean isPc = mContext.getPackageManager().hasSystemFeature(FEATURE_PC);
// Transfer any global setting for forcing RTL layout, into a System Property
- SystemProperties.set(DEVELOPMENT_FORCE_RTL, forceRtl ? "1":"0");
+ DisplayProperties.debug_force_rtl(forceRtl);
final Configuration configuration = new Configuration();
Settings.System.getConfiguration(resolver, configuration);
@@ -2407,7 +2405,7 @@
try {
synchronized (mGlobalLock) {
if (animate) {
- final PinnedActivityStack stack = mRootActivityContainer.getStack(stackId);
+ final ActivityStack stack = mRootActivityContainer.getStack(stackId);
if (stack == null) {
Slog.w(TAG, "resizeStack: stackId " + stackId + " not found.");
return;
@@ -3712,7 +3710,7 @@
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
- final PinnedActivityStack stack =
+ final ActivityStack stack =
mRootActivityContainer.getDefaultDisplay().getPinnedStack();
if (stack == null) {
Slog.w(TAG, "dismissPip: pinned stack not found.");
@@ -3834,9 +3832,8 @@
// If we are animating to fullscreen then we have already dispatched the PIP mode
// changed, so we should reflect that check here as well.
- final PinnedActivityStack stack = r.getActivityStack();
- final PinnedStackWindowController windowController = stack.getWindowContainerController();
- return !windowController.mContainer.isAnimatingBoundsToFullscreen();
+ final TaskStack taskStack = r.getActivityStack().getTaskStack();
+ return !taskStack.isAnimatingBoundsToFullscreen();
}
@Override
@@ -3870,7 +3867,7 @@
r.pictureInPictureArgs.getSourceRectHint());
mRootActivityContainer.moveActivityToPinnedStack(
r, sourceBounds, aspectRatio, "enterPictureInPictureMode");
- final PinnedActivityStack stack = r.getActivityStack();
+ final ActivityStack stack = r.getActivityStack();
stack.setPictureInPictureAspectRatio(aspectRatio);
stack.setPictureInPictureActions(actions);
MetricsLoggerWrapper.logPictureInPictureEnter(mContext, r.appInfo.uid,
@@ -3914,7 +3911,7 @@
// If the activity is already in picture-in-picture, update the pinned stack now
// if it is not already expanding to fullscreen. Otherwise, the arguments will
// be used the next time the activity enters PiP
- final PinnedActivityStack stack = r.getActivityStack();
+ final ActivityStack stack = r.getActivityStack();
if (!stack.isAnimatingBoundsToFullscreen()) {
stack.setPictureInPictureAspectRatio(
r.pictureInPictureArgs.getAspectRatio());
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 740d472..b735115 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1160,12 +1160,14 @@
@Override
boolean onDescendantOrientationChanged(IBinder freezeDisplayToken,
ConfigurationContainer requestingContainer) {
+ final int previousRotation = mRotation;
final Configuration config = updateOrientationFromAppTokens(
getRequestedOverrideConfiguration(), freezeDisplayToken, false);
- // If display rotation class tells us that it doesn't consider app requested orientation,
- // this display won't rotate just because of an app changes its requested orientation. Thus
- // it indicates that this display chooses not to handle this request.
- final boolean handled = getDisplayRotation().respectAppRequestedOrientation();
+ // This event is considered handled iff a configuration propagation is triggered, because
+ // that's the only place lower level containers check if they need to do something to this
+ // request. The only guaranteed signal is that the display is rotated to a different
+ // orientation (i.e. rotating 180 degrees doesn't count).
+ final boolean handled = (mRotation - previousRotation) % 2 != 0;
if (config == null) {
return handled;
}
@@ -2307,13 +2309,12 @@
out.set(mDisplayFrames.mStable);
}
- TaskStack createStack(int stackId, boolean onTop, StackWindowController controller) {
- if (DEBUG_STACK) Slog.d(TAG_WM, "Create new stackId=" + stackId + " on displayId="
- + mDisplayId);
+ void setStackOnDisplay(int stackId, boolean onTop, TaskStack stack) {
+ if (DEBUG_STACK) {
+ Slog.d(TAG_WM, "Create new stackId=" + stackId + " on displayId=" + mDisplayId);
+ }
- final TaskStack stack = new TaskStack(mWmService, stackId, controller);
mTaskStackContainers.addStackToDisplay(stack, onTop);
- return stack;
}
void moveStackToDisplay(TaskStack stack, boolean onTop) {
@@ -4015,7 +4016,6 @@
/**
* Adds the stack to this container.
- * @see DisplayContent#createStack(int, boolean, StackWindowController)
*/
void addStackToDisplay(TaskStack stack, boolean onTop) {
addStackReferenceIfNeeded(stack);
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index bcc7be4..7aabc15 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -329,15 +329,6 @@
return mFixedToUserRotation;
}
- /**
- * Returns {@code true} if this display rotation takes app requested orientation into
- * consideration; {@code false} otherwise. For the time being the only case where this is {@code
- * false} is when {@link #isFixedToUserRotation()} is {@code true}.
- */
- boolean respectAppRequestedOrientation() {
- return !mFixedToUserRotation;
- }
-
public int getLandscapeRotation() {
return mLandscapeRotation;
}
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 5f56fe5..177f244 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -462,22 +462,19 @@
mOccluded = false;
mDismissingKeyguardActivity = null;
- // Only the top activity of the focused stack on each display may control it's
- // occluded state.
- final ActivityStack focusedStack = display.getFocusedStack();
- if (focusedStack != null) {
- final ActivityRecord topDismissing =
- focusedStack.getTopDismissingKeyguardActivity();
- mOccluded = focusedStack.topActivityOccludesKeyguard() || (topDismissing != null
- && focusedStack.topRunningActivityLocked() == topDismissing
- && controller.canShowWhileOccluded(
+ final ActivityStack stack = getStackForControllingOccluding(display);
+ if (stack != null) {
+ final ActivityRecord topDismissing = stack.getTopDismissingKeyguardActivity();
+ mOccluded = stack.topActivityOccludesKeyguard() || (topDismissing != null
+ && stack.topRunningActivityLocked() == topDismissing
+ && controller.canShowWhileOccluded(
true /* dismissKeyguard */,
false /* showWhenLocked */));
- if (focusedStack.getTopDismissingKeyguardActivity() != null) {
- mDismissingKeyguardActivity = focusedStack.getTopDismissingKeyguardActivity();
+ if (stack.getTopDismissingKeyguardActivity() != null) {
+ mDismissingKeyguardActivity = stack.getTopDismissingKeyguardActivity();
}
- mOccluded |= controller.mWindowManager.isShowingDream();
}
+ mOccluded |= controller.mWindowManager.isShowingDream();
// TODO(b/113840485): Handle app transition for individual display, and apply occluded
// state change to secondary displays.
@@ -492,6 +489,23 @@
}
}
+ /**
+ * Gets the stack used to check the occluded state.
+ * <p>
+ * Only the top non-pinned activity of the focusable stack on each display can control its
+ * occlusion state.
+ */
+ private ActivityStack getStackForControllingOccluding(ActivityDisplay display) {
+ for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+ final ActivityStack stack = display.getChildAt(stackNdx);
+ if (stack != null && stack.isFocusableAndVisible()
+ && !stack.inPinnedWindowingMode()) {
+ return stack;
+ }
+ }
+ return null;
+ }
+
void dumpStatus(PrintWriter pw, String prefix) {
final StringBuilder sb = new StringBuilder();
sb.append(prefix);
diff --git a/services/core/java/com/android/server/wm/LaunchParamsPersister.java b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
index 3062d34..86dc66d 100644
--- a/services/core/java/com/android/server/wm/LaunchParamsPersister.java
+++ b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
@@ -221,7 +221,7 @@
}
private boolean saveTaskToLaunchParam(TaskRecord task, PersistableLaunchParams params) {
- final ActivityStack<?> stack = task.getStack();
+ final ActivityStack stack = task.getStack();
final int displayId = stack.mDisplayId;
final ActivityDisplay display =
mSupervisor.mRootActivityContainer.getActivityDisplay(displayId);
diff --git a/services/core/java/com/android/server/wm/PinnedActivityStack.java b/services/core/java/com/android/server/wm/PinnedActivityStack.java
deleted file mode 100644
index 2a05af4..0000000
--- a/services/core/java/com/android/server/wm/PinnedActivityStack.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-
-import android.app.RemoteAction;
-import android.content.res.Configuration;
-import android.graphics.Rect;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * State and management of the pinned stack of activities.
- */
-class PinnedActivityStack extends ActivityStack<PinnedStackWindowController>
- implements PinnedStackWindowListener {
-
- PinnedActivityStack(ActivityDisplay display, int stackId, ActivityStackSupervisor supervisor,
- boolean onTop) {
- super(display, stackId, supervisor, WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, onTop);
- }
-
- @Override
- PinnedStackWindowController createStackWindowController(int displayId, boolean onTop,
- Rect outBounds) {
- return new PinnedStackWindowController(mStackId, this, displayId, onTop, outBounds,
- mRootActivityContainer.mWindowManager);
- }
-
- Rect getDefaultPictureInPictureBounds(float aspectRatio) {
- return getWindowContainerController().getPictureInPictureBounds(aspectRatio,
- null /* currentStackBounds */);
- }
-
- void animateResizePinnedStack(Rect sourceHintBounds, Rect toBounds, int animationDuration,
- boolean fromFullscreen) {
- if (skipResizeAnimation(toBounds == null /* toFullscreen */)) {
- mService.moveTasksToFullscreenStack(mStackId, true /* onTop */);
- } else {
- getWindowContainerController().animateResizePinnedStack(toBounds, sourceHintBounds,
- animationDuration, fromFullscreen);
- }
- }
-
- private boolean skipResizeAnimation(boolean toFullscreen) {
- if (!toFullscreen) {
- return false;
- }
- final Configuration parentConfig = getParent().getConfiguration();
- final ActivityRecord top = topRunningNonOverlayTaskActivity();
- return top != null && !top.isConfigurationCompatible(parentConfig);
- }
-
- void setPictureInPictureAspectRatio(float aspectRatio) {
- getWindowContainerController().setPictureInPictureAspectRatio(aspectRatio);
- }
-
- void setPictureInPictureActions(List<RemoteAction> actions) {
- getWindowContainerController().setPictureInPictureActions(actions);
- }
-
- boolean isAnimatingBoundsToFullscreen() {
- return getWindowContainerController().mContainer.isAnimatingBoundsToFullscreen();
- }
-
- /**
- * Returns whether to defer the scheduling of the multi-window mode.
- */
- boolean deferScheduleMultiWindowModeChanged() {
- // For the pinned stack, the deferring of the multi-window mode changed is tied to the
- // transition animation into picture-in-picture, and is called once the animation completes,
- // or is interrupted in a way that would leave the stack in a non-fullscreen state.
- // @see BoundsAnimationController
- // @see BoundsAnimationControllerTests
- return mWindowContainerController.deferScheduleMultiWindowModeChanged();
- }
-
- public void updatePictureInPictureModeForPinnedStackAnimation(Rect targetStackBounds,
- boolean forceUpdate) {
- // It is guaranteed that the activities requiring the update will be in the pinned stack at
- // this point (either reparented before the animation into PiP, or before reparenting after
- // the animation out of PiP)
- synchronized (mService.mGlobalLock) {
- if (!isAttached()) {
- return;
- }
- ArrayList<TaskRecord> tasks = getAllTasks();
- for (int i = 0; i < tasks.size(); i++ ) {
- mStackSupervisor.updatePictureInPictureMode(tasks.get(i), targetStackBounds,
- forceUpdate);
- }
- }
- }
-}
diff --git a/services/core/java/com/android/server/wm/PinnedStackWindowController.java b/services/core/java/com/android/server/wm/PinnedStackWindowController.java
deleted file mode 100644
index 518e39b..0000000
--- a/services/core/java/com/android/server/wm/PinnedStackWindowController.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.wm;
-
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-
-import static com.android.server.wm.BoundsAnimationController.NO_PIP_MODE_CHANGED_CALLBACKS;
-import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_END;
-import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_START;
-import static com.android.server.wm.BoundsAnimationController.SchedulePipModeChangedState;
-
-import android.app.RemoteAction;
-import android.graphics.Rect;
-
-import java.util.List;
-
-/**
- * Controller for the pinned stack container. See {@link StackWindowController}.
- */
-public class PinnedStackWindowController extends StackWindowController {
-
- private Rect mTmpFromBounds = new Rect();
- private Rect mTmpToBounds = new Rect();
-
- public PinnedStackWindowController(int stackId, PinnedStackWindowListener listener,
- int displayId, boolean onTop, Rect outBounds, WindowManagerService service) {
- super(stackId, listener, displayId, onTop, outBounds, service);
- }
-
- /**
- * @return the {@param currentStackBounds} transformed to the give {@param aspectRatio}. If
- * {@param currentStackBounds} is null, then the {@param aspectRatio} is applied to the
- * default bounds.
- */
- public Rect getPictureInPictureBounds(float aspectRatio, Rect stackBounds) {
- synchronized (mGlobalLock) {
- if (!mService.mSupportsPictureInPicture || mContainer == null) {
- return null;
- }
-
- final DisplayContent displayContent = mContainer.getDisplayContent();
- if (displayContent == null) {
- return null;
- }
-
- final PinnedStackController pinnedStackController =
- displayContent.getPinnedStackController();
- if (stackBounds == null) {
- // Calculate the aspect ratio bounds from the default bounds
- stackBounds = pinnedStackController.getDefaultOrLastSavedBounds();
- }
-
- if (pinnedStackController.isValidPictureInPictureAspectRatio(aspectRatio)) {
- return pinnedStackController.transformBoundsToAspectRatio(stackBounds, aspectRatio,
- true /* useCurrentMinEdgeSize */);
- } else {
- return stackBounds;
- }
- }
- }
-
- /**
- * Animates the pinned stack.
- */
- public void animateResizePinnedStack(Rect toBounds, Rect sourceHintBounds,
- int animationDuration, boolean fromFullscreen) {
- synchronized (mGlobalLock) {
- if (mContainer == null) {
- throw new IllegalArgumentException("Pinned stack container not found :(");
- }
-
- // Get the from-bounds
- final Rect fromBounds = new Rect();
- mContainer.getBounds(fromBounds);
-
- // Get non-null fullscreen to-bounds for animating if the bounds are null
- @SchedulePipModeChangedState int schedulePipModeChangedState =
- NO_PIP_MODE_CHANGED_CALLBACKS;
- final boolean toFullscreen = toBounds == null;
- if (toFullscreen) {
- if (fromFullscreen) {
- throw new IllegalArgumentException("Should not defer scheduling PiP mode"
- + " change on animation to fullscreen.");
- }
- schedulePipModeChangedState = SCHEDULE_PIP_MODE_CHANGED_ON_START;
-
- mService.getStackBounds(
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, mTmpToBounds);
- if (!mTmpToBounds.isEmpty()) {
- // If there is a fullscreen bounds, use that
- toBounds = new Rect(mTmpToBounds);
- } else {
- // Otherwise, use the display bounds
- toBounds = new Rect();
- mContainer.getDisplayContent().getBounds(toBounds);
- }
- } else if (fromFullscreen) {
- schedulePipModeChangedState = SCHEDULE_PIP_MODE_CHANGED_ON_END;
- }
-
- mContainer.setAnimationFinalBounds(sourceHintBounds, toBounds, toFullscreen);
-
- final Rect finalToBounds = toBounds;
- final @SchedulePipModeChangedState int finalSchedulePipModeChangedState =
- schedulePipModeChangedState;
- final DisplayContent displayContent = mContainer.getDisplayContent();
- displayContent.mBoundsAnimationController.getHandler().post(() -> {
- if (mContainer == null) {
- return;
- }
- displayContent.mBoundsAnimationController.animateBounds(mContainer, fromBounds,
- finalToBounds, animationDuration, finalSchedulePipModeChangedState,
- fromFullscreen, toFullscreen);
- });
- }
- }
-
- /**
- * Sets the current picture-in-picture aspect ratio.
- */
- public void setPictureInPictureAspectRatio(float aspectRatio) {
- synchronized (mGlobalLock) {
- if (!mService.mSupportsPictureInPicture || mContainer == null) {
- return;
- }
-
- final PinnedStackController pinnedStackController =
- mContainer.getDisplayContent().getPinnedStackController();
-
- if (Float.compare(aspectRatio, pinnedStackController.getAspectRatio()) != 0) {
- mContainer.getAnimationOrCurrentBounds(mTmpFromBounds);
- mTmpToBounds.set(mTmpFromBounds);
- getPictureInPictureBounds(aspectRatio, mTmpToBounds);
- if (!mTmpToBounds.equals(mTmpFromBounds)) {
- animateResizePinnedStack(mTmpToBounds, null /* sourceHintBounds */,
- -1 /* duration */, false /* fromFullscreen */);
- }
- pinnedStackController.setAspectRatio(
- pinnedStackController.isValidPictureInPictureAspectRatio(aspectRatio)
- ? aspectRatio : -1f);
- }
- }
- }
-
- /**
- * Sets the current picture-in-picture actions.
- */
- public void setPictureInPictureActions(List<RemoteAction> actions) {
- synchronized (mGlobalLock) {
- if (!mService.mSupportsPictureInPicture || mContainer == null) {
- return;
- }
-
- mContainer.getDisplayContent().getPinnedStackController().setActions(actions);
- }
- }
-
- /**
- * @return whether the multi-window mode change should be deferred as a part of a transition
- * from fullscreen to non-fullscreen bounds.
- */
- public boolean deferScheduleMultiWindowModeChanged() {
- synchronized (mGlobalLock) {
- return mContainer.deferScheduleMultiWindowModeChanged();
- }
- }
-
- /**
- * @return whether the stack can be resized from the bounds animation.
- */
- public boolean pinnedStackResizeDisallowed() {
- synchronized (mGlobalLock) {
- return mContainer.pinnedStackResizeDisallowed();
- }
- }
-
- /**
- * The following calls are made from WM to AM.
- */
-
- /** Calls directly into activity manager so window manager lock shouldn't held. */
- public void updatePictureInPictureModeForPinnedStackAnimation(Rect targetStackBounds,
- boolean forceUpdate) {
- if (mListener != null) {
- PinnedStackWindowListener listener = (PinnedStackWindowListener) mListener;
- listener.updatePictureInPictureModeForPinnedStackAnimation(targetStackBounds,
- forceUpdate);
- }
- }
-}
diff --git a/services/core/java/com/android/server/wm/PinnedStackWindowListener.java b/services/core/java/com/android/server/wm/PinnedStackWindowListener.java
deleted file mode 100644
index 33e8a60..0000000
--- a/services/core/java/com/android/server/wm/PinnedStackWindowListener.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.wm;
-
-import android.graphics.Rect;
-
-/**
- * Interface used by the creator of {@link PinnedStackWindowController} to listen to changes with
- * the stack container.
- */
-public interface PinnedStackWindowListener extends StackWindowListener {
-
- /**
- * Called when the stack container pinned stack animation will change the picture-in-picture
- * mode. This is a direct call into ActivityManager.
- */
- default void updatePictureInPictureModeForPinnedStackAnimation(Rect targetStackBounds,
- boolean forceUpdate) {}
-}
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index f55c7c9..55554a7 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -955,7 +955,7 @@
mWindowManager.deferSurfaceLayout();
final ActivityDisplay display = r.getActivityStack().getDisplay();
- PinnedActivityStack stack = display.getPinnedStack();
+ ActivityStack stack = display.getPinnedStack();
// This will clear the pinned stack by moving an existing task to the full screen stack,
// ensuring only one task is present.
diff --git a/services/core/java/com/android/server/wm/StackWindowController.java b/services/core/java/com/android/server/wm/StackWindowController.java
deleted file mode 100644
index ada807b..0000000
--- a/services/core/java/com/android/server/wm/StackWindowController.java
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.wm;
-
-import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
-import static com.android.server.wm.WindowContainer.POSITION_TOP;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-
-import android.content.res.Configuration;
-import android.graphics.Rect;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.util.Slog;
-import android.util.SparseArray;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.lang.ref.WeakReference;
-
-/**
- * Controller for the stack container. This is created by activity manager to link activity stacks
- * to the stack container they use in window manager.
- *
- * Test class: {@link StackWindowControllerTests}
- */
-public class StackWindowController
- extends WindowContainerController<TaskStack, StackWindowListener> {
-
- private final int mStackId;
-
- private final H mHandler;
-
- final Rect mTmpBounds = new Rect();
-
- public StackWindowController(int stackId, StackWindowListener listener, int displayId,
- boolean onTop, Rect outBounds) {
- this(stackId, listener, displayId, onTop, outBounds, WindowManagerService.getInstance());
- }
-
- @VisibleForTesting
- public StackWindowController(int stackId, StackWindowListener listener,
- int displayId, boolean onTop, Rect outBounds, WindowManagerService service) {
- super(listener, service);
- mStackId = stackId;
- mHandler = new H(new WeakReference<>(this), service.mH.getLooper());
-
- final DisplayContent dc = mRoot.getDisplayContent(displayId);
- if (dc == null) {
- throw new IllegalArgumentException("Trying to add stackId=" + stackId
- + " to unknown displayId=" + displayId);
- }
-
- dc.createStack(stackId, onTop, this);
- getRawBounds(outBounds);
- }
-
- @Override
- public void removeContainer() {
- if (mContainer != null) {
- mContainer.removeIfPossible();
- super.removeContainer();
- }
- }
-
- void reparent(int displayId, Rect outStackBounds, boolean onTop) {
- if (mContainer == null) {
- throw new IllegalArgumentException("Trying to move unknown stackId=" + mStackId
- + " to displayId=" + displayId);
- }
-
- final DisplayContent targetDc = mRoot.getDisplayContent(displayId);
- if (targetDc == null) {
- throw new IllegalArgumentException("Trying to move stackId=" + mStackId
- + " to unknown displayId=" + displayId);
- }
-
- targetDc.moveStackToDisplay(mContainer, onTop);
- getRawBounds(outStackBounds);
- }
-
- void positionChildAt(Task child, int position) {
- if (DEBUG_STACK) {
- Slog.i(TAG_WM, "positionChildAt: positioning task=" + child + " at " + position);
- }
- if (child == null) {
- if (DEBUG_STACK) {
- Slog.i(TAG_WM, "positionChildAt: could not find task=" + this);
- }
- return;
- }
- if (mContainer == null) {
- if (DEBUG_STACK) {
- Slog.i(TAG_WM, "positionChildAt: could not find stack for task=" + mContainer);
- }
- return;
- }
- child.positionAt(position);
- mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
- }
-
- void positionChildAtTop(Task child, boolean includingParents) {
- if (child == null) {
- // TODO: Fix the call-points that cause this to happen.
- return;
- }
-
- mContainer.positionChildAt(POSITION_TOP, child, includingParents);
-
- final DisplayContent displayContent = mContainer.getDisplayContent();
- if (displayContent.mAppTransition.isTransitionSet()) {
- child.setSendingToBottom(false);
- }
- displayContent.layoutAndAssignWindowLayersIfNeeded();
- }
-
- void positionChildAtBottom(Task child, boolean includingParents) {
- if (child == null) {
- // TODO: Fix the call-points that cause this to happen.
- return;
- }
-
- mContainer.positionChildAt(POSITION_BOTTOM, child, includingParents);
-
- if (mContainer.getDisplayContent().mAppTransition.isTransitionSet()) {
- child.setSendingToBottom(true);
- }
- mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
- }
-
- /**
- * Re-sizes a stack and its containing tasks.
- *
- * @param bounds New stack bounds. Passing in null sets the bounds to fullscreen.
- * @param taskBounds Bounds for tasks in the resized stack, keyed by task id.
- * @param taskTempInsetBounds Inset bounds for individual tasks, keyed by task id.
- */
- public void resize(Rect bounds, SparseArray<Rect> taskBounds,
- SparseArray<Rect> taskTempInsetBounds) {
- if (mContainer == null) {
- throw new IllegalArgumentException("resizeStack: stack " + this + " not found.");
- }
- // We might trigger a configuration change. Save the current task bounds for freezing.
- mContainer.prepareFreezingTaskBounds();
- if (mContainer.setBounds(bounds, taskBounds, taskTempInsetBounds)
- && mContainer.isVisible()) {
- mContainer.getDisplayContent().setLayoutNeeded();
- mService.mWindowPlacerLocked.performSurfacePlacement();
- }
- }
-
- public void onPipAnimationEndResize() {
- mContainer.onPipAnimationEndResize();
- }
-
- /**
- * @see TaskStack.getStackDockedModeBoundsLocked(ConfigurationContainer, Rect, Rect, Rect)
- */
- public void getStackDockedModeBounds(Configuration parentConfig, Rect dockedBounds,
- Rect currentTempTaskBounds,
- Rect outStackBounds, Rect outTempTaskBounds) {
- if (mContainer != null) {
- mContainer.getStackDockedModeBoundsLocked(parentConfig, dockedBounds,
- currentTempTaskBounds, outStackBounds, outTempTaskBounds);
- return;
- }
- outStackBounds.setEmpty();
- outTempTaskBounds.setEmpty();
- }
-
- public void prepareFreezingTaskBounds() {
- if (mContainer == null) {
- throw new IllegalArgumentException("prepareFreezingTaskBounds: stack " + this
- + " not found.");
- }
- mContainer.prepareFreezingTaskBounds();
- }
-
- public void getRawBounds(Rect outBounds) {
- if (mContainer.matchParentBounds()) {
- outBounds.setEmpty();
- } else {
- mContainer.getRawBounds(outBounds);
- }
- }
-
- public void getBounds(Rect outBounds) {
- if (mContainer != null) {
- mContainer.getBounds(outBounds);
- return;
- }
- outBounds.setEmpty();
- }
-
- void requestResize(Rect bounds) {
- mHandler.obtainMessage(H.REQUEST_RESIZE, bounds).sendToTarget();
- }
-
- @Override
- public String toString() {
- return "{StackWindowController stackId=" + mStackId + "}";
- }
-
- private static final class H extends Handler {
-
- static final int REQUEST_RESIZE = 0;
-
- private final WeakReference<StackWindowController> mController;
-
- H(WeakReference<StackWindowController> controller, Looper looper) {
- super(looper);
- mController = controller;
- }
-
- @Override
- public void handleMessage(Message msg) {
- final StackWindowController controller = mController.get();
- final StackWindowListener listener = (controller != null)
- ? controller.mListener : null;
- if (listener == null) {
- return;
- }
- switch (msg.what) {
- case REQUEST_RESIZE:
- listener.requestResize((Rect) msg.obj);
- break;
- }
- }
- }
-}
diff --git a/services/core/java/com/android/server/wm/StackWindowListener.java b/services/core/java/com/android/server/wm/StackWindowListener.java
deleted file mode 100644
index c763c17..0000000
--- a/services/core/java/com/android/server/wm/StackWindowListener.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.wm;
-
-import android.graphics.Rect;
-
-/**
- * Interface used by the creator of {@link StackWindowController} to listen to changes with
- * the stack container.
- */
-public interface StackWindowListener extends WindowContainerListener {
-
- /** Called when the stack container would like its controller to resize. */
- void requestResize(Rect bounds);
-}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index d334bd2..a7dd55b 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -209,26 +209,14 @@
super.removeImmediately();
}
- void reparent(StackWindowController stackController, int position, boolean moveParents) {
- if (DEBUG_STACK) {
- Slog.i(TAG_WM, "reparent: moving taskId=" + mTaskId
- + " to stack=" + stackController + " at " + position);
- }
- final TaskStack stack = stackController.mContainer;
- if (stack == null) {
- throw new IllegalArgumentException("reparent: could not find stack="
- + stackController);
- }
- reparent(stack, position, moveParents);
- getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
- }
-
-
void reparent(TaskStack stack, int position, boolean moveParents) {
if (stack == mStack) {
throw new IllegalArgumentException(
"task=" + this + " already child of stack=" + mStack);
}
+ if (stack == null) {
+ throw new IllegalArgumentException("reparent: could not find stack.");
+ }
if (DEBUG_STACK) Slog.i(TAG, "reParentTask: removing taskId=" + mTaskId
+ " from stack=" + mStack);
EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "reParentTask");
@@ -254,6 +242,7 @@
onDisplayChanged(displayContent);
prevDisplayContent.setLayoutNeeded();
}
+ getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
}
/** @see ActivityTaskManagerService#positionTaskInStack(int, int, int). */
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index 6acd864..f3050a9 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -709,7 +709,7 @@
final List<TaskRecord> tasksToCheck = new ArrayList<>();
for (int i = 0; i < display.getChildCount(); ++i) {
- ActivityStack<?> stack = display.getChildAt(i);
+ final ActivityStack stack = display.getChildAt(i);
if (!stack.inFreeformWindowingMode()) {
continue;
}
diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java
index 4a553cf..69dcaf4 100644
--- a/services/core/java/com/android/server/wm/TaskRecord.java
+++ b/services/core/java/com/android/server/wm/TaskRecord.java
@@ -455,17 +455,10 @@
}
final Rect bounds = updateOverrideConfigurationFromLaunchBounds();
- final StackWindowController stackController = getStack().getWindowContainerController();
+ final TaskStack stack = getStack().getTaskStack();
- if (DEBUG_STACK) {
- Slog.i(TAG_WM, "TaskRecord: taskId=" + taskId
- + " stack=" + stackController + " bounds=" + bounds);
- }
-
- final TaskStack stack = stackController.mContainer;
if (stack == null) {
- throw new IllegalArgumentException("TaskRecord: invalid stack="
- + stackController);
+ throw new IllegalArgumentException("TaskRecord: invalid stack=" + mStack);
}
EventLog.writeEvent(WM_TASK_CREATED, taskId, stack.mStackId);
mTask = new Task(taskId, stack, userId, mService.mWindowManager, mResizeMode,
@@ -742,7 +735,7 @@
// Must reparent first in window manager to avoid a situation where AM can delete the
// we are coming from in WM before we reparent because it became empty.
- mTask.reparent(toStack.getWindowContainerController(), position,
+ mTask.reparent(toStack.getTaskStack(), position,
moveStackMode == REPARENT_MOVE_STACK_TO_FRONT);
final boolean moveStackToFront = moveStackMode == REPARENT_MOVE_STACK_TO_FRONT
@@ -1278,28 +1271,28 @@
}
/**
- * Checks if the root activity requires a particular orientation (either by override or
+ * Checks if the top activity requires a particular orientation (either by override or
* activityInfo) and returns that. Otherwise, this returns ORIENTATION_UNDEFINED.
*/
- private int getRootActivityRequestedOrientation() {
- ActivityRecord root = getRootActivity();
+ private int getTopActivityRequestedOrientation() {
+ ActivityRecord top = getTopActivity();
if (getRequestedOverrideConfiguration().orientation != ORIENTATION_UNDEFINED
- || root == null) {
+ || top == null) {
return getRequestedOverrideConfiguration().orientation;
}
- int rootScreenOrientation = root.getOrientation();
- if (rootScreenOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {
+ int screenOrientation = top.getOrientation();
+ if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {
// NOSENSOR means the display's "natural" orientation, so return that.
ActivityDisplay display = mStack != null ? mStack.getDisplay() : null;
if (display != null && display.mDisplayContent != null) {
return mStack.getDisplay().mDisplayContent.getNaturalOrientation();
}
- } else if (rootScreenOrientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
+ } else if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
// LOCKED means the activity's orientation remains unchanged, so return existing value.
- return root.getConfiguration().orientation;
- } else if (ActivityInfo.isFixedOrientationLandscape(rootScreenOrientation)) {
+ return top.getConfiguration().orientation;
+ } else if (ActivityInfo.isFixedOrientationLandscape(screenOrientation)) {
return ORIENTATION_LANDSCAPE;
- } else if (ActivityInfo.isFixedOrientationPortrait(rootScreenOrientation)) {
+ } else if (ActivityInfo.isFixedOrientationPortrait(screenOrientation)) {
return ORIENTATION_PORTRAIT;
}
return ORIENTATION_UNDEFINED;
@@ -2196,9 +2189,9 @@
// In FULLSCREEN mode, always start with empty bounds to indicate "fill parent"
outOverrideBounds.setEmpty();
- // If the task or its root activity require a different orientation, make it fit the
+ // If the task or its top activity requires a different orientation, make it fit the
// available bounds by scaling down its bounds.
- int forcedOrientation = getRootActivityRequestedOrientation();
+ int forcedOrientation = getTopActivityRequestedOrientation();
if (forcedOrientation != ORIENTATION_UNDEFINED
&& forcedOrientation != newParentConfig.orientation) {
final Rect parentBounds = newParentConfig.windowConfiguration.getBounds();
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index ee74bdf..8ed7d04 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -21,6 +21,7 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.PINNED_WINDOWING_MODE_ELEVATION_IN_DIP;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
@@ -33,6 +34,10 @@
import static android.view.WindowManager.DOCKED_RIGHT;
import static android.view.WindowManager.DOCKED_TOP;
+import static com.android.server.wm.BoundsAnimationController.NO_PIP_MODE_CHANGED_CALLBACKS;
+import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_END;
+import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_START;
+import static com.android.server.wm.BoundsAnimationController.SchedulePipModeChangedState;
import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
import static com.android.server.wm.StackProto.ADJUSTED_BOUNDS;
import static com.android.server.wm.StackProto.ADJUSTED_FOR_IME;
@@ -47,10 +52,12 @@
import static com.android.server.wm.StackProto.MINIMIZE_AMOUNT;
import static com.android.server.wm.StackProto.TASKS;
import static com.android.server.wm.StackProto.WINDOW_CONTAINER;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.annotation.CallSuper;
+import android.app.RemoteAction;
import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.Rect;
@@ -71,9 +78,10 @@
import com.android.server.EventLogTags;
import java.io.PrintWriter;
+import java.util.List;
public class TaskStack extends WindowContainer<Task> implements
- BoundsAnimationTarget {
+ BoundsAnimationTarget, ConfigurationContainerListener {
/** Minimum size of an adjusted stack bounds relative to original stack bounds. Used to
* restrict IME adjustment so that a min portion of top stack remains visible.*/
private static final float ADJUSTED_STACK_FRACTION_MIN = 0.3f;
@@ -93,6 +101,10 @@
private Rect mTmpRect2 = new Rect();
private Rect mTmpRect3 = new Rect();
+ /** For Pinned stack controlling. */
+ private Rect mTmpFromBounds = new Rect();
+ private Rect mTmpToBounds = new Rect();
+
/** Stack bounds adjusted to screen content area (taking into account IM windows, etc.) */
private final Rect mAdjustedBounds = new Rect();
@@ -141,6 +153,9 @@
private Dimmer mDimmer = new Dimmer(this);
+ // TODO: remove after unification.
+ ActivityStack mActivityStack;
+
/**
* For {@link #prepareSurfaces}.
*/
@@ -150,10 +165,11 @@
private final AnimatingAppWindowTokenRegistry mAnimatingAppWindowTokenRegistry =
new AnimatingAppWindowTokenRegistry();
- TaskStack(WindowManagerService service, int stackId, StackWindowController controller) {
+ TaskStack(WindowManagerService service, int stackId, ActivityStack activityStack) {
super(service);
mStackId = stackId;
- setController(controller);
+ mActivityStack = activityStack;
+ activityStack.registerConfigurationChangeListener(this);
mDockedStackMinimizeThickness = service.mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.docked_stack_minimize_thickness);
EventLog.writeEvent(EventLogTags.WM_STACK_CREATED, stackId);
@@ -572,6 +588,49 @@
positionChildAt(position, task, moveParents /* includingParents */, showForAllUsers);
}
+ void positionChildAt(Task child, int position) {
+ if (DEBUG_STACK) {
+ Slog.i(TAG_WM, "positionChildAt: positioning task=" + child + " at " + position);
+ }
+ if (child == null) {
+ if (DEBUG_STACK) {
+ Slog.i(TAG_WM, "positionChildAt: could not find task=" + this);
+ }
+ return;
+ }
+ child.positionAt(position);
+ getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
+ }
+
+ void positionChildAtTop(Task child, boolean includingParents) {
+ if (child == null) {
+ // TODO: Fix the call-points that cause this to happen.
+ return;
+ }
+
+ positionChildAt(POSITION_TOP, child, includingParents);
+
+ final DisplayContent displayContent = getDisplayContent();
+ if (displayContent.mAppTransition.isTransitionSet()) {
+ child.setSendingToBottom(false);
+ }
+ displayContent.layoutAndAssignWindowLayersIfNeeded();
+ }
+
+ void positionChildAtBottom(Task child, boolean includingParents) {
+ if (child == null) {
+ // TODO: Fix the call-points that cause this to happen.
+ return;
+ }
+
+ positionChildAt(POSITION_BOTTOM, child, includingParents);
+
+ if (getDisplayContent().mAppTransition.isTransitionSet()) {
+ child.setSendingToBottom(true);
+ }
+ getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
+ }
+
@Override
void positionChildAt(int position, Task child, boolean includingParents) {
positionChildAt(position, child, includingParents, child.showForAllUsers());
@@ -596,6 +655,21 @@
EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, child.mTaskId, toTop, targetPosition);
}
+ void reparent(int displayId, Rect outStackBounds, boolean onTop) {
+ final DisplayContent targetDc = mWmService.mRoot.getDisplayContent(displayId);
+ if (targetDc == null) {
+ throw new IllegalArgumentException("Trying to move stackId=" + mStackId
+ + " to unknown displayId=" + displayId);
+ }
+
+ targetDc.moveStackToDisplay(this, onTop);
+ if (matchParentBounds()) {
+ outStackBounds.setEmpty();
+ } else {
+ getRawBounds(outStackBounds);
+ }
+ }
+
// TODO: We should really have users as a window container in the hierarchy so that we don't
// have to do complicated things like we are doing in this method.
private int findPositionForTask(Task task, int targetPosition, boolean showForAllUsers,
@@ -725,6 +799,23 @@
}
/**
+ * Re-sizes a stack and its containing tasks.
+ *
+ * @param bounds New stack bounds. Passing in null sets the bounds to fullscreen.
+ * @param taskBounds Bounds for tasks in the resized stack, keyed by task id.
+ * @param taskTempInsetBounds Inset bounds for individual tasks, keyed by task id.
+ */
+ void resize(Rect bounds, SparseArray<Rect> taskBounds,
+ SparseArray<Rect> taskTempInsetBounds) {
+ // We might trigger a configuration change. Save the current task bounds for freezing.
+ prepareFreezingTaskBounds();
+ if (setBounds(bounds, taskBounds, taskTempInsetBounds) && isVisible()) {
+ getDisplayContent().setLayoutNeeded();
+ mWmService.mWindowPlacerLocked.performSurfacePlacement();
+ }
+ }
+
+ /**
* Calculate an amount by which to expand the stack bounds in each direction.
* Used to make room for shadows in the pinned windowing mode.
*/
@@ -929,12 +1020,7 @@
(dockedStack == null || dockedStack == this) ? null : dockedStack.getRawBounds();
getStackDockedModeBoundsLocked(mDisplayContent.getConfiguration(), dockedBounds,
null /* currentTempTaskBounds */, bounds, tempBounds);
- getController().requestResize(bounds);
- }
-
- @Override
- StackWindowController getController() {
- return (StackWindowController) super.getController();
+ mActivityStack.requestResize(bounds);
}
@Override
@@ -947,6 +1033,14 @@
}
@Override
+ void removeImmediately() {
+ if (mActivityStack != null) {
+ mActivityStack.unregisterConfigurationChangeListener(this);
+ }
+ super.removeImmediately();
+ }
+
+ @Override
void onParentSet() {
super.onParentSet();
@@ -1572,14 +1666,13 @@
// I don't believe you...
}
- final PinnedStackWindowController controller =
- (PinnedStackWindowController) getController();
- if (schedulePipModeChangedCallback && controller != null) {
+ if (schedulePipModeChangedCallback && mActivityStack != null) {
// We need to schedule the PiP mode change before the animation up. It is possible
// in this case for the animation down to not have been completed, so always
// force-schedule and update to the client to ensure that it is notified that it
// is no longer in picture-in-picture mode
- controller.updatePictureInPictureModeForPinnedStackAnimation(null, forceUpdate);
+ mActivityStack.updatePictureInPictureModeForPinnedStackAnimation(null,
+ forceUpdate);
}
}
return true;
@@ -1592,12 +1685,10 @@
// Update to the final bounds if requested. This is done here instead of in the bounds
// animator to allow us to coordinate this after we notify the PiP mode changed
- final PinnedStackWindowController controller =
- (PinnedStackWindowController) getController();
- if (schedulePipModeChangedCallback && controller != null) {
+ if (schedulePipModeChangedCallback) {
// We need to schedule the PiP mode change after the animation down, so use the
// final bounds
- controller.updatePictureInPictureModeForPinnedStackAnimation(
+ mActivityStack.updatePictureInPictureModeForPinnedStackAnimation(
mBoundsAnimationTarget, false /* forceUpdate */);
}
@@ -1624,6 +1715,135 @@
}
}
+ /**
+ * @return the current stack bounds transformed to the given {@param aspectRatio}. If
+ * the default bounds is {@code null}, then the {@param aspectRatio} is applied to the
+ * default bounds.
+ */
+ Rect getPictureInPictureBounds(float aspectRatio, Rect stackBounds) {
+ if (!mWmService.mSupportsPictureInPicture) {
+ return null;
+ }
+
+ final DisplayContent displayContent = getDisplayContent();
+ if (displayContent == null) {
+ return null;
+ }
+
+ if (!inPinnedWindowingMode()) {
+ return null;
+ }
+
+ final PinnedStackController pinnedStackController =
+ displayContent.getPinnedStackController();
+ if (stackBounds == null) {
+ // Calculate the aspect ratio bounds from the default bounds
+ stackBounds = pinnedStackController.getDefaultOrLastSavedBounds();
+ }
+
+ if (pinnedStackController.isValidPictureInPictureAspectRatio(aspectRatio)) {
+ return pinnedStackController.transformBoundsToAspectRatio(stackBounds, aspectRatio,
+ true /* useCurrentMinEdgeSize */);
+ } else {
+ return stackBounds;
+ }
+ }
+
+ /**
+ * Animates the pinned stack.
+ */
+ void animateResizePinnedStack(Rect toBounds, Rect sourceHintBounds,
+ int animationDuration, boolean fromFullscreen) {
+ if (!inPinnedWindowingMode()) {
+ return;
+ }
+ // Get the from-bounds
+ final Rect fromBounds = new Rect();
+ getBounds(fromBounds);
+
+ // Get non-null fullscreen to-bounds for animating if the bounds are null
+ @SchedulePipModeChangedState int schedulePipModeChangedState =
+ NO_PIP_MODE_CHANGED_CALLBACKS;
+ final boolean toFullscreen = toBounds == null;
+ if (toFullscreen) {
+ if (fromFullscreen) {
+ throw new IllegalArgumentException("Should not defer scheduling PiP mode"
+ + " change on animation to fullscreen.");
+ }
+ schedulePipModeChangedState = SCHEDULE_PIP_MODE_CHANGED_ON_START;
+
+ mWmService.getStackBounds(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, mTmpToBounds);
+ if (!mTmpToBounds.isEmpty()) {
+ // If there is a fullscreen bounds, use that
+ toBounds = new Rect(mTmpToBounds);
+ } else {
+ // Otherwise, use the display bounds
+ toBounds = new Rect();
+ getDisplayContent().getBounds(toBounds);
+ }
+ } else if (fromFullscreen) {
+ schedulePipModeChangedState = SCHEDULE_PIP_MODE_CHANGED_ON_END;
+ }
+
+ setAnimationFinalBounds(sourceHintBounds, toBounds, toFullscreen);
+
+ final Rect finalToBounds = toBounds;
+ final @SchedulePipModeChangedState int finalSchedulePipModeChangedState =
+ schedulePipModeChangedState;
+ final DisplayContent displayContent = getDisplayContent();
+ displayContent.mBoundsAnimationController.getHandler().post(() -> {
+ displayContent.mBoundsAnimationController.animateBounds(this, fromBounds,
+ finalToBounds, animationDuration, finalSchedulePipModeChangedState,
+ fromFullscreen, toFullscreen);
+ });
+ }
+
+ /**
+ * Sets the current picture-in-picture aspect ratio.
+ */
+ void setPictureInPictureAspectRatio(float aspectRatio) {
+ if (!mWmService.mSupportsPictureInPicture) {
+ return;
+ }
+
+ if (!inPinnedWindowingMode()) {
+ return;
+ }
+
+ final PinnedStackController pinnedStackController =
+ getDisplayContent().getPinnedStackController();
+
+ if (Float.compare(aspectRatio, pinnedStackController.getAspectRatio()) == 0) {
+ return;
+ }
+ getAnimationOrCurrentBounds(mTmpFromBounds);
+ mTmpToBounds.set(mTmpFromBounds);
+ getPictureInPictureBounds(aspectRatio, mTmpToBounds);
+ if (!mTmpToBounds.equals(mTmpFromBounds)) {
+ animateResizePinnedStack(mTmpToBounds, null /* sourceHintBounds */,
+ -1 /* duration */, false /* fromFullscreen */);
+ }
+ pinnedStackController.setAspectRatio(
+ pinnedStackController.isValidPictureInPictureAspectRatio(aspectRatio)
+ ? aspectRatio : -1f);
+ }
+
+ /**
+ * Sets the current picture-in-picture actions.
+ */
+ void setPictureInPictureActions(List<RemoteAction> actions) {
+ if (!mWmService.mSupportsPictureInPicture) {
+ return;
+ }
+
+ if (!inPinnedWindowingMode()) {
+ return;
+ }
+
+ getDisplayContent().getPinnedStackController().setActions(actions);
+ }
+
@Override
public boolean isAttached() {
synchronized (mWmService.mGlobalLock) {
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index c8c5e8f..fb00aeb 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -107,6 +107,7 @@
"android.hardware.gnss@1.0",
"android.hardware.gnss@1.1",
"android.hardware.gnss@2.0",
+ "android.hardware.gnss.visibility_control@1.0",
"android.hardware.input.classifier@1.0",
"android.hardware.ir@1.0",
"android.hardware.light@2.0",
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index b290bc5..dcb2ff5 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -26,6 +26,7 @@
#include <android/hardware/gnss/1.1/IGnssMeasurement.h>
#include <android/hardware/gnss/2.0/IGnssMeasurement.h>
#include <android/hardware/gnss/measurement_corrections/1.0/IMeasurementCorrections.h>
+#include <android/hardware/gnss/visibility_control/1.0/IGnssVisibilityControl.h>
#include <nativehelper/JNIHelp.h>
#include "jni.h"
#include "hardware_legacy/power.h"
@@ -88,6 +89,8 @@
static jmethodID method_correctionPlaneLngDeg;
static jmethodID method_correctionPlaneAltDeg;
static jmethodID method_correctionPlaneAzimDeg;
+static jmethodID method_reportNfwNotification;
+static jmethodID method_isInEmergencySession;
/*
* Save a pointer to JavaVm to attach/detach threads executing
@@ -152,6 +155,9 @@
using IMeasurementCorrections =
android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrections;
+using android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControl;
+using android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControlCallback;
+
struct GnssDeathRecipient : virtual public hidl_death_recipient
{
// hidl_death_recipient interface
@@ -190,7 +196,7 @@
// This boolean is needed to ensure that Gnsss Measurement Corrections related method are only
// initalized when needed which will be few devices initially
bool firstGnssMeasurementCorrectionInjected = false;
-
+sp<IGnssVisibilityControl> gnssVisibilityControlIface = nullptr;
#define WAKE_LOCK_NAME "GPS"
@@ -856,7 +862,7 @@
Return<void> GnssMeasurementCallback::gnssMeasurementCb_2_0(
const IGnssMeasurementCallback_V2_0::GnssData& data) {
- // TODO(b/119571122): implement gnssMeasurementCb_2_0
+ translateAndSetGnssData(data);
return Void();
}
@@ -894,9 +900,8 @@
return data.measurementCount;
}
-template<>
-size_t GnssMeasurementCallback::getMeasurementCount<IGnssMeasurementCallback_V1_1::GnssData>
- (const IGnssMeasurementCallback_V1_1::GnssData& data) {
+template<class T>
+size_t GnssMeasurementCallback::getMeasurementCount(const T& data) {
return data.measurements.size();
}
@@ -958,6 +963,17 @@
ADR_STATE_HALF_CYCLE_REPORTED));
}
+// Preallocate object as: JavaObject object(env, "android/location/GnssMeasurement");
+template<>
+void GnssMeasurementCallback::translateSingleGnssMeasurement
+ <IGnssMeasurementCallback_V2_0::GnssMeasurement>(
+ const IGnssMeasurementCallback_V2_0::GnssMeasurement* measurement_V2_0,
+ JavaObject& object) {
+ translateSingleGnssMeasurement(&(measurement_V2_0->v1_1), object);
+
+ SET(CodeType, (static_cast<int32_t>(measurement_V2_0->codeType)));
+}
+
jobject GnssMeasurementCallback::translateGnssClock(
JNIEnv* env, const IGnssMeasurementCallback_V1_0::GnssClock* clock) {
JavaObject object(env, "android/location/GnssClock");
@@ -1080,6 +1096,54 @@
}
/*
+ * GnssVisibilityControlCallback implements callback methods of IGnssVisibilityControlCallback.hal.
+ */
+struct GnssVisibilityControlCallback : public IGnssVisibilityControlCallback {
+ Return<void> nfwNotifyCb(const IGnssVisibilityControlCallback::NfwNotification& notification)
+ override;
+ Return<bool> isInEmergencySession() override;
+};
+
+Return<void> GnssVisibilityControlCallback::nfwNotifyCb(
+ const IGnssVisibilityControlCallback::NfwNotification& notification) {
+ JNIEnv* env = getJniEnv();
+ jstring proxyAppPackageName = env->NewStringUTF(notification.proxyAppPackageName.c_str());
+ jstring otherProtocolStackName = env->NewStringUTF(notification.otherProtocolStackName.c_str());
+ jstring requestorId = env->NewStringUTF(notification.requestorId.c_str());
+
+ if (proxyAppPackageName && otherProtocolStackName && requestorId) {
+ env->CallVoidMethod(mCallbacksObj, method_reportNfwNotification, proxyAppPackageName,
+ notification.protocolStack, otherProtocolStackName,
+ notification.requestor, requestorId,
+ notification.inEmergencyMode, notification.isCachedLocation);
+ } else {
+ ALOGE("%s: OOM Error\n", __func__);
+ }
+
+ if (requestorId) {
+ env->DeleteLocalRef(requestorId);
+ }
+
+ if (otherProtocolStackName) {
+ env->DeleteLocalRef(otherProtocolStackName);
+ }
+
+ if (proxyAppPackageName) {
+ env->DeleteLocalRef(proxyAppPackageName);
+ }
+
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return Void();
+}
+
+Return<bool> GnssVisibilityControlCallback::isInEmergencySession() {
+ JNIEnv* env = getJniEnv();
+ auto result = env->CallBooleanMethod(mCallbacksObj, method_isInEmergencySession);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return result;
+}
+
+/*
* AGnssCallback_V1_0 implements callback methods required by the IAGnssCallback 1.0 interface.
*/
struct AGnssCallback_V1_0 : public IAGnssCallback_V1_0 {
@@ -1313,6 +1377,9 @@
"reportLocationBatch",
"([Landroid/location/Location;)V");
method_reportGnssServiceDied = env->GetMethodID(clazz, "reportGnssServiceDied", "()V");
+ method_reportNfwNotification = env->GetMethodID(clazz, "reportNfwNotification",
+ "(Ljava/lang/String;BLjava/lang/String;BLjava/lang/String;BZZ)V");
+ method_isInEmergencySession = env->GetMethodID(clazz, "isInEmergencySession", "()Z");
/*
* Save a pointer to JVM.
@@ -1388,12 +1455,6 @@
if (gnssHal_V2_0 != nullptr) {
// TODO(b/119638366): getExtensionGnssMeasurement_1_1 from gnssHal_V2_0
auto gnssMeasurement = gnssHal_V2_0->getExtensionGnssMeasurement_2_0();
- auto gnssCorrections = gnssHal_V2_0->getExtensionMeasurementCorrections();
- if (!gnssCorrections.isOk()) {
- ALOGD("Unable to get a handle to GnssMeasurementCorrections interface");
- } else {
- gnssCorrectionsIface = gnssCorrections;
- }
if (!gnssMeasurement.isOk()) {
ALOGD("Unable to get a handle to GnssMeasurement_V2_0");
} else {
@@ -1401,6 +1462,12 @@
gnssMeasurementIface_V1_1 = gnssMeasurementIface_V2_0;
gnssMeasurementIface = gnssMeasurementIface_V2_0;
}
+ auto gnssCorrections = gnssHal_V2_0->getExtensionMeasurementCorrections();
+ if (!gnssCorrections.isOk()) {
+ ALOGD("Unable to get a handle to GnssMeasurementCorrections interface");
+ } else {
+ gnssCorrectionsIface = gnssCorrections;
+ }
} else if (gnssHal_V1_1 != nullptr) {
auto gnssMeasurement = gnssHal_V1_1->getExtensionGnssMeasurement_1_1();
if (!gnssMeasurement.isOk()) {
@@ -1471,6 +1538,15 @@
} else {
gnssBatchingIface = gnssBatching;
}
+
+ if (gnssHal_V2_0 != nullptr) {
+ auto gnssVisibilityControl = gnssHal_V2_0->getExtensionVisibilityControl();
+ if (!gnssVisibilityControl.isOk()) {
+ ALOGD("Unable to get a handle to GnssVisibilityControl interface");
+ } else {
+ gnssVisibilityControlIface = gnssVisibilityControl;
+ }
+ }
}
static jboolean android_location_GnssLocationProvider_is_supported(
@@ -1572,7 +1648,13 @@
if (agnssRilIface != nullptr) {
agnssRilIface->setCallback(aGnssRilCbIface);
} else {
- ALOGI("Unable to Initialize AGnss Ril interface\n");
+ ALOGI("Unable to initialize AGnss Ril interface\n");
+ }
+
+ if (gnssVisibilityControlIface != nullptr) {
+ sp<IGnssVisibilityControlCallback> gnssVisibilityControlCbIface =
+ new GnssVisibilityControlCallback();
+ gnssVisibilityControlIface->setCallback(gnssVisibilityControlCbIface);
}
return JNI_TRUE;
@@ -1974,6 +2056,11 @@
return result;
}
+static jboolean android_location_GnssLocationProvider_is_gnss_visibility_control_supported(
+ JNIEnv* /* env */, jclass /* clazz */) {
+ return (gnssVisibilityControlIface != nullptr) ? JNI_TRUE : JNI_FALSE;
+}
+
static void android_location_GnssNetworkConnectivityHandler_update_network_state(JNIEnv* env,
jobject /* obj */,
jboolean connected,
@@ -2557,6 +2644,29 @@
return gnssBatchingIface->stop();
}
+static jboolean android_location_GnssVisibilityControl_enable_nfw_location_access(
+ JNIEnv* env, jobject, jobjectArray proxyApps) {
+ if (gnssVisibilityControlIface == nullptr) {
+ ALOGI("No GNSS Visibility Control interface available");
+ return JNI_FALSE;
+ }
+
+ const jsize length = env->GetArrayLength(proxyApps);
+ hidl_vec<hidl_string> hidlProxyApps(length);
+ for (int i = 0; i < length; ++i) {
+ jstring proxyApp = (jstring) (env->GetObjectArrayElement(proxyApps, i));
+ ScopedJniString jniProxyApp(env, proxyApp);
+ hidlProxyApps[i] = jniProxyApp;
+ }
+
+ auto result = gnssVisibilityControlIface->enableNfwLocationAccess(hidlProxyApps);
+ if (result.isOk()) {
+ return result;
+ } else {
+ return JNI_FALSE;
+ }
+}
+
static const JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
{"class_init_native", "()V", reinterpret_cast<void *>(
@@ -2607,6 +2717,8 @@
{"native_get_internal_state",
"()Ljava/lang/String;",
reinterpret_cast<void *>(android_location_GnssLocationProvider_get_internal_state)},
+ {"native_is_gnss_visibility_control_supported", "()Z", reinterpret_cast<void *>(
+ android_location_GnssLocationProvider_is_gnss_visibility_control_supported)},
};
static const JNINativeMethod sMethodsBatching[] = {
@@ -2736,6 +2848,14 @@
reinterpret_cast<void *>(android_location_GnssConfiguration_set_es_extension_sec)},
};
+static const JNINativeMethod sVisibilityControlMethods[] = {
+ /* name, signature, funcPtr */
+ {"native_enable_nfw_location_access",
+ "([Ljava/lang/String;)Z",
+ reinterpret_cast<void *>(
+ android_location_GnssVisibilityControl_enable_nfw_location_access)},
+};
+
int register_android_server_location_GnssLocationProvider(JNIEnv* env) {
jniRegisterNativeMethods(
env,
@@ -2767,6 +2887,11 @@
"com/android/server/location/GnssConfiguration",
sConfigurationMethods,
NELEM(sConfigurationMethods));
+ jniRegisterNativeMethods(
+ env,
+ "com/android/server/location/GnssVisibilityControl",
+ sVisibilityControlMethods,
+ NELEM(sVisibilityControlMethods));
return jniRegisterNativeMethods(
env,
"com/android/server/location/GnssLocationProvider",
diff --git a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreDatabase.java b/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreDatabase.java
new file mode 100644
index 0000000..eaab650
--- /dev/null
+++ b/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreDatabase.java
@@ -0,0 +1,143 @@
+/*
+ * 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.server.net.ipmemorystore;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+
+/**
+ * Encapsulating class for using the SQLite database backing the memory store.
+ *
+ * This class groups together the contracts and the SQLite helper used to
+ * use the database.
+ *
+ * @hide
+ */
+public class IpMemoryStoreDatabase {
+ /**
+ * Contract class for the Network Attributes table.
+ */
+ public static class NetworkAttributesContract {
+ public static final String TABLENAME = "NetworkAttributes";
+
+ public static final String COLNAME_L2KEY = "l2Key";
+ public static final String COLTYPE_L2KEY = "TEXT NOT NULL";
+
+ public static final String COLNAME_EXPIRYDATE = "expiryDate";
+ // Milliseconds since the Epoch, in true Java style
+ public static final String COLTYPE_EXPIRYDATE = "BIGINT";
+
+ public static final String COLNAME_ASSIGNEDV4ADDRESS = "assignedV4Address";
+ public static final String COLTYPE_ASSIGNEDV4ADDRESS = "INTEGER";
+
+ // Please note that the group hint is only a *hint*, hence its name. The client can offer
+ // this information to nudge the grouping in the decision it thinks is right, but it can't
+ // decide for the memory store what is the same L3 network.
+ public static final String COLNAME_GROUPHINT = "groupHint";
+ public static final String COLTYPE_GROUPHINT = "TEXT";
+
+ public static final String COLNAME_DNSADDRESSES = "dnsAddresses";
+ // Stored in marshalled form as is
+ public static final String COLTYPE_DNSADDRESSES = "BLOB";
+
+ public static final String COLNAME_MTU = "mtu";
+ public static final String COLTYPE_MTU = "INTEGER";
+
+ public static final String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS "
+ + TABLENAME + " ("
+ + COLNAME_L2KEY + " " + COLTYPE_L2KEY + " PRIMARY KEY NOT NULL, "
+ + COLNAME_EXPIRYDATE + " " + COLTYPE_EXPIRYDATE + ", "
+ + COLNAME_ASSIGNEDV4ADDRESS + " " + COLTYPE_ASSIGNEDV4ADDRESS + ", "
+ + COLNAME_GROUPHINT + " " + COLTYPE_GROUPHINT + ", "
+ + COLNAME_DNSADDRESSES + " " + COLTYPE_DNSADDRESSES + ", "
+ + COLNAME_MTU + " " + COLTYPE_MTU + ")";
+ public static final String DROP_TABLE = "DROP TABLE IF EXISTS " + TABLENAME;
+ }
+
+ /**
+ * Contract class for the Private Data table.
+ */
+ public static class PrivateDataContract {
+ public static final String TABLENAME = "PrivateData";
+
+ public static final String COLNAME_L2KEY = "l2Key";
+ public static final String COLTYPE_L2KEY = "TEXT NOT NULL";
+
+ public static final String COLNAME_CLIENT = "client";
+ public static final String COLTYPE_CLIENT = "TEXT NOT NULL";
+
+ public static final String COLNAME_DATANAME = "dataName";
+ public static final String COLTYPE_DATANAME = "TEXT NOT NULL";
+
+ public static final String COLNAME_DATA = "data";
+ public static final String COLTYPE_DATA = "BLOB NOT NULL";
+
+ public static final String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS "
+ + TABLENAME + " ("
+ + COLNAME_L2KEY + " " + COLTYPE_L2KEY + ", "
+ + COLNAME_CLIENT + " " + COLTYPE_CLIENT + ", "
+ + COLNAME_DATANAME + " " + COLTYPE_DATANAME + ", "
+ + COLNAME_DATA + " " + COLTYPE_DATA + ", "
+ + "PRIMARY KEY ("
+ + COLNAME_L2KEY + ", "
+ + COLNAME_CLIENT + ", "
+ + COLNAME_DATANAME + "))";
+ public static final String DROP_TABLE = "DROP TABLE IF EXISTS " + TABLENAME;
+ }
+
+ // To save memory when the DB is not used, close it after 30s of inactivity. This is
+ // determined manually based on what feels right.
+ private static final long IDLE_CONNECTION_TIMEOUT_MS = 30_000;
+
+ /** The SQLite DB helper */
+ public static class DbHelper extends SQLiteOpenHelper {
+ // Update this whenever changing the schema.
+ private static final int SCHEMA_VERSION = 1;
+ private static final String DATABASE_FILENAME = "IpMemoryStore.db";
+
+ public DbHelper(@NonNull final Context context) {
+ super(context, DATABASE_FILENAME, null, SCHEMA_VERSION);
+ setIdleConnectionTimeout(IDLE_CONNECTION_TIMEOUT_MS);
+ }
+
+ /** Called when the database is created */
+ public void onCreate(@NonNull final SQLiteDatabase db) {
+ db.execSQL(NetworkAttributesContract.CREATE_TABLE);
+ db.execSQL(PrivateDataContract.CREATE_TABLE);
+ }
+
+ /** Called when the database is upgraded */
+ public void onUpgrade(@NonNull final SQLiteDatabase db, final int oldVersion,
+ final int newVersion) {
+ // No upgrade supported yet.
+ db.execSQL(NetworkAttributesContract.DROP_TABLE);
+ db.execSQL(PrivateDataContract.DROP_TABLE);
+ onCreate(db);
+ }
+
+ /** Called when the database is downgraded */
+ public void onDowngrade(@NonNull final SQLiteDatabase db, final int oldVersion,
+ final int newVersion) {
+ // Downgrades always nuke all data and recreate an empty table.
+ db.execSQL(NetworkAttributesContract.DROP_TABLE);
+ db.execSQL(PrivateDataContract.DROP_TABLE);
+ onCreate(db);
+ }
+ }
+}
diff --git a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreService.java b/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreService.java
index c9759bf..55a72190 100644
--- a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreService.java
+++ b/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreService.java
@@ -19,6 +19,8 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
+import android.database.SQLException;
+import android.database.sqlite.SQLiteDatabase;
import android.net.IIpMemoryStore;
import android.net.ipmemorystore.Blob;
import android.net.ipmemorystore.IOnBlobRetrievedListener;
@@ -27,6 +29,10 @@
import android.net.ipmemorystore.IOnSameNetworkResponseListener;
import android.net.ipmemorystore.IOnStatusListener;
import android.net.ipmemorystore.NetworkAttributesParcelable;
+import android.util.Log;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
/**
* Implementation for the IP memory store.
@@ -37,10 +43,75 @@
* @hide
*/
public class IpMemoryStoreService extends IIpMemoryStore.Stub {
- final Context mContext;
+ private static final String TAG = IpMemoryStoreService.class.getSimpleName();
+ private static final int MAX_CONCURRENT_THREADS = 4;
+ @NonNull
+ final Context mContext;
+ @Nullable
+ final SQLiteDatabase mDb;
+ @NonNull
+ final ExecutorService mExecutor;
+
+ /**
+ * Construct an IpMemoryStoreService object.
+ * This constructor will block on disk access to open the database.
+ * @param context the context to access storage with.
+ */
public IpMemoryStoreService(@NonNull final Context context) {
+ // Note that constructing the service will access the disk and block
+ // for some time, but it should make no difference to the clients. Because
+ // the interface is one-way, clients fire and forget requests, and the callback
+ // will get called eventually in any case, and the framework will wait for the
+ // service to be created to deliver subsequent requests.
+ // Avoiding this would mean the mDb member can't be final, which means the service would
+ // have to test for nullity, care for failure, and allow for a wait at every single access,
+ // which would make the code a lot more complex and require all methods to possibly block.
mContext = context;
+ SQLiteDatabase db;
+ final IpMemoryStoreDatabase.DbHelper helper = new IpMemoryStoreDatabase.DbHelper(context);
+ try {
+ db = helper.getWritableDatabase();
+ if (null == db) Log.e(TAG, "Unexpected null return of getWriteableDatabase");
+ } catch (final SQLException e) {
+ Log.e(TAG, "Can't open the Ip Memory Store database", e);
+ db = null;
+ } catch (final Exception e) {
+ Log.wtf(TAG, "Impossible exception Ip Memory Store database", e);
+ db = null;
+ }
+ mDb = db;
+ // The work-stealing thread pool executor will spawn threads as needed up to
+ // the max only when there is no free thread available. This generally behaves
+ // exactly like one would expect it intuitively :
+ // - When work arrives, it will spawn a new thread iff there are no available threads
+ // - When there is no work to do it will shutdown threads after a while (the while
+ // being equal to 2 seconds (not configurable) when max threads are spun up and
+ // twice as much for every one less thread)
+ // - When all threads are busy the work is enqueued and waits for any worker
+ // to become available.
+ // Because the stealing pool is made for very heavily parallel execution of
+ // small tasks that spawn others, it creates a queue per thread that in this
+ // case is overhead. However, the three behaviors above make it a superior
+ // choice to cached or fixedThreadPoolExecutor, neither of which can actually
+ // enqueue a task waiting for a thread to be free. This can probably be solved
+ // with judicious subclassing of ThreadPoolExecutor, but that's a lot of dangerous
+ // complexity for little benefit in this case.
+ mExecutor = Executors.newWorkStealingPool(MAX_CONCURRENT_THREADS);
+ }
+
+ /**
+ * Shutdown the memory store service, cancelling running tasks and dropping queued tasks.
+ *
+ * This is provided to give a way to clean up, and is meant to be available in case of an
+ * emergency shutdown.
+ */
+ public void shutdown() {
+ // By contrast with ExecutorService#shutdown, ExecutorService#shutdownNow tries
+ // to cancel the existing tasks, and does not wait for completion. It does not
+ // guarantee the threads can be terminated in any given amount of time.
+ mExecutor.shutdownNow();
+ if (mDb != null) mDb.close();
}
/**
@@ -61,7 +132,7 @@
public void storeNetworkAttributes(@NonNull final String l2Key,
@NonNull final NetworkAttributesParcelable attributes,
@Nullable final IOnStatusListener listener) {
- // TODO : implement this
+ // TODO : implement this.
}
/**
@@ -79,7 +150,7 @@
public void storeBlob(@NonNull final String l2Key, @NonNull final String clientId,
@NonNull final String name, @NonNull final Blob data,
@Nullable final IOnStatusListener listener) {
- // TODO : implement this
+ // TODO : implement this.
}
/**
@@ -99,7 +170,7 @@
@Override
public void findL2Key(@NonNull final NetworkAttributesParcelable attributes,
@NonNull final IOnL2KeyResponseListener listener) {
- // TODO : implement this
+ // TODO : implement this.
}
/**
@@ -114,7 +185,7 @@
@Override
public void isSameNetwork(@NonNull final String l2Key1, @NonNull final String l2Key2,
@NonNull final IOnSameNetworkResponseListener listener) {
- // TODO : implement this
+ // TODO : implement this.
}
/**
diff --git a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/RelevanceUtils.java b/services/ipmemorystore/java/com/android/server/net/ipmemorystore/RelevanceUtils.java
new file mode 100644
index 0000000..aa45400
--- /dev/null
+++ b/services/ipmemorystore/java/com/android/server/net/ipmemorystore/RelevanceUtils.java
@@ -0,0 +1,307 @@
+/*
+ * 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.server.net.ipmemorystore;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * A class containing the logic around the relevance value for
+ * IP Memory Store.
+ *
+ * @hide
+ */
+public class RelevanceUtils {
+ /**
+ * The relevance is a decaying value that gets lower and lower until it
+ * reaches 0 after some time passes. It follows an exponential decay law,
+ * dropping slowly at first then faster and faster, because a network is
+ * likely to be visited again if it was visited not long ago, and the longer
+ * it hasn't been visited the more likely it is that it won't be visited
+ * again. For example, a network visited on holiday should stay fresh for
+ * the duration of the holiday and persist for a while, but after the venue
+ * hasn't been visited for a while it should quickly be discarded. What
+ * should accelerate forgetting the network is extended periods without
+ * visits, so that occasional venues get discarded but regular visits keep
+ * the network relevant, even if the visits are infrequent.
+ *
+ * This function must be stable by iteration, meaning that adjusting the same value
+ * for different dates iteratively multiple times should give the same result.
+ * Formally, if f is the decay function that associates a relevance x at a date d1
+ * to the value at ulterior date d3, then for any date d2 between d1 and d3 :
+ * f(x, d3 - d1) = f(f(x, d3 - d2), d2 - d1). Intuitively, this property simply
+ * means it should be the same to compute and store back the value after two months,
+ * or to do it once after one month, store it back, and do it again after another
+ * months has passed.
+ * The pair of the relevance and date define the entire curve, so any pair
+ * of values on the curve will define the same curve. Setting one of them to a
+ * constant, so as not to have to store it, means the other one will always suffice
+ * to describe the curve. For example, only storing the date for a known, constant
+ * value of the relevance is an efficient way of remembering this information (and
+ * to compare relevances together, as f is monotonically decreasing).
+ *
+ *** Choosing the function :
+ * Functions of the kind described above are standard exponential decay functions
+ * like the ones that govern atomic decay where the value at any given date can be
+ * computed uniformly from the value at a previous date and the time elapsed since
+ * that date. It is simple to picture this kind of function as one where after a
+ * given period of time called the half-life, the relevance value will have been
+ * halved. Decay of this kind is expressed in function of the previous value by
+ * functions like
+ * f(x, t) = x * F ^ (t / L)
+ * ...where x is the value, t is the elapsed time, L is the half-life (or more
+ * generally the F-th-life) and F the decay factor (typically 0.5, hence why L is
+ * usually called the half-life). The ^ symbol here is used for exponentiation.
+ * Or, starting at a given M for t = 0 :
+ * f(t) = M * F ^ (t / L)
+ *
+ * Because a line in the store needs to become irrelevant at some point but
+ * this class of functions never go to 0, a minimum cutoff has to be chosen to
+ * represent irrelevance. The simpler way of doing this is to simply add this
+ * minimum cutoff to the computation before and removing it after.
+ * Thus the function becomes :
+ * f(x, t) = ((x + K) * F ^ (t / L)) - K
+ * ...where K is the minimum cutoff, L the half-life, and F the factor between
+ * the original x and x after its half-life. Strictly speaking using the word
+ * "half-life" implies that F = 0.5, but the relation works for any value of F.
+ *
+ * It is easy enough to check that this function satisfies the stability
+ * relation that was given above for any value of F, L and K, which become
+ * parameters that can be defined at will.
+ *
+ * relevance
+ * 1.0 |
+ * |\
+ * | \
+ * | \ (this graph rendered with L = 75 days and K = 1/40)
+ * 0.75| ',
+ * | \
+ * | '.
+ * | \.
+ * | \
+ * 0.5 | '\
+ * | ''.
+ * | ''.
+ * | ''.
+ * 0.25| '''..
+ * | '''..
+ * | ''''....
+ * | '''''..........
+ * 0 +-------------------------------------------------------''''''''''----
+ * 0 50 100 150 200 250 300 350 400 days
+ *
+ *** Choosing the parameters
+ * The maximum M is an arbitrary parameter that simply scales the curve.
+ * The tradeoff for M is pretty simple : if the relevance is going to be an
+ * integer, the bigger M is the more precision there is in the relevance.
+ * However, values of M that are easy for humans to read are preferable to
+ * help debugging, and a suitably low value may be enough to ensure there
+ * won't be integer overflows in intermediate computations.
+ * A value of 1_000_000 probably is plenty for precision, while still in the
+ * low range of what ints can represent.
+ *
+ * F and L are parameters to be chosen arbitrarily and have an impact on how
+ * fast the relevance will be decaying at first, keeping in mind that
+ * the 400 days value and the cap stay the same. In simpler words, F and L
+ * define the steepness of the curve.
+ * To keep things simple (and familiar) F is arbitrarily chosen to be 0.5, and
+ * L is set to 200 days visually to achieve the desired effect. Refer to the
+ * illustration above to get a feel of how that feels.
+ *
+ * Moreover, the memory store works on an assumption that the relevance should
+ * be capped, and that an entry with capped relevance should decay in 400 days.
+ * This is on premises that the networks a device will need to remember the
+ * longest should be networks visited about once a year.
+ * For this reason, the relevance is at the maximum M 400 days before expiry :
+ * f(M, 400 days) = 0
+ * From replacing this with the value of the function, K can then be derived
+ * from the values of M, F and L :
+ * (M + K) * F ^ (t / L) - K = 0
+ * K = M * F ^ (400 days / L) / (1 - F ^ (400 days / L))
+ * Replacing with actual values this gives :
+ * K = 1_000_000 * 0.5 ^ (400 / 200) / (1 - 0.5 ^ (400 / 200))
+ * = 1_000_000 / 3 ≈ 333_333.3
+ * This ensures the function has the desired profile, the desired value at
+ * cap, and the desired value at expiry.
+ *
+ *** Useful relations
+ * Let's define the expiry time for any given relevance x as the interval of
+ * time such as :
+ * f(x, expiry) = 0
+ * which can be rewritten
+ * ((x + K) * F ^ (expiry / L)) = K
+ * ...giving an expression of the expiry in function of the relevance x as
+ * expiry = L * logF(K / (x + K))
+ * Conversely the relevance x can be expressed in function of the expiry as
+ * x = K / F ^ (expiry / L) - K
+ * These relations are useful in utility functions.
+ *
+ *** Bumping things up
+ * The last issue therefore is to decide how to bump up the relevance. The
+ * simple approach is to simply lift up the curve a little bit by a constant
+ * normalized amount, delaying the time of expiry. For example increasing
+ * the relevance by an amount I gives :
+ * x2 = x1 + I
+ * x2 and x1 correspond to two different expiry times expiry2 and expiry1,
+ * and replacing x1 and x2 in the relation above with their expression in
+ * function of the expiry comes :
+ * K / F ^ (expiry2 / L) - K = K / F ^ (expiry1 / L) - K + I
+ * which resolves to :
+ * expiry2 = L * logF(K / (I + K / F ^ (expiry1 / L)))
+ *
+ * In this implementation, the bump is defined as 1/25th of the cap for
+ * the relevance. This means a network will be remembered for the maximum
+ * period of 400 days if connected 25 times in succession not accounting
+ * for decay. Of course decay actually happens so it will take more than 25
+ * connections for any given network to actually reach the cap, but because
+ * decay is slow at first, it is a good estimate of how fast cap happens.
+ *
+ * Specifically, it gives the following four results :
+ * - A network that a device connects to once hits irrelevance about 32.7 days after
+ * it was first registered if never connected again.
+ * - A network that a device connects to once a day at a fixed hour will hit the cap
+ * on the 27th connection.
+ * - A network that a device connects to once a week at a fixed hour will hit the cap
+ * on the 57th connection.
+ * - A network that a device connects to every day for 7 straight days then never again
+ * expires 144 days after the last connection.
+ * These metrics tend to match pretty well the requirements.
+ */
+
+ // TODO : make these constants configurable at runtime. Don't forget to build it so that
+ // changes will wipe the database, migrate the values, or otherwise make sure the relevance
+ // values are still meaningful.
+
+ // How long, in milliseconds, is a capped relevance valid for, or in other
+ // words how many milliseconds after its relevance was set to RELEVANCE_CAP does
+ // any given line expire. 400 days.
+ @VisibleForTesting
+ public static final long CAPPED_RELEVANCE_LIFETIME_MS = 400L * 24 * 60 * 60 * 1000;
+
+ // The constant that represents a normalized 1.0 value for the relevance. In other words,
+ // the cap for the relevance. This is referred to as M in the explanation above.
+ @VisibleForTesting
+ public static final int CAPPED_RELEVANCE = 1_000_000;
+
+ // The decay factor. After a half-life, the relevance will have decayed by this value.
+ // This is referred to as F in the explanation above.
+ private static final double DECAY_FACTOR = 0.5;
+
+ // The half-life. After this time, the relevance will have decayed by a factor DECAY_FACTOR.
+ // This is referred to as L in the explanation above.
+ private static final long HALF_LIFE_MS = 200L * 24 * 60 * 60 * 1000;
+
+ // The value of the frame change. This is referred to as K in the explanation above.
+ private static final double IRRELEVANCE_FLOOR =
+ CAPPED_RELEVANCE * powF((double) CAPPED_RELEVANCE_LIFETIME_MS / HALF_LIFE_MS)
+ / (1 - powF((double) CAPPED_RELEVANCE_LIFETIME_MS / HALF_LIFE_MS));
+
+ // How much to bump the relevance by every time a line is written to.
+ @VisibleForTesting
+ public static final int RELEVANCE_BUMP = CAPPED_RELEVANCE / 25;
+
+ // Java doesn't include a function for the logarithm in an arbitrary base, so implement it
+ private static final double LOG_DECAY_FACTOR = Math.log(DECAY_FACTOR);
+ private static double logF(final double value) {
+ return Math.log(value) / LOG_DECAY_FACTOR;
+ }
+
+ // Utility function to get a power of the decay factor, to simplify the code.
+ private static double powF(final double value) {
+ return Math.pow(DECAY_FACTOR, value);
+ }
+
+ /**
+ * Compute the value of the relevance now given an expiry date.
+ *
+ * @param expiry the date at which the column in the database expires.
+ * @return the adjusted value of the relevance for this moment in time.
+ */
+ public static int computeRelevanceForNow(final long expiry) {
+ return computeRelevanceForTargetDate(expiry, System.currentTimeMillis());
+ }
+
+ /**
+ * Compute the value of the relevance at a given date from an expiry date.
+ *
+ * Because relevance decays with time, a relevance in the past corresponds to
+ * a different relevance later.
+ *
+ * Relevance is always a positive value. 0 means not relevant at all.
+ *
+ * See the explanation at the top of this file to get the justification for this
+ * computation.
+ *
+ * @param expiry the date at which the column in the database expires.
+ * @param target the target date to adjust the relevance to.
+ * @return the adjusted value of the relevance for the target moment.
+ */
+ public static int computeRelevanceForTargetDate(final long expiry, final long target) {
+ final long delay = expiry - target;
+ if (delay >= CAPPED_RELEVANCE_LIFETIME_MS) return CAPPED_RELEVANCE;
+ if (delay <= 0) return 0;
+ return (int) (IRRELEVANCE_FLOOR / powF((float) delay / HALF_LIFE_MS) - IRRELEVANCE_FLOOR);
+ }
+
+ /**
+ * Compute the expiry duration adjusted up for a new fresh write.
+ *
+ * Every time data is written to the memory store for a given line, the
+ * relevance is bumped up by a certain amount, which will boost the priority
+ * of this line for computation of group attributes, and delay (possibly
+ * indefinitely, if the line is accessed regularly) forgetting the data stored
+ * in that line.
+ * As opposed to bumpExpiryDate, this function uses a duration from now to expiry.
+ *
+ * See the explanation at the top of this file for a justification of this computation.
+ *
+ * @param oldExpiryDuration the old expiry duration in milliseconds from now.
+ * @return the expiry duration representing a bumped up relevance value.
+ */
+ public static long bumpExpiryDuration(final long oldExpiryDuration) {
+ // L * logF(K / (I + K / F ^ (expiry1 / L))), as documented above
+ final double divisionFactor = powF(((double) oldExpiryDuration) / HALF_LIFE_MS);
+ final double oldRelevance = IRRELEVANCE_FLOOR / divisionFactor;
+ final long newDuration =
+ (long) (HALF_LIFE_MS * logF(IRRELEVANCE_FLOOR / (RELEVANCE_BUMP + oldRelevance)));
+ return Math.min(newDuration, CAPPED_RELEVANCE_LIFETIME_MS);
+ }
+
+ /**
+ * Compute the new expiry date adjusted up for a new fresh write.
+ *
+ * Every time data is written to the memory store for a given line, the
+ * relevance is bumped up by a certain amount, which will boost the priority
+ * of this line for computation of group attributes, and delay (possibly
+ * indefinitely, if the line is accessed regularly) forgetting the data stored
+ * in that line.
+ * As opposed to bumpExpiryDuration, this function takes the old timestamp and returns the
+ * new timestamp.
+ *
+ * {@see bumpExpiryDuration}, and keep in mind that the bump depends on when this is called,
+ * because the relevance decays exponentially, therefore bumping up a high relevance (for a
+ * date far in the future) is less potent than bumping up a low relevance (for a date in
+ * a close future).
+ *
+ * @param oldExpiryDate the old date of expiration.
+ * @return the new expiration date after the relevance bump.
+ */
+ public static long bumpExpiryDate(final long oldExpiryDate) {
+ final long now = System.currentTimeMillis();
+ final long newDuration = bumpExpiryDuration(oldExpiryDate - now);
+ return now + newDuration;
+ }
+}
diff --git a/services/robotests/backup/src/com/android/server/backup/TransportManagerTest.java b/services/robotests/backup/src/com/android/server/backup/TransportManagerTest.java
index 7559560..9a6e003 100644
--- a/services/robotests/backup/src/com/android/server/backup/TransportManagerTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/TransportManagerTest.java
@@ -58,7 +58,9 @@
import com.android.server.backup.transport.TransportClient;
import com.android.server.backup.transport.TransportClientManager;
import com.android.server.backup.transport.TransportNotRegisteredException;
+import com.android.server.testing.shadows.ShadowApplicationPackageManager;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -66,6 +68,7 @@
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowPackageManager;
import java.util.ArrayList;
@@ -75,6 +78,7 @@
import java.util.stream.Stream;
@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowApplicationPackageManager.class})
@Presubmit
public class TransportManagerTest {
private static final String PACKAGE_A = "some.package.a";
@@ -102,6 +106,12 @@
mTransportB1 = genericTransport(PACKAGE_B, "TransportBaz");
}
+ /** Reset shadow state. */
+ @After
+ public void tearDown() throws Exception {
+ ShadowApplicationPackageManager.reset();
+ }
+
@Test
public void testRegisterTransports() throws Exception {
setUpPackage(PACKAGE_A, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
@@ -666,7 +676,8 @@
packageInfo.packageName = packageName;
packageInfo.applicationInfo = new ApplicationInfo();
packageInfo.applicationInfo.privateFlags = flags;
- mShadowPackageManager.addPackage(packageInfo);
+ mShadowPackageManager.installPackage(packageInfo);
+ ShadowApplicationPackageManager.addInstalledPackage(packageName, packageInfo);
}
private TransportManager createTransportManagerWithRegisteredTransports(
diff --git a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
index 3b7fa3d..427aed7 100644
--- a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
@@ -514,10 +514,14 @@
private void setUpForUpdateTransportAttributes() throws Exception {
mTransportComponent = mTransport.getTransportComponent();
String transportPackage = mTransportComponent.getPackageName();
+ PackageInfo packageInfo = getPackageInfo(transportPackage);
ShadowPackageManager shadowPackageManager = shadowOf(mContext.getPackageManager());
- shadowPackageManager.addPackage(transportPackage);
+ shadowPackageManager.installPackage(packageInfo);
shadowPackageManager.setPackagesForUid(PACKAGE_UID, transportPackage);
+ // Set up for user invocations on ApplicationPackageManager.
+ ShadowApplicationPackageManager.addInstalledPackage(transportPackage, packageInfo);
+ ShadowApplicationPackageManager.setPackageUid(transportPackage, PACKAGE_UID);
mTransportUid = mContext.getPackageManager().getPackageUid(transportPackage, 0);
}
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowApplicationPackageManager.java b/services/robotests/src/com/android/server/testing/shadows/ShadowApplicationPackageManager.java
index dc32209..ab121ed 100644
--- a/services/robotests/src/com/android/server/testing/shadows/ShadowApplicationPackageManager.java
+++ b/services/robotests/src/com/android/server/testing/shadows/ShadowApplicationPackageManager.java
@@ -38,6 +38,7 @@
extends org.robolectric.shadows.ShadowApplicationPackageManager {
private static final Map<String, PackageInfo> sPackageInfos = new ArrayMap<>();
private static final List<PackageInfo> sInstalledPackages = new ArrayList<>();
+ private static final Map<String, Integer> sPackageUids = new ArrayMap<>();
/**
* Registers the package {@code packageName} to be returned when invoking {@link
@@ -49,6 +50,14 @@
sInstalledPackages.add(packageInfo);
}
+ /**
+ * Sets the package uid {@code packageUid} for the package {@code packageName} to be returned
+ * when invoking {@link ApplicationPackageManager#getPackageUidAsUser(String, int, int)}.
+ */
+ public static void setPackageUid(String packageName, int packageUid) {
+ sPackageUids.put(packageName, packageUid);
+ }
+
@Override
protected PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId)
throws NameNotFoundException {
@@ -63,6 +72,15 @@
return sInstalledPackages;
}
+ @Override
+ protected int getPackageUidAsUser(String packageName, int flags, int userId)
+ throws NameNotFoundException {
+ if (!sPackageUids.containsKey(packageName)) {
+ throw new NameNotFoundException(packageName);
+ }
+ return sPackageUids.get(packageName);
+ }
+
/** Clear package state. */
@Resetter
public static void reset() {
diff --git a/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java b/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java
index c8e6782..4a48468 100644
--- a/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java
@@ -85,6 +85,7 @@
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
+import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -793,6 +794,7 @@
}
@Test
+ @FlakyTest(bugId = 114098433)
public void testAllListeners() throws Exception {
final AppStateTrackerTestable instance = newInstance();
callStart(instance);
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index f1cd0cd..57ee6dc 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -33,6 +33,7 @@
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
@@ -43,7 +44,12 @@
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
import android.app.AlarmManager;
+import android.app.AppGlobals;
+import android.app.IActivityManager;
+import android.app.IUidObserver;
import android.app.job.JobInfo;
import android.app.usage.UsageStatsManager;
import android.app.usage.UsageStatsManagerInternal;
@@ -56,13 +62,16 @@
import android.os.BatteryManagerInternal;
import android.os.Handler;
import android.os.Looper;
+import android.os.RemoteException;
import android.os.SystemClock;
+import android.util.SparseBooleanArray;
import androidx.test.runner.AndroidJUnit4;
import com.android.server.LocalServices;
import com.android.server.job.JobSchedulerService;
import com.android.server.job.JobSchedulerService.Constants;
+import com.android.server.job.JobStore;
import com.android.server.job.controllers.QuotaController.ExecutionStats;
import com.android.server.job.controllers.QuotaController.TimingSession;
@@ -96,9 +105,13 @@
private BroadcastReceiver mChargingReceiver;
private Constants mConstants;
private QuotaController mQuotaController;
+ private int mSourceUid;
+ private IUidObserver mUidObserver;
private MockitoSession mMockingSession;
@Mock
+ private ActivityManagerInternal mActivityMangerInternal;
+ @Mock
private AlarmManager mAlarmManager;
@Mock
private Context mContext;
@@ -107,6 +120,8 @@
@Mock
private UsageStatsManagerInternal mUsageStatsManager;
+ private JobStore mJobStore;
+
@Before
public void setUp() {
mMockingSession = mockitoSession()
@@ -123,8 +138,17 @@
when(mJobSchedulerService.getLock()).thenReturn(mJobSchedulerService);
when(mJobSchedulerService.getConstants()).thenReturn(mConstants);
// Called in QuotaController constructor.
+ IActivityManager activityManager = ActivityManager.getService();
+ spyOn(activityManager);
+ try {
+ doNothing().when(activityManager).registerUidObserver(any(), anyInt(), anyInt(), any());
+ } catch (RemoteException e) {
+ fail("registerUidObserver threw exception: " + e.getMessage());
+ }
when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
when(mContext.getSystemService(Context.ALARM_SERVICE)).thenReturn(mAlarmManager);
+ doReturn(mActivityMangerInternal)
+ .when(() -> LocalServices.getService(ActivityManagerInternal.class));
doReturn(mock(BatteryManagerInternal.class))
.when(() -> LocalServices.getService(BatteryManagerInternal.class));
doReturn(mUsageStatsManager)
@@ -132,6 +156,9 @@
// Used in JobStatus.
doReturn(mock(PackageManagerInternal.class))
.when(() -> LocalServices.getService(PackageManagerInternal.class));
+ // Used in QuotaController.Handler.
+ mJobStore = JobStore.initAndGetForTesting(mContext, mContext.getFilesDir());
+ when(mJobSchedulerService.getJobStore()).thenReturn(mJobStore);
// Freeze the clocks at 24 hours after this moment in time. Several tests create sessions
// in the past, and QuotaController sometimes floors values at 0, so if the test time
@@ -150,10 +177,23 @@
// Capture the listeners.
ArgumentCaptor<BroadcastReceiver> receiverCaptor =
ArgumentCaptor.forClass(BroadcastReceiver.class);
+ ArgumentCaptor<IUidObserver> uidObserverCaptor =
+ ArgumentCaptor.forClass(IUidObserver.class);
mQuotaController = new QuotaController(mJobSchedulerService);
verify(mContext).registerReceiver(receiverCaptor.capture(), any());
mChargingReceiver = receiverCaptor.getValue();
+ try {
+ verify(activityManager).registerUidObserver(
+ uidObserverCaptor.capture(),
+ eq(ActivityManager.UID_OBSERVER_PROCSTATE),
+ eq(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE),
+ any());
+ mUidObserver = uidObserverCaptor.getValue();
+ mSourceUid = AppGlobals.getPackageManager().getPackageUid(SOURCE_PACKAGE, 0, 0);
+ } catch (RemoteException e) {
+ fail(e.getMessage());
+ }
}
@After
@@ -182,6 +222,25 @@
mChargingReceiver.onReceive(mContext, intent);
}
+ private void setProcessState(int procState) {
+ try {
+ doReturn(procState).when(mActivityMangerInternal).getUidProcessState(mSourceUid);
+ SparseBooleanArray foregroundUids = mQuotaController.getForegroundUids();
+ spyOn(foregroundUids);
+ mUidObserver.onUidStateChanged(mSourceUid, procState, 0);
+ if (procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
+ verify(foregroundUids, timeout(SECOND_IN_MILLIS).times(1))
+ .put(eq(mSourceUid), eq(true));
+ assertTrue(foregroundUids.get(mSourceUid));
+ } else {
+ verify(foregroundUids, timeout(SECOND_IN_MILLIS).times(1)).delete(eq(mSourceUid));
+ assertFalse(foregroundUids.get(mSourceUid));
+ }
+ } catch (RemoteException e) {
+ fail("registerUidObserver threw exception: " + e.getMessage());
+ }
+ }
+
private void setStandbyBucket(int bucketIndex) {
int bucket;
switch (bucketIndex) {
@@ -204,9 +263,18 @@
anyLong())).thenReturn(bucket);
}
- private void setStandbyBucket(int bucketIndex, JobStatus job) {
+ private void setStandbyBucket(int bucketIndex, JobStatus... jobs) {
setStandbyBucket(bucketIndex);
- job.setStandbyBucket(bucketIndex);
+ for (JobStatus job : jobs) {
+ job.setStandbyBucket(bucketIndex);
+ }
+ }
+
+ private void trackJobs(JobStatus... jobs) {
+ for (JobStatus job : jobs) {
+ mJobStore.add(job);
+ mQuotaController.maybeStartTrackingJobLocked(job, null);
+ }
}
private JobStatus createJobStatus(String testTag, int jobId) {
@@ -214,8 +282,11 @@
new ComponentName(mContext, "TestQuotaJobService"))
.setMinimumLatency(Math.abs(jobId) + 1)
.build();
- return JobStatus.createFromJobInfo(
+ JobStatus js = JobStatus.createFromJobInfo(
jobInfo, CALLING_UID, SOURCE_PACKAGE, SOURCE_USER_ID, testTag);
+ // Make sure tests aren't passing just because the default bucket is likely ACTIVE.
+ js.setStandbyBucket(FREQUENT_INDEX);
+ return js;
}
private TimingSession createTimingSession(long start, long duration, int count) {
@@ -709,6 +780,7 @@
verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
JobStatus jobStatus = createJobStatus("testMaybeScheduleStartAlarmLocked_Active", 1);
+ setStandbyBucket(standbyBucket, jobStatus);
mQuotaController.maybeStartTrackingJobLocked(jobStatus, null);
mQuotaController.prepareForExecutionLocked(jobStatus);
advanceElapsedClock(5 * MINUTE_IN_MILLIS);
@@ -1339,19 +1411,23 @@
setDischarging();
JobStatus jobStatus = createJobStatus("testTimerTracking_AllForeground", 1);
- jobStatus.uidActive = true;
+ setProcessState(ActivityManager.PROCESS_STATE_TOP);
mQuotaController.maybeStartTrackingJobLocked(jobStatus, null);
assertNull(mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
mQuotaController.prepareForExecutionLocked(jobStatus);
advanceElapsedClock(5 * SECOND_IN_MILLIS);
+ // Change to a state that should still be considered foreground.
+ setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+ advanceElapsedClock(5 * SECOND_IN_MILLIS);
mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false);
assertNull(mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
}
/**
- * Tests that Timers properly track overlapping foreground and background jobs.
+ * Tests that Timers properly track sessions when switching between foreground and background
+ * states.
*/
@Test
public void testTimerTracking_ForegroundAndBackground() {
@@ -1360,7 +1436,6 @@
JobStatus jobBg1 = createJobStatus("testTimerTracking_ForegroundAndBackground", 1);
JobStatus jobBg2 = createJobStatus("testTimerTracking_ForegroundAndBackground", 2);
JobStatus jobFg3 = createJobStatus("testTimerTracking_ForegroundAndBackground", 3);
- jobFg3.uidActive = true;
mQuotaController.maybeStartTrackingJobLocked(jobBg1, null);
mQuotaController.maybeStartTrackingJobLocked(jobBg2, null);
mQuotaController.maybeStartTrackingJobLocked(jobFg3, null);
@@ -1368,6 +1443,7 @@
List<TimingSession> expected = new ArrayList<>();
// UID starts out inactive.
+ setProcessState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
long start = JobSchedulerService.sElapsedRealtimeClock.millis();
mQuotaController.prepareForExecutionLocked(jobBg1);
advanceElapsedClock(10 * SECOND_IN_MILLIS);
@@ -1379,48 +1455,223 @@
// Bg job starts while inactive, spans an entire active session, and ends after the
// active session.
- // Fg job starts after the bg job and ends before the bg job.
- // Entire bg job duration should be counted since it started before active session. However,
- // count should only be 1 since Timer shouldn't count fg jobs.
+ // App switching to foreground state then fg job starts.
+ // App remains in foreground state after coming to foreground, so there should only be one
+ // session.
start = JobSchedulerService.sElapsedRealtimeClock.millis();
mQuotaController.maybeStartTrackingJobLocked(jobBg2, null);
mQuotaController.prepareForExecutionLocked(jobBg2);
advanceElapsedClock(10 * SECOND_IN_MILLIS);
+ expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
+ setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
mQuotaController.prepareForExecutionLocked(jobFg3);
advanceElapsedClock(10 * SECOND_IN_MILLIS);
mQuotaController.maybeStopTrackingJobLocked(jobFg3, null, false);
advanceElapsedClock(10 * SECOND_IN_MILLIS);
mQuotaController.maybeStopTrackingJobLocked(jobBg2, null, false);
- expected.add(createTimingSession(start, 30 * SECOND_IN_MILLIS, 1));
assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
advanceElapsedClock(SECOND_IN_MILLIS);
// Bg job 1 starts, then fg job starts. Bg job 1 job ends. Shortly after, uid goes
// "inactive" and then bg job 2 starts. Then fg job ends.
- // This should result in two TimingSessions with a count of one each.
+ // This should result in two TimingSessions:
+ // * The first should have a count of 1
+ // * The second should have a count of 2 since it will include both jobs
start = JobSchedulerService.sElapsedRealtimeClock.millis();
mQuotaController.maybeStartTrackingJobLocked(jobBg1, null);
mQuotaController.maybeStartTrackingJobLocked(jobBg2, null);
mQuotaController.maybeStartTrackingJobLocked(jobFg3, null);
+ setProcessState(ActivityManager.PROCESS_STATE_LAST_ACTIVITY);
mQuotaController.prepareForExecutionLocked(jobBg1);
advanceElapsedClock(10 * SECOND_IN_MILLIS);
+ expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
+ setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
mQuotaController.prepareForExecutionLocked(jobFg3);
advanceElapsedClock(10 * SECOND_IN_MILLIS);
mQuotaController.maybeStopTrackingJobLocked(jobBg1, jobBg1, true);
- expected.add(createTimingSession(start, 20 * SECOND_IN_MILLIS, 1));
advanceElapsedClock(10 * SECOND_IN_MILLIS); // UID "inactive" now
start = JobSchedulerService.sElapsedRealtimeClock.millis();
+ setProcessState(ActivityManager.PROCESS_STATE_TOP_SLEEPING);
mQuotaController.prepareForExecutionLocked(jobBg2);
advanceElapsedClock(10 * SECOND_IN_MILLIS);
mQuotaController.maybeStopTrackingJobLocked(jobFg3, null, false);
advanceElapsedClock(10 * SECOND_IN_MILLIS);
mQuotaController.maybeStopTrackingJobLocked(jobBg2, null, false);
- expected.add(createTimingSession(start, 20 * SECOND_IN_MILLIS, 1));
+ expected.add(createTimingSession(start, 20 * SECOND_IN_MILLIS, 2));
assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
}
/**
+ * Tests that Timers properly track overlapping top and background jobs.
+ */
+ @Test
+ public void testTimerTracking_TopAndNonTop() {
+ setDischarging();
+
+ JobStatus jobBg1 = createJobStatus("testTimerTracking_TopAndNonTop", 1);
+ JobStatus jobBg2 = createJobStatus("testTimerTracking_TopAndNonTop", 2);
+ JobStatus jobFg1 = createJobStatus("testTimerTracking_TopAndNonTop", 3);
+ JobStatus jobTop = createJobStatus("testTimerTracking_TopAndNonTop", 4);
+ mQuotaController.maybeStartTrackingJobLocked(jobBg1, null);
+ mQuotaController.maybeStartTrackingJobLocked(jobBg2, null);
+ mQuotaController.maybeStartTrackingJobLocked(jobFg1, null);
+ mQuotaController.maybeStartTrackingJobLocked(jobTop, null);
+ assertNull(mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+ List<TimingSession> expected = new ArrayList<>();
+
+ // UID starts out inactive.
+ setProcessState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
+ long start = JobSchedulerService.sElapsedRealtimeClock.millis();
+ mQuotaController.prepareForExecutionLocked(jobBg1);
+ advanceElapsedClock(10 * SECOND_IN_MILLIS);
+ mQuotaController.maybeStopTrackingJobLocked(jobBg1, jobBg1, true);
+ expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
+ assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+ advanceElapsedClock(SECOND_IN_MILLIS);
+
+ // Bg job starts while inactive, spans an entire active session, and ends after the
+ // active session.
+ // App switching to top state then fg job starts.
+ // App remains in top state after coming to top, so there should only be one
+ // session.
+ start = JobSchedulerService.sElapsedRealtimeClock.millis();
+ mQuotaController.maybeStartTrackingJobLocked(jobBg2, null);
+ mQuotaController.prepareForExecutionLocked(jobBg2);
+ advanceElapsedClock(10 * SECOND_IN_MILLIS);
+ expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
+ setProcessState(ActivityManager.PROCESS_STATE_TOP);
+ mQuotaController.prepareForExecutionLocked(jobTop);
+ advanceElapsedClock(10 * SECOND_IN_MILLIS);
+ mQuotaController.maybeStopTrackingJobLocked(jobTop, null, false);
+ advanceElapsedClock(10 * SECOND_IN_MILLIS);
+ mQuotaController.maybeStopTrackingJobLocked(jobBg2, null, false);
+ assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+ advanceElapsedClock(SECOND_IN_MILLIS);
+
+ // Bg job 1 starts, then top job starts. Bg job 1 job ends. Then app goes to
+ // foreground_service and a new job starts. Shortly after, uid goes
+ // "inactive" and then bg job 2 starts. Then top job ends, followed by bg and fg jobs.
+ // This should result in two TimingSessions:
+ // * The first should have a count of 1
+ // * The second should have a count of 2, which accounts for the bg2 and fg, but not top
+ // jobs.
+ start = JobSchedulerService.sElapsedRealtimeClock.millis();
+ mQuotaController.maybeStartTrackingJobLocked(jobBg1, null);
+ mQuotaController.maybeStartTrackingJobLocked(jobBg2, null);
+ mQuotaController.maybeStartTrackingJobLocked(jobTop, null);
+ setProcessState(ActivityManager.PROCESS_STATE_LAST_ACTIVITY);
+ mQuotaController.prepareForExecutionLocked(jobBg1);
+ advanceElapsedClock(10 * SECOND_IN_MILLIS);
+ expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
+ setProcessState(ActivityManager.PROCESS_STATE_TOP);
+ mQuotaController.prepareForExecutionLocked(jobTop);
+ advanceElapsedClock(10 * SECOND_IN_MILLIS);
+ mQuotaController.maybeStopTrackingJobLocked(jobBg1, jobBg1, true);
+ advanceElapsedClock(5 * SECOND_IN_MILLIS);
+ setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+ mQuotaController.prepareForExecutionLocked(jobFg1);
+ advanceElapsedClock(5 * SECOND_IN_MILLIS);
+ setProcessState(ActivityManager.PROCESS_STATE_TOP);
+ advanceElapsedClock(10 * SECOND_IN_MILLIS); // UID "inactive" now
+ start = JobSchedulerService.sElapsedRealtimeClock.millis();
+ setProcessState(ActivityManager.PROCESS_STATE_TOP_SLEEPING);
+ mQuotaController.prepareForExecutionLocked(jobBg2);
+ advanceElapsedClock(10 * SECOND_IN_MILLIS);
+ mQuotaController.maybeStopTrackingJobLocked(jobTop, null, false);
+ advanceElapsedClock(10 * SECOND_IN_MILLIS);
+ mQuotaController.maybeStopTrackingJobLocked(jobBg2, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobFg1, null, false);
+ expected.add(createTimingSession(start, 20 * SECOND_IN_MILLIS, 2));
+ assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+ }
+
+ /**
+ * Tests that TOP jobs aren't stopped when an app runs out of quota.
+ */
+ @Test
+ public void testTracking_OutOfQuota_ForegroundAndBackground() {
+ setDischarging();
+
+ JobStatus jobBg = createJobStatus("testTracking_OutOfQuota_ForegroundAndBackground", 1);
+ JobStatus jobTop = createJobStatus("testTracking_OutOfQuota_ForegroundAndBackground", 2);
+ trackJobs(jobBg, jobTop);
+ setStandbyBucket(WORKING_INDEX, jobTop, jobBg); // 2 hour window
+ // Now the package only has 20 seconds to run.
+ final long remainingTimeMs = 20 * SECOND_IN_MILLIS;
+ mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+ createTimingSession(
+ JobSchedulerService.sElapsedRealtimeClock.millis() - HOUR_IN_MILLIS,
+ 10 * MINUTE_IN_MILLIS - remainingTimeMs, 1));
+
+ InOrder inOrder = inOrder(mJobSchedulerService);
+
+ // UID starts out inactive.
+ setProcessState(ActivityManager.PROCESS_STATE_SERVICE);
+ // Start the job.
+ mQuotaController.prepareForExecutionLocked(jobBg);
+ advanceElapsedClock(remainingTimeMs / 2);
+ // New job starts after UID is in the foreground. Since the app is now in the foreground, it
+ // should continue to have remainingTimeMs / 2 time remaining.
+ setProcessState(ActivityManager.PROCESS_STATE_TOP);
+ mQuotaController.prepareForExecutionLocked(jobTop);
+ advanceElapsedClock(remainingTimeMs);
+
+ // Wait for some extra time to allow for job processing.
+ inOrder.verify(mJobSchedulerService,
+ timeout(remainingTimeMs + 2 * SECOND_IN_MILLIS).times(0))
+ .onControllerStateChanged();
+ assertEquals(remainingTimeMs / 2, mQuotaController.getRemainingExecutionTimeLocked(jobBg));
+ assertEquals(remainingTimeMs / 2, mQuotaController.getRemainingExecutionTimeLocked(jobTop));
+ // Go to a background state.
+ setProcessState(ActivityManager.PROCESS_STATE_TOP_SLEEPING);
+ advanceElapsedClock(remainingTimeMs / 2 + 1);
+ inOrder.verify(mJobSchedulerService,
+ timeout(remainingTimeMs / 2 + 2 * SECOND_IN_MILLIS).times(1))
+ .onControllerStateChanged();
+ // Top job should still be allowed to run.
+ assertFalse(jobBg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+ assertTrue(jobTop.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+
+ // New jobs to run.
+ JobStatus jobBg2 = createJobStatus("testTracking_OutOfQuota_ForegroundAndBackground", 3);
+ JobStatus jobTop2 = createJobStatus("testTracking_OutOfQuota_ForegroundAndBackground", 4);
+ JobStatus jobFg = createJobStatus("testTracking_OutOfQuota_ForegroundAndBackground", 5);
+ setStandbyBucket(WORKING_INDEX, jobBg2, jobTop2, jobFg);
+
+ advanceElapsedClock(20 * SECOND_IN_MILLIS);
+ setProcessState(ActivityManager.PROCESS_STATE_TOP);
+ inOrder.verify(mJobSchedulerService, timeout(SECOND_IN_MILLIS).times(1))
+ .onControllerStateChanged();
+ trackJobs(jobFg, jobTop);
+ mQuotaController.prepareForExecutionLocked(jobTop);
+ assertTrue(jobTop.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+ assertTrue(jobFg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+ assertTrue(jobBg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+
+ // App still in foreground so everything should be in quota.
+ advanceElapsedClock(20 * SECOND_IN_MILLIS);
+ setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+ assertTrue(jobTop.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+ assertTrue(jobFg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+ assertTrue(jobBg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+
+ advanceElapsedClock(20 * SECOND_IN_MILLIS);
+ setProcessState(ActivityManager.PROCESS_STATE_SERVICE);
+ inOrder.verify(mJobSchedulerService, timeout(SECOND_IN_MILLIS).times(1))
+ .onControllerStateChanged();
+ // App is now in background and out of quota. Fg should now change to out of quota since it
+ // wasn't started. Top should remain in quota since it started when the app was in TOP.
+ assertTrue(jobTop.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+ assertFalse(jobFg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+ assertFalse(jobBg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+ trackJobs(jobBg2);
+ assertFalse(jobBg2.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+ }
+
+ /**
* Tests that a job is properly updated and JobSchedulerService is notified when a job reaches
* its quota.
*/
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
index 8b0e8ab..eb9b98e 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
@@ -30,6 +30,7 @@
import androidx.test.filters.SmallTest;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -147,6 +148,7 @@
mTestLooper.dispatchAll();
}
+ @Ignore("b/120845532")
@Test
public void arcInitiation_requestActiveSource() {
mSendCecCommandSuccess = true;
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java
index 93a09dc..5d8131f 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java
@@ -40,7 +40,6 @@
import com.android.server.hdmi.HdmiCecController.AllocateAddressCallback;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -142,7 +141,6 @@
assertEquals(ADDR_UNREGISTERED, mLogicalAddress);
}
- @Ignore("b/110413065 Support multiple device types 4 and 5.")
@Test
public void testAllocatLogicalAddress_PlaybackPreferredNotOccupied() {
mHdmiCecController.allocateLogicalAddress(DEVICE_PLAYBACK, ADDR_PLAYBACK_1, mCallback);
@@ -158,7 +156,6 @@
assertEquals(ADDR_PLAYBACK_2, mLogicalAddress);
}
- @Ignore("b/110413065 Support multiple device types 4 and 5.")
@Test
public void testAllocatLogicalAddress_PlaybackNoPreferredNotOcuppied() {
mHdmiCecController.allocateLogicalAddress(DEVICE_PLAYBACK, ADDR_UNREGISTERED, mCallback);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
index 3b51a2a..3a6cdc2 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
@@ -21,6 +21,7 @@
import static com.android.server.hdmi.Constants.ADDR_AUDIO_SYSTEM;
import static com.android.server.hdmi.Constants.ADDR_BROADCAST;
import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_1;
+import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_2;
import static com.android.server.hdmi.Constants.ADDR_TUNER_1;
import static com.android.server.hdmi.Constants.ADDR_TV;
import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
@@ -29,9 +30,9 @@
import static com.google.common.truth.Truth.assertThat;
import android.hardware.hdmi.HdmiDeviceInfo;
+import android.hardware.hdmi.HdmiPortInfo;
import android.media.AudioManager;
import android.os.Looper;
-import android.os.SystemProperties;
import android.os.test.TestLooper;
import androidx.test.InstrumentationRegistry;
@@ -46,7 +47,6 @@
import org.junit.runners.JUnit4;
import java.util.ArrayList;
-
@SmallTest
@RunWith(JUnit4.class)
/** Tests for {@link HdmiCecLocalDeviceAudioSystem} class. */
@@ -67,9 +67,15 @@
private int mMusicVolume;
private int mMusicMaxVolume;
private boolean mMusicMute;
- private int mAvrPhysicalAddress;
+ private static final int SELF_PHYSICAL_ADDRESS = 0x2000;
+ private static final int HDMI_1_PHYSICAL_ADDRESS = 0x2100;
+ private static final int HDMI_2_PHYSICAL_ADDRESS = 0x2200;
+ private static final int HDMI_3_PHYSICAL_ADDRESS = 0x2300;
private int mInvokeDeviceEventState;
private HdmiDeviceInfo mDeviceInfo;
+ private boolean mMutingEnabled;
+ private boolean mArcSupport;
+ private HdmiPortInfo[] mHdmiPortInfo;
@Before
public void setUp() {
@@ -141,9 +147,20 @@
}
@Override
- int pathToPortId(int path) {
- // port id is not useful for the test right now
- return 1;
+ void writeStringSetting(String key, String value) {
+ // do nothing
+ }
+
+ @Override
+ boolean readBooleanSetting(String key, boolean defVal) {
+ switch (key) {
+ case Constants.PROPERTY_SYSTEM_AUDIO_MODE_MUTING_ENABLE:
+ return mMutingEnabled;
+ case Constants.PROPERTY_ARC_SUPPORT:
+ return mArcSupport;
+ default:
+ return defVal;
+ }
}
};
@@ -154,11 +171,17 @@
void setIsActiveSource(boolean on) {
mIsActiveSource = on;
}
+
+ @Override
+ protected int getPreferredAddress() {
+ return ADDR_PLAYBACK_1;
+ }
};
mHdmiCecLocalDeviceAudioSystem.init();
mHdmiCecLocalDevicePlayback.init();
mHdmiControlService.setIoLooper(mMyLooper);
mNativeWrapper = new FakeNativeWrapper();
+ mNativeWrapper.setPhysicalAddress(SELF_PHYSICAL_ADDRESS);
mHdmiCecController =
HdmiCecController.createWithNativeWrapper(mHdmiControlService, mNativeWrapper);
mHdmiControlService.setCecController(mHdmiCecController);
@@ -166,15 +189,28 @@
mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService));
mLocalDevices.add(mHdmiCecLocalDeviceAudioSystem);
mLocalDevices.add(mHdmiCecLocalDevicePlayback);
+ mHdmiCecLocalDeviceAudioSystem.setRoutingControlFeatureEnables(true);
+ mHdmiPortInfo = new HdmiPortInfo[4];
+ mHdmiPortInfo[0] =
+ new HdmiPortInfo(
+ 0, HdmiPortInfo.PORT_INPUT, SELF_PHYSICAL_ADDRESS, true, false, false);
+ mHdmiPortInfo[1] =
+ new HdmiPortInfo(
+ 2, HdmiPortInfo.PORT_INPUT, HDMI_1_PHYSICAL_ADDRESS, true, false, false);
+ mHdmiPortInfo[2] =
+ new HdmiPortInfo(
+ 1, HdmiPortInfo.PORT_INPUT, HDMI_2_PHYSICAL_ADDRESS, true, false, false);
+ mHdmiPortInfo[3] =
+ new HdmiPortInfo(
+ 4, HdmiPortInfo.PORT_INPUT, HDMI_3_PHYSICAL_ADDRESS, true, false, false);
+ mNativeWrapper.setPortInfo(mHdmiPortInfo);
mHdmiControlService.initPortInfo();
// No TV device interacts with AVR so system audio control won't be turned on here
mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
mTestLooper.dispatchAll();
mNativeWrapper.clearResultMessages();
- mAvrPhysicalAddress = 0x2000;
- mNativeWrapper.setPhysicalAddress(mAvrPhysicalAddress);
- SystemProperties.set(Constants.PROPERTY_ARC_SUPPORT, "true");
- SystemProperties.set(Constants.PROPERTY_SYSTEM_AUDIO_MODE_MUTING_ENABLE, "true");
+ mMutingEnabled = true;
+ mArcSupport = true;
mInvokeDeviceEventState = 0;
mDeviceInfo = null;
}
@@ -244,6 +280,8 @@
assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
}
+ // Testing device has sadConfig.xml
+ @Ignore("b/120845532")
@Test
public void handleRequestShortAudioDescriptor_noAudioDeviceInfo() throws Exception {
HdmiCecMessage expectedMessage =
@@ -414,51 +452,6 @@
}
@Test
- public void pathToPort_isMe() throws Exception {
- int targetPhysicalAddress = 0x1000;
- mNativeWrapper.setPhysicalAddress(0x1000);
- assertThat(mHdmiCecLocalDeviceAudioSystem
- .getLocalPortFromPhysicalAddress(targetPhysicalAddress))
- .isEqualTo(0);
- }
-
- @Test
- public void pathToPort_isBelow() throws Exception {
- int targetPhysicalAddress = 0x1100;
- mNativeWrapper.setPhysicalAddress(0x1000);
- assertThat(mHdmiCecLocalDeviceAudioSystem
- .getLocalPortFromPhysicalAddress(targetPhysicalAddress))
- .isEqualTo(1);
- }
-
- @Test
- public void pathToPort_neitherMeNorBelow() throws Exception {
- int targetPhysicalAddress = 0x3000;
- mNativeWrapper.setPhysicalAddress(0x2000);
- assertThat(mHdmiCecLocalDeviceAudioSystem
- .getLocalPortFromPhysicalAddress(targetPhysicalAddress))
- .isEqualTo(-1);
-
- targetPhysicalAddress = 0x2200;
- mNativeWrapper.setPhysicalAddress(0x3300);
- assertThat(mHdmiCecLocalDeviceAudioSystem
- .getLocalPortFromPhysicalAddress(targetPhysicalAddress))
- .isEqualTo(-1);
-
- targetPhysicalAddress = 0x2213;
- mNativeWrapper.setPhysicalAddress(0x2212);
- assertThat(mHdmiCecLocalDeviceAudioSystem
- .getLocalPortFromPhysicalAddress(targetPhysicalAddress))
- .isEqualTo(-1);
-
- targetPhysicalAddress = 0x2340;
- mNativeWrapper.setPhysicalAddress(0x2310);
- assertThat(mHdmiCecLocalDeviceAudioSystem
- .getLocalPortFromPhysicalAddress(targetPhysicalAddress))
- .isEqualTo(-1);
- }
-
- @Test
public void handleRequestArcInitiate_isNotDirectConnectedToTv() throws Exception {
HdmiCecMessage message =
HdmiCecMessageBuilder.buildRequestArcInitiation(ADDR_TV, ADDR_AUDIO_SYSTEM);
@@ -530,7 +523,7 @@
ADDR_TV,
Constants.MESSAGE_REQUEST_ARC_INITIATION,
Constants.ABORT_UNRECOGNIZED_OPCODE);
- SystemProperties.set(Constants.PROPERTY_ARC_SUPPORT, "false");
+ mArcSupport = false;
assertThat(mHdmiCecLocalDeviceAudioSystem.handleRequestArcInitiate(message)).isTrue();
mTestLooper.dispatchAll();
@@ -541,7 +534,7 @@
HdmiCecMessage message =
HdmiCecMessageBuilder.buildSystemAudioModeRequest(
ADDR_TUNER_1, ADDR_AUDIO_SYSTEM,
- mAvrPhysicalAddress, true);
+ SELF_PHYSICAL_ADDRESS, true);
HdmiCecMessage expectedMessage =
HdmiCecMessageBuilder.buildFeatureAbortCommand(
ADDR_AUDIO_SYSTEM,
@@ -559,7 +552,7 @@
HdmiCecMessage message =
HdmiCecMessageBuilder.buildSystemAudioModeRequest(
ADDR_TUNER_1, ADDR_AUDIO_SYSTEM,
- mAvrPhysicalAddress, true);
+ SELF_PHYSICAL_ADDRESS, true);
HdmiCecMessage expectedMessage =
HdmiCecMessageBuilder.buildSetSystemAudioMode(
ADDR_AUDIO_SYSTEM, Constants.ADDR_BROADCAST, true);
@@ -585,15 +578,14 @@
.isEqualTo(expectedActiveSource);
}
- @Ignore("b/110413065 Support multiple device types 4 and 5.")
@Test
public void handleRoutingChange_currentActivePortIsHome() {
HdmiCecMessage message =
- HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x3000, mAvrPhysicalAddress);
+ HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x3000, SELF_PHYSICAL_ADDRESS);
HdmiCecMessage expectedMessage =
- HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1, mAvrPhysicalAddress);
- ActiveSource expectedActiveSource = ActiveSource.of(ADDR_PLAYBACK_1, mAvrPhysicalAddress);
+ HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1, SELF_PHYSICAL_ADDRESS);
+ ActiveSource expectedActiveSource = ActiveSource.of(ADDR_PLAYBACK_1, SELF_PHYSICAL_ADDRESS);
int expectedLocalActivePort = Constants.CEC_SWITCH_HOME;
assertThat(mHdmiCecLocalDeviceAudioSystem.handleRoutingChange(message)).isTrue();
@@ -608,17 +600,18 @@
@Test
public void handleRoutingInformation_currentActivePortIsHDMI1() {
HdmiCecMessage message =
- HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV, 0x2000);
- mHdmiCecLocalDeviceAudioSystem.setRoutingPort(Constants.CEC_SWITCH_HDMI1);
+ HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV, SELF_PHYSICAL_ADDRESS);
+ mHdmiCecLocalDeviceAudioSystem.setRoutingPort(mHdmiPortInfo[1].getId());
HdmiCecMessage expectedMessage =
- HdmiCecMessageBuilder.buildRoutingInformation(ADDR_AUDIO_SYSTEM, 0x2100);
+ HdmiCecMessageBuilder.buildRoutingInformation(
+ ADDR_AUDIO_SYSTEM, HDMI_1_PHYSICAL_ADDRESS);
assertThat(mHdmiCecLocalDeviceAudioSystem.handleRoutingInformation(message)).isTrue();
mTestLooper.dispatchAll();
assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
}
- @Ignore("b/110413065 Support multiple device types 4 and 5.")
+ @Ignore("b/120845532")
@Test
public void handleRoutingChange_homeIsActive_playbackSendActiveSource() {
HdmiCecMessage message =
@@ -667,7 +660,7 @@
mHdmiCecLocalDeviceAudioSystem.addDeviceInfo(oldDevice);
HdmiDeviceInfo differentDevice = new HdmiDeviceInfo(
- ADDR_PLAYBACK_1, 0x2100, 4, HdmiDeviceInfo.DEVICE_PLAYBACK,
+ ADDR_PLAYBACK_1, 0x2300, 4, HdmiDeviceInfo.DEVICE_PLAYBACK,
Constants.UNKNOWN_VENDOR_ID, HdmiUtils.getDefaultDeviceName(ADDR_PLAYBACK_1));
mHdmiCecLocalDeviceAudioSystem.updateCecDevice(differentDevice);
@@ -686,14 +679,13 @@
mHdmiCecLocalDeviceAudioSystem.addDeviceInfo(oldDevice);
HdmiDeviceInfo differentDevice = new HdmiDeviceInfo(
- ADDR_PLAYBACK_1, 0x2200, 1, HdmiDeviceInfo.DEVICE_PLAYBACK,
- Constants.UNKNOWN_VENDOR_ID, HdmiUtils.getDefaultDeviceName(ADDR_PLAYBACK_1));
+ ADDR_PLAYBACK_2, 0x2200, 1, HdmiDeviceInfo.DEVICE_PLAYBACK,
+ Constants.UNKNOWN_VENDOR_ID, HdmiUtils.getDefaultDeviceName(ADDR_PLAYBACK_2));
HdmiCecMessage reportPhysicalAddress = HdmiCecMessageBuilder
.buildReportPhysicalAddressCommand(
- ADDR_PLAYBACK_1, 0x2200, HdmiDeviceInfo.DEVICE_PLAYBACK);
+ ADDR_PLAYBACK_2, 0x2200, HdmiDeviceInfo.DEVICE_PLAYBACK);
mHdmiCecLocalDeviceAudioSystem.handleReportPhysicalAddress(reportPhysicalAddress);
- mHdmiCecLocalDeviceAudioSystem.addDeviceInfo(oldDevice);
mTestLooper.dispatchAll();
assertThat(mDeviceInfo).isEqualTo(differentDevice);
assertThat(mHdmiCecLocalDeviceAudioSystem
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
index 792c617..feae4ee 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -81,7 +81,8 @@
mNativeWrapper.setPhysicalAddress(mPlaybackPhysicalAddress);
}
- @Ignore
+ // Playback device does not handle routing control related feature right now
+ @Ignore("b/120845532")
@Test
public void handleSetStreamPath_underCurrentDevice() {
assertThat(mHdmiCecLocalDevicePlayback.getLocalActivePath()).isEqualTo(0);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
index 67ce13f..1f66074 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -179,6 +179,7 @@
@Test
public void pathToPort_pathExists_weAreNonTv() {
mNativeWrapper.setPhysicalAddress(0x2000);
+ mHdmiControlService.initPortInfo();
assertThat(mHdmiControlService.pathToPortId(0x2120)).isEqualTo(1);
assertThat(mHdmiControlService.pathToPortId(0x2234)).isEqualTo(2);
}
@@ -186,6 +187,7 @@
@Test
public void pathToPort_pathExists_weAreTv() {
mNativeWrapper.setPhysicalAddress(0x0000);
+ mHdmiControlService.initPortInfo();
assertThat(mHdmiControlService.pathToPortId(0x2120)).isEqualTo(3);
assertThat(mHdmiControlService.pathToPortId(0x3234)).isEqualTo(4);
}
@@ -193,6 +195,7 @@
@Test
public void pathToPort_pathInvalid() {
mNativeWrapper.setPhysicalAddress(0x2000);
+ mHdmiControlService.initPortInfo();
assertThat(mHdmiControlService.pathToPortId(0x1000)).isEqualTo(Constants.INVALID_PORT_ID);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiUtilsTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiUtilsTest.java
new file mode 100644
index 0000000..985c647
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiUtilsTest.java
@@ -0,0 +1,146 @@
+/*
+ * 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.server.hdmi;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.util.Slog;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.server.hdmi.HdmiUtils.CodecSad;
+import com.android.server.hdmi.HdmiUtils.DeviceConfig;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+
+@SmallTest
+@RunWith(JUnit4.class)
+/** Tests for {@link HdmiUtils} class. */
+public class HdmiUtilsTest {
+
+ private static final String TAG = "HdmiUtilsTest";
+
+ private final String mExampleXML =
+ "<!-- A sample Short Audio Descriptor configuration xml -->"
+ + "<config version=\"1.0\" xmlns:xi=\"http://www.w3.org/2001/XInclude\">"
+ + "<device type=\"VX_AUDIO_DEVICE_IN_HDMI_ARC\">"
+ + "<supportedFormat format=\"AUDIO_FORMAT_LPCM\" descriptor=\"011a03\"/>"
+ + "<supportedFormat format=\"AUDIO_FORMAT_DD\" descriptor=\"0d0506\"/>"
+ + "</device>"
+ + "<device type=\"AUDIO_DEVICE_IN_SPDIF\">"
+ + "<supportedFormat format=\"AUDIO_FORMAT_LPCM\" descriptor=\"010203\"/>"
+ + "<supportedFormat format=\"AUDIO_FORMAT_DD\" descriptor=\"040506\"/>"
+ + "</device>"
+ + "</config>";
+
+ @Test
+ public void pathToPort_isMe() {
+ int targetPhysicalAddress = 0x1000;
+ int myPhysicalAddress = 0x1000;
+ assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+ targetPhysicalAddress, myPhysicalAddress)).isEqualTo(
+ HdmiUtils.TARGET_SAME_PHYSICAL_ADDRESS);
+ }
+
+ @Test
+ public void pathToPort_isDirectlyBelow() {
+ int targetPhysicalAddress = 0x1100;
+ int myPhysicalAddress = 0x1000;
+ assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+ targetPhysicalAddress, myPhysicalAddress)).isEqualTo(1);
+ }
+
+ @Test
+ public void pathToPort_isBelow() {
+ int targetPhysicalAddress = 0x1110;
+ int myPhysicalAddress = 0x1000;
+ assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+ targetPhysicalAddress, myPhysicalAddress)).isEqualTo(1);
+ }
+
+ @Test
+ public void pathToPort_neitherMeNorBelow() {
+ int targetPhysicalAddress = 0x3000;
+ int myPhysicalAddress = 0x2000;
+ assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+ targetPhysicalAddress, myPhysicalAddress)).isEqualTo(
+ HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE);
+
+ targetPhysicalAddress = 0x2200;
+ myPhysicalAddress = 0x3300;
+ assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+ targetPhysicalAddress, myPhysicalAddress)).isEqualTo(
+ HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE);
+
+ targetPhysicalAddress = 0x2213;
+ myPhysicalAddress = 0x2212;
+ assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+ targetPhysicalAddress, myPhysicalAddress)).isEqualTo(
+ HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE);
+
+ targetPhysicalAddress = 0x2340;
+ myPhysicalAddress = 0x2310;
+ assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+ targetPhysicalAddress, myPhysicalAddress)).isEqualTo(
+ HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE);
+ }
+
+ @Test
+ public void parseSampleXML() {
+ List<DeviceConfig> config = new ArrayList<>();
+ try {
+ config = HdmiUtils.ShortAudioDescriptorXmlParser.parse(
+ new ByteArrayInputStream(mExampleXML.getBytes(StandardCharsets.UTF_8)));
+ } catch (IOException e) {
+ Slog.e(TAG, e.getMessage(), e);
+ } catch (XmlPullParserException e) {
+ Slog.e(TAG, e.getMessage(), e);
+ }
+
+ CodecSad expectedCodec1 = new CodecSad(Constants.AUDIO_CODEC_LPCM, "011a03");
+ CodecSad expectedCodec2 = new CodecSad(Constants.AUDIO_CODEC_DD, "0d0506");
+ CodecSad expectedCodec3 = new CodecSad(Constants.AUDIO_CODEC_LPCM, "010203");
+ CodecSad expectedCodec4 = new CodecSad(Constants.AUDIO_CODEC_DD, "040506");
+
+ List<CodecSad> expectedList1 = new ArrayList<>();
+ expectedList1.add(expectedCodec1);
+ expectedList1.add(expectedCodec2);
+
+ List<CodecSad> expectedList2 = new ArrayList<>();
+ expectedList2.add(expectedCodec3);
+ expectedList2.add(expectedCodec4);
+
+ DeviceConfig expectedDevice1 = new DeviceConfig(
+ "VX_AUDIO_DEVICE_IN_HDMI_ARC", expectedList1);
+ DeviceConfig expectedDevice2 = new DeviceConfig(
+ "AUDIO_DEVICE_IN_SPDIF", expectedList2);
+
+ List<DeviceConfig> expectedConfig = new ArrayList<>();
+ expectedConfig.add(expectedDevice1);
+ expectedConfig.add(expectedDevice2);
+
+ assertThat(config).isEqualTo(expectedConfig);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
index bd297ee..440a49a 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
@@ -31,6 +31,7 @@
import androidx.test.filters.SmallTest;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -150,6 +151,11 @@
int sourceAddress, int physicalAddress) {
mBroadcastActiveSource = true;
}
+
+ @Override
+ int pathToPortId(int path) {
+ return -1;
+ }
};
mHdmiCecLocalDeviceAudioSystem =
new HdmiCecLocalDeviceAudioSystem(hdmiControlService) {
@@ -270,6 +276,7 @@
assertTrue(mHdmiCecLocalDeviceAudioSystem.isSystemAudioActivated());
}
+ @Ignore("b/120845532")
@Test
public void testIsPlaybackDevice_cannotReceiveActiveSource() {
resetTestVariables();
@@ -282,10 +289,10 @@
mTestLooper.dispatchAll();
assertThat(mMsgRequestActiveSourceCount).isEqualTo(1);
- assertThat(mMsgSetSystemAudioModeCount).isEqualTo(1);
- assertThat(mQueryTvSystemAudioModeSupportCount).isEqualTo(1);
- assertThat(mHdmiCecLocalDeviceAudioSystem.isSystemAudioActivated()).isTrue();
assertThat(mBroadcastActiveSource).isTrue();
+ assertThat(mQueryTvSystemAudioModeSupportCount).isEqualTo(1);
+ assertThat(mMsgSetSystemAudioModeCount).isEqualTo(1);
+ assertThat(mHdmiCecLocalDeviceAudioSystem.isSystemAudioActivated()).isTrue();
}
private void resetTestVariables() {
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index 823b7a5..3ebc6ad 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -544,6 +544,18 @@
switchUser(-1, UserHandle.of(startUser), false);
}
+ public void testSwitchUserByHandle_ThrowsException() {
+ synchronized (mUserSwitchLock) {
+ try {
+ ActivityManager am = getContext().getSystemService(ActivityManager.class);
+ am.switchUser(null);
+ fail("Expected IllegalArgumentException on passing in a null UserHandle.");
+ } catch (IllegalArgumentException expected) {
+ // Do nothing - exception is expected.
+ }
+ }
+ }
+
@MediumTest
public void testConcurrentUserCreate() throws Exception {
int userCount = mUserManager.getUserCount();
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexLoggerTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexLoggerTests.java
index 3b6b48b..f817e8e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexLoggerTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexLoggerTests.java
@@ -77,7 +77,6 @@
@Mock IPackageManager mPM;
@Mock Installer mInstaller;
- private final Object mInstallLock = new Object();
private PackageDynamicCodeLoading mPackageDynamicCodeLoading;
private DexLogger mDexLogger;
@@ -103,7 +102,7 @@
};
// For test purposes capture log messages as well as sending to the event log.
- mDexLogger = new DexLogger(mPM, mInstaller, mInstallLock, mPackageDynamicCodeLoading) {
+ mDexLogger = new DexLogger(mPM, mInstaller, mPackageDynamicCodeLoading) {
@Override
void writeDclEvent(int uid, String message) {
super.writeDclEvent(uid, message);
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index 41d5691..8171469 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -61,6 +61,7 @@
import android.view.Display;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -416,6 +417,7 @@
}
@Test
+ @FlakyTest(bugId = 119774928)
public void testEnabledState() throws Exception {
TestParoleListener paroleListener = new TestParoleListener();
mController.addListener(paroleListener);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 83c1c76..94b21af 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -3511,9 +3511,9 @@
}
@Test
- public void testAppOverlay() throws Exception {
- mBinderService.setAppOverlaysAllowed(PKG, mUid, false);
- assertFalse(mBinderService.areAppOverlaysAllowedForPackage(PKG, mUid));
+ public void testBubble() throws Exception {
+ mBinderService.setBubblesAllowed(PKG, mUid, false);
+ assertFalse(mBinderService.areBubblesAllowedForPackage(PKG, mUid));
}
@Test
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 0fcfea7..24a1f8c 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -809,7 +809,7 @@
channel.setBypassDnd(true);
channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
channel.setShowBadge(true);
- channel.setAllowAppOverlay(false);
+ channel.setAllowBubbles(false);
int lockMask = 0;
for (int i = 0; i < NotificationChannel.LOCKABLE_FIELDS.length; i++) {
lockMask |= NotificationChannel.LOCKABLE_FIELDS[i];
@@ -826,7 +826,7 @@
assertFalse(savedChannel.canBypassDnd());
assertFalse(Notification.VISIBILITY_SECRET == savedChannel.getLockscreenVisibility());
assertEquals(channel.canShowBadge(), savedChannel.canShowBadge());
- assertEquals(channel.canOverlayApps(), savedChannel.canOverlayApps());
+ assertEquals(channel.canBubble(), savedChannel.canBubble());
verify(mHandler, never()).requestSort();
}
@@ -840,7 +840,7 @@
channel.setBypassDnd(true);
channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
channel.setShowBadge(true);
- channel.setAllowAppOverlay(false);
+ channel.setAllowBubbles(false);
int lockMask = 0;
for (int i = 0; i < NotificationChannel.LOCKABLE_FIELDS.length; i++) {
lockMask |= NotificationChannel.LOCKABLE_FIELDS[i];
@@ -857,7 +857,7 @@
assertFalse(savedChannel.canBypassDnd());
assertFalse(Notification.VISIBILITY_SECRET == savedChannel.getLockscreenVisibility());
assertEquals(channel.canShowBadge(), savedChannel.canShowBadge());
- assertEquals(channel.canOverlayApps(), savedChannel.canOverlayApps());
+ assertEquals(channel.canBubble(), savedChannel.canBubble());
}
@Test
@@ -969,16 +969,16 @@
}
@Test
- public void testLockFields_appOverlay() {
+ public void testLockFields_allowBubble() {
mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false);
assertEquals(0,
mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel().getId(), false)
.getUserLockedFields());
final NotificationChannel update = getChannel();
- update.setAllowAppOverlay(false);
+ update.setAllowBubbles(false);
mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update, true);
- assertEquals(NotificationChannel.USER_LOCKED_ALLOW_APP_OVERLAY,
+ assertEquals(NotificationChannel.USER_LOCKED_ALLOW_BUBBLE,
mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update.getId(), false)
.getUserLockedFields());
}
@@ -2161,30 +2161,30 @@
}
@Test
- public void testAllowAppOverlay_defaults() throws Exception {
- assertTrue(mHelper.areAppOverlaysAllowed(PKG_O, UID_O));
+ public void testAllowBubbles_defaults() throws Exception {
+ assertTrue(mHelper.areBubblessAllowed(PKG_O, UID_O));
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
loadStreamXml(baos, false);
- assertTrue(mHelper.areAppOverlaysAllowed(PKG_O, UID_O));
+ assertTrue(mHelper.areBubblessAllowed(PKG_O, UID_O));
assertEquals(0, mHelper.getAppLockedFields(PKG_O, UID_O));
}
@Test
- public void testAllowAppOverlay_xml() throws Exception {
- mHelper.setAppOverlaysAllowed(PKG_O, UID_O, false);
- assertFalse(mHelper.areAppOverlaysAllowed(PKG_O, UID_O));
- assertEquals(PreferencesHelper.LockableAppFields.USER_LOCKED_APP_OVERLAY,
+ public void testAllowBubbles_xml() throws Exception {
+ mHelper.setBubblesAllowed(PKG_O, UID_O, false);
+ assertFalse(mHelper.areBubblessAllowed(PKG_O, UID_O));
+ assertEquals(PreferencesHelper.LockableAppFields.USER_LOCKED_BUBBLE,
mHelper.getAppLockedFields(PKG_O, UID_O));
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
loadStreamXml(baos, false);
- assertFalse(mHelper.areAppOverlaysAllowed(PKG_O, UID_O));
- assertEquals(PreferencesHelper.LockableAppFields.USER_LOCKED_APP_OVERLAY,
+ assertFalse(mHelper.areBubblessAllowed(PKG_O, UID_O));
+ assertEquals(PreferencesHelper.LockableAppFields.USER_LOCKED_BUBBLE,
mHelper.getAppLockedFields(PKG_O, UID_O));
}
@@ -2290,14 +2290,14 @@
mHelper.lockChannelsForOEM(new String[] {PKG_O});
NotificationChannel update = new NotificationChannel("a", "a", IMPORTANCE_NONE);
- update.setAllowAppOverlay(false);
+ update.setAllowBubbles(false);
mHelper.updateNotificationChannel(PKG_O, UID_O, update, true);
assertEquals(IMPORTANCE_HIGH,
mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance());
assertEquals(false,
- mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).canOverlayApps());
+ mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).canBubble());
mHelper.updateNotificationChannel(PKG_O, UID_O, update, true);
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 8f9d2ba..06360c2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -41,9 +41,11 @@
import android.app.ActivityOptions;
import android.app.servertransaction.ClientTransaction;
import android.app.servertransaction.PauseActivityItem;
+import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
+import android.util.MergedConfiguration;
import android.util.MutableBoolean;
import androidx.test.filters.MediumTest;
@@ -68,7 +70,7 @@
@Before
public void setUp() throws Exception {
setupActivityTaskManagerService();
- mStack = new StackBuilder(mRootActivityContainer).build();
+ mStack = (TestActivityStack) new StackBuilder(mRootActivityContainer).build();
mTask = mStack.getChildAt(0);
mActivity = mTask.getTopActivity();
}
@@ -251,4 +253,72 @@
assertEquals(prevSeq + 1, appWindowTokenRequestedOrientation.seq);
verify(mActivity.mAppWindowToken).onMergedOverrideConfigurationChanged();
}
+
+ @Test
+ public void testSetsRelaunchReason_NotDragResizing() {
+ 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(mTask.getConfiguration());
+ newConfig.orientation = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT
+ ? Configuration.ORIENTATION_LANDSCAPE : Configuration.ORIENTATION_PORTRAIT;
+ mTask.onRequestedOverrideConfigurationChanged(newConfig);
+
+ mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE;
+
+ mActivity.ensureActivityConfiguration(0, false, false);
+
+ assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE,
+ mActivity.mRelaunchReason);
+ }
+
+ @Test
+ public void testSetsRelaunchReason_DragResizing() {
+ 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(mTask.getConfiguration());
+ newConfig.orientation = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT
+ ? Configuration.ORIENTATION_LANDSCAPE : Configuration.ORIENTATION_PORTRAIT;
+ mTask.onRequestedOverrideConfigurationChanged(newConfig);
+
+ doReturn(true).when(mTask.getTask()).isDragResizing();
+
+ mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE;
+
+ mActivity.ensureActivityConfiguration(0, false, false);
+
+ assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE,
+ mActivity.mRelaunchReason);
+ }
+
+ @Test
+ public void testSetsRelaunchReason_NonResizeConfigChanges() {
+ mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
+
+ mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
+ mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
+ mActivity.getConfiguration()));
+
+ mActivity.info.configChanges &= ~ActivityInfo.CONFIG_FONT_SCALE;
+ final Configuration newConfig = new Configuration(mTask.getConfiguration());
+ newConfig.fontScale = 5;
+ mTask.onRequestedOverrideConfigurationChanged(newConfig);
+
+ mActivity.mRelaunchReason =
+ ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
+
+ mActivity.ensureActivityConfiguration(0, false, false);
+
+ assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_NONE,
+ mActivity.mRelaunchReason);
+ }
}
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 b2a2869..fda23e9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -36,6 +36,8 @@
import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
import static com.android.server.wm.ActivityStack.ActivityState.STOPPING;
import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
+import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE;
+import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
import static com.google.common.truth.Truth.assertThat;
@@ -264,13 +266,13 @@
// Do not move display to back because there is still another stack.
stack2.moveToBack("testMoveStackToBackIncludingParent", stack2.topTask());
- verify(stack2.getWindowContainerController()).positionChildAtBottom(any(),
+ verify(stack2.getTaskStack()).positionChildAtBottom(any(),
eq(false) /* includingParents */);
// Also move display to back because there is only one stack left.
display.removeChild(stack1);
stack2.moveToBack("testMoveStackToBackIncludingParent", stack2.topTask());
- verify(stack2.getWindowContainerController()).positionChildAtBottom(any(),
+ verify(stack2.getTaskStack()).positionChildAtBottom(any(),
eq(true) /* includingParents */);
}
@@ -687,6 +689,62 @@
}
@Test
+ public void testHandleAppDied_RelaunchesAfterCrashDuringWindowingModeResize() {
+ final ActivityRecord activity = new ActivityBuilder(mService).setTask(mTask).build();
+
+ activity.mRelaunchReason = RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
+ activity.launchCount = 1;
+ activity.haveState = false;
+
+ mStack.handleAppDiedLocked(activity.app);
+
+ assertEquals(1, mTask.mActivities.size());
+ assertEquals(1, mStack.getAllTasks().size());
+ }
+
+ @Test
+ public void testHandleAppDied_NotRelaunchAfterThreeCrashesDuringWindowingModeResize() {
+ final ActivityRecord activity = new ActivityBuilder(mService).setTask(mTask).build();
+
+ activity.mRelaunchReason = RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
+ activity.launchCount = 3;
+ activity.haveState = false;
+
+ mStack.handleAppDiedLocked(activity.app);
+
+ assertThat(mTask.mActivities).isEmpty();
+ assertThat(mStack.getAllTasks()).isEmpty();
+ }
+
+ @Test
+ public void testHandleAppDied_RelaunchesAfterCrashDuringFreeResize() {
+ final ActivityRecord activity = new ActivityBuilder(mService).setTask(mTask).build();
+
+ activity.mRelaunchReason = RELAUNCH_REASON_FREE_RESIZE;
+ activity.launchCount = 1;
+ activity.haveState = false;
+
+ mStack.handleAppDiedLocked(activity.app);
+
+ assertEquals(1, mTask.mActivities.size());
+ assertEquals(1, mStack.getAllTasks().size());
+ }
+
+ @Test
+ public void testHandleAppDied_NotRelaunchAfterThreeCrashesDuringFreeResize() {
+ final ActivityRecord activity = new ActivityBuilder(mService).setTask(mTask).build();
+
+ activity.mRelaunchReason = RELAUNCH_REASON_FREE_RESIZE;
+ activity.launchCount = 3;
+ activity.haveState = false;
+
+ mStack.handleAppDiedLocked(activity.app);
+
+ assertThat(mTask.mActivities).isEmpty();
+ assertThat(mStack.getAllTasks()).isEmpty();
+ }
+
+ @Test
public void testFinishCurrentActivity() {
// Create 2 activities on a new display.
final ActivityDisplay display = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP);
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 ec88718..898d107 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -143,7 +143,7 @@
.setStack(mService.mRootActivityContainer.getDefaultDisplay().createStack(
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */))
.build();
- assertThat((Object) task2.getStack()).isInstanceOf(PinnedActivityStack.class);
+ assertThat((Object) task2.getStack()).isInstanceOf(ActivityStack.class);
mStarter.updateBounds(task2, bounds);
verify(mService, times(1)).resizeStack(eq(task2.getStack().mStackId),
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 5589ca1..d462e69 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -39,9 +39,6 @@
import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.doCallRealMethod;
-
import android.app.ActivityManagerInternal;
import android.app.ActivityOptions;
import android.app.IApplicationThread;
@@ -66,11 +63,11 @@
import android.view.DisplayInfo;
import com.android.internal.app.IVoiceInteractor;
-import com.android.server.appop.AppOpsService;
import com.android.server.AttributeCache;
import com.android.server.ServiceThread;
import com.android.server.am.ActivityManagerService;
import com.android.server.am.PendingIntentController;
+import com.android.server.appop.AppOpsService;
import com.android.server.firewall.IntentFirewall;
import com.android.server.uri.UriGrantsManagerInternal;
@@ -377,7 +374,7 @@
mStack.addTask(task, true, "creating test task");
task.setStack(mStack);
task.setTask();
- mStack.getWindowContainerController().mContainer.addChild(task.mTask, 0);
+ mStack.getTaskStack().addChild(task.mTask, 0);
}
task.touchActiveTime();
@@ -632,7 +629,7 @@
@SuppressWarnings("TypeParameterUnusedInFormals")
@Override
- <T extends ActivityStack> T createStackUnchecked(int windowingMode, int activityType,
+ ActivityStack createStackUnchecked(int windowingMode, int activityType,
int stackId, boolean onTop) {
return new StackBuilder(mSupervisor.mRootActivityContainer).setDisplay(this)
.setWindowingMode(windowingMode).setActivityType(activityType)
@@ -681,10 +678,9 @@
* method is called. Note that its functionality depends on the implementations of the
* construction arguments.
*/
- protected static class TestActivityStack<T extends StackWindowController>
- extends ActivityStack<T> {
+ protected static class TestActivityStack
+ extends ActivityStack {
private int mOnActivityRemovedFromStackCount = 0;
- private T mContainerController;
static final int IS_TRANSLUCENT_UNSET = 0;
static final int IS_TRANSLUCENT_FALSE = 1;
@@ -724,20 +720,20 @@
}
@Override
- protected T createStackWindowController(int displayId, boolean onTop, Rect outBounds) {
- mContainerController = (T) WindowTestUtils.createMockStackWindowContainerController();
+ protected void createTaskStack(int displayId, boolean onTop, Rect outBounds) {
+ mTaskStack = WindowTestUtils.createMockTaskStack();
// Primary pinned stacks require a non-empty out bounds to be set or else all tasks
// will be moved to the full screen stack.
if (getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
outBounds.set(0, 0, 100, 100);
}
- return mContainerController;
+
}
@Override
- T getWindowContainerController() {
- return mContainerController;
+ TaskStack getTaskStack() {
+ return mTaskStack;
}
void setIsTranslucent(boolean isTranslucent) {
@@ -827,27 +823,23 @@
}
@SuppressWarnings("TypeParameterUnusedInFormals")
- <T extends ActivityStack> T build() {
+ ActivityStack build() {
final int stackId = mStackId >= 0 ? mStackId : mDisplay.getNextStackId();
if (mWindowingMode == WINDOWING_MODE_PINNED) {
- return (T) new PinnedActivityStack(mDisplay, stackId,
- mRootActivityContainer.mStackSupervisor, mOnTop) {
+ return new ActivityStack(mDisplay, stackId, mRootActivityContainer.mStackSupervisor,
+ mWindowingMode, ACTIVITY_TYPE_STANDARD, mOnTop) {
@Override
Rect getDefaultPictureInPictureBounds(float aspectRatio) {
return new Rect(50, 50, 100, 100);
}
@Override
- PinnedStackWindowController createStackWindowController(int displayId,
- boolean onTop, Rect outBounds) {
- PinnedStackWindowController controller =
- mock(PinnedStackWindowController.class);
- controller.mContainer = mock(TaskStack.class);
- return controller;
+ void createTaskStack(int displayId, boolean onTop, Rect outBounds) {
+ mTaskStack = mock(TaskStack.class);
}
};
} else {
- return (T) new TestActivityStack(mDisplay, stackId,
+ return new TestActivityStack(mDisplay, stackId,
mRootActivityContainer.mStackSupervisor, mWindowingMode,
mActivityType, mOnTop, mCreateActivity);
}
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 fa42289..0c6e632 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -39,7 +39,9 @@
import androidx.test.filters.SmallTest;
+import org.junit.AfterClass;
import org.junit.Before;
+import org.junit.BeforeClass;
import org.junit.Test;
/**
@@ -52,15 +54,34 @@
@Presubmit
public class AppTransitionTests extends WindowTestsBase {
+ private static RootWindowContainer sOriginalRootWindowContainer;
+
private DisplayContent mDc;
+ @BeforeClass
+ public static void setUpRootWindowContainerMock() {
+ final WindowManagerService wm = WmServiceUtils.getWindowManagerService();
+ // For unit test, we don't need to test performSurfacePlacement to prevent some abnormal
+ // interaction with surfaceflinger native side.
+ sOriginalRootWindowContainer = wm.mRoot;
+ // Creating spied mock of RootWindowContainer shouldn't be done in @Before, since it will
+ // create unnecessary nested spied objects chain, because WindowManagerService object under
+ // test is a single instance shared among all tests that extend WindowTestsBase class.
+ // Instead it should be done once before running all tests in this test class.
+ wm.mRoot = spy(wm.mRoot);
+ doNothing().when(wm.mRoot).performSurfacePlacement(anyBoolean());
+ }
+
+ @AfterClass
+ public static void tearDownRootWindowContainerMock() {
+ final WindowManagerService wm = WmServiceUtils.getWindowManagerService();
+ wm.mRoot = sOriginalRootWindowContainer;
+ sOriginalRootWindowContainer = null;
+ }
+
@Before
public void setUp() throws Exception {
mDc = mWm.getDefaultDisplayContentLocked();
- // For unit test, we don't need to test performSurfacePlacement to prevent some
- // abnormal interaction with surfaceflinger native side.
- mWm.mRoot = spy(mWm.mRoot);
- doNothing().when(mWm.mRoot).performSurfacePlacement(anyBoolean());
}
@Test
@@ -160,7 +181,7 @@
assertTrue(dc1.mOpeningApps.size() > 0);
// Move stack to another display.
- stack1.getController().reparent(dc2.getDisplayId(), new Rect(), true);
+ stack1.reparent(dc2.getDisplayId(), new Rect(), true);
// Verify if token are cleared from both pending transition list in former display.
assertFalse(dc1.mOpeningApps.contains(token1));
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 3826fac..f399463 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -59,6 +59,7 @@
import android.platform.test.annotations.Presubmit;
import android.util.DisplayMetrics;
import android.view.DisplayCutout;
+import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.Surface;
@@ -584,15 +585,17 @@
@Test
public void testOnDescendantOrientationRequestChanged() {
- final DisplayContent dc = createNewDisplay();
+ final DisplayInfo info = new DisplayInfo();
+ info.logicalWidth = 1080;
+ info.logicalHeight = 1920;
+ info.logicalDensityDpi = 240;
+ final DisplayContent dc = createNewDisplay(info);
+ dc.configureDisplayPolicy();
mWm.mAtmService.mRootActivityContainer = mock(RootActivityContainer.class);
- final int newOrientation = dc.getLastOrientation() == SCREEN_ORIENTATION_LANDSCAPE
- ? SCREEN_ORIENTATION_PORTRAIT
- : SCREEN_ORIENTATION_LANDSCAPE;
final WindowState window = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
window.getTask().mTaskRecord = mock(TaskRecord.class, ExtendedMockito.RETURNS_DEEP_STUBS);
- window.mAppToken.setOrientation(newOrientation);
+ window.mAppToken.mOrientation = SCREEN_ORIENTATION_LANDSCAPE;
ActivityRecord activityRecord = mock(ActivityRecord.class);
@@ -603,21 +606,22 @@
verify(mWm.mAtmService).updateDisplayOverrideConfigurationLocked(captor.capture(),
same(activityRecord), anyBoolean(), eq(dc.getDisplayId()));
final Configuration newDisplayConfig = captor.getValue();
- assertEquals(Configuration.ORIENTATION_PORTRAIT, newDisplayConfig.orientation);
+ assertEquals(Configuration.ORIENTATION_LANDSCAPE, newDisplayConfig.orientation);
}
@Test
public void testOnDescendantOrientationRequestChanged_FrozenToUserRotation() {
- final DisplayContent dc = createNewDisplay();
+ final DisplayInfo info = new DisplayInfo();
+ info.logicalWidth = 1080;
+ info.logicalHeight = 1920;
+ info.logicalDensityDpi = 240;
+ final DisplayContent dc = createNewDisplay(info);
dc.getDisplayRotation().setFixedToUserRotation(true);
mWm.mAtmService.mRootActivityContainer = mock(RootActivityContainer.class);
- final int newOrientation = dc.getLastOrientation() == SCREEN_ORIENTATION_LANDSCAPE
- ? SCREEN_ORIENTATION_PORTRAIT
- : SCREEN_ORIENTATION_LANDSCAPE;
final WindowState window = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
window.getTask().mTaskRecord = mock(TaskRecord.class, ExtendedMockito.RETURNS_DEEP_STUBS);
- window.mAppToken.setOrientation(newOrientation);
+ window.mAppToken.mOrientation = SCREEN_ORIENTATION_LANDSCAPE;
ActivityRecord activityRecord = mock(ActivityRecord.class);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
index 198e7ce..d05711e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
@@ -33,7 +33,6 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import android.content.ContentResolver;
@@ -612,23 +611,6 @@
// ========================
// Non-rotation API Tests
// ========================
- @Test
- public void testRespectsAppRequestedOrientationByDefault() throws Exception {
- mBuilder.build();
-
- assertTrue("Display rotation should respect app requested orientation by"
- + " default.", mTarget.respectAppRequestedOrientation());
- }
-
- @Test
- public void testNotRespectAppRequestedOrientation_FixedToUserRotation() throws Exception {
- mBuilder.build();
- mTarget.setFixedToUserRotation(true);
-
- assertFalse("Display rotation shouldn't respect app requested orientation if"
- + " fixed to user rotation.", mTarget.respectAppRequestedOrientation());
- }
-
/**
* Call {@link DisplayRotation#configure(int, int, int, int)} to configure {@link #mTarget}
* according to given parameters.
diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
index bb3ab35..68d8bc0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
@@ -94,8 +94,8 @@
private WindowState createDropTargetWindow(String name, int ownerId) {
final WindowTestUtils.TestAppWindowToken token = WindowTestUtils.createTestAppWindowToken(
mDisplayContent);
- final TaskStack stack = createStackControllerOnStackOnDisplay(
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer;
+ final TaskStack stack = createTaskStackOnDisplay(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, mDisplayContent);
final Task task = createTaskInStack(stack, ownerId);
task.addChild(token, 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 58302d6..a3f535a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -323,8 +323,8 @@
public void testFindTaskToMoveToFrontWhenRecentsOnTop() {
// Create stack/task on default display.
final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
- final TestActivityStack targetStack =
- new StackBuilder(mRootActivityContainer).setOnTop(false).build();
+ final TestActivityStack targetStack = (TestActivityStack) new StackBuilder(
+ mRootActivityContainer).setOnTop(false).build();
final TaskRecord targetTask = targetStack.getChildAt(0);
// Create Recents on top of the display.
diff --git a/services/tests/wmtests/src/com/android/server/wm/StackWindowControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/StackWindowControllerTests.java
deleted file mode 100644
index 5690b58..0000000
--- a/services/tests/wmtests/src/com/android/server/wm/StackWindowControllerTests.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import android.graphics.Rect;
-import android.platform.test.annotations.Presubmit;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-
-/**
- * Test class for {@link StackWindowController}.
- *
- * Build/Install/Run:
- * atest FrameworksServicesTests:StackWindowControllerTests
- */
-@SmallTest
-@Presubmit
-public class StackWindowControllerTests extends WindowTestsBase {
- @Test
- public void testRemoveContainer() {
- final StackWindowController stackController =
- createStackControllerOnDisplay(mDisplayContent);
- final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stackController);
-
- final TaskStack stack = stackController.mContainer;
- assertNotNull(stack);
- assertNotNull(task);
- stackController.removeContainer();
- // Assert that the container was removed.
- assertNull(stackController.mContainer);
- assertNull(stack.getDisplayContent());
- assertNull(task.getDisplayContent());
- assertNull(task.mStack);
- }
-
- @Test
- public void testRemoveContainer_deferRemoval() {
- final StackWindowController stackController =
- createStackControllerOnDisplay(mDisplayContent);
- final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stackController);
-
- final TaskStack stack = stackController.mContainer;
- // Stack removal is deferred if one of its child is animating.
- task.setLocalIsAnimating(true);
-
- stackController.removeContainer();
- // For the case of deferred removal the stack controller will no longer be connected to the
- // container, but the task controller will still be connected to the its container until
- // the stack window container is removed.
- assertNull(stackController.mContainer);
- assertNull(stack.getController());
- assertNotNull(task);
-
- stack.removeImmediately();
- // After removing, the task will be isolated.
- assertNull(task.getParent());
- assertEquals(task.getChildCount(), 0);
- assertNull(task.getController());
- }
-
- @Test
- public void testReparent() {
- // Create first stack on primary display.
- final StackWindowController stack1Controller =
- createStackControllerOnDisplay(mDisplayContent);
- final TaskStack stack1 = stack1Controller.mContainer;
- final WindowTestUtils.TestTask task1 = WindowTestUtils.createTestTask(stack1Controller);
- task1.mOnDisplayChangedCalled = false;
-
- // Create second display and put second stack on it.
- final DisplayContent dc = createNewDisplay();
- final StackWindowController stack2Controller =
- createStackControllerOnDisplay(dc);
- final TaskStack stack2 = stack2Controller.mContainer;
-
- // Reparent
- stack1Controller.reparent(dc.getDisplayId(), new Rect(), true /* onTop */);
- assertEquals(dc, stack1.getDisplayContent());
- final int stack1PositionInParent = stack1.getParent().mChildren.indexOf(stack1);
- final int stack2PositionInParent = stack1.getParent().mChildren.indexOf(stack2);
- assertEquals(stack1PositionInParent, stack2PositionInParent + 1);
- assertTrue(task1.mOnDisplayChangedCalled);
- }
-}
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 8a98cbe..1c33dfb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -25,6 +25,13 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
+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.doCallRealMethod;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static org.hamcrest.Matchers.not;
@@ -46,6 +53,7 @@
import android.service.voice.IVoiceInteractionSession;
import android.util.Xml;
import android.view.DisplayInfo;
+import android.view.Surface;
import androidx.test.filters.MediumTest;
@@ -217,12 +225,17 @@
info.logicalHeight = fullScreenBounds.height();
ActivityDisplay display = addNewActivityDisplayAt(info, POSITION_TOP);
assertTrue(mRootActivityContainer.getActivityDisplay(display.mDisplayId) != null);
+ // Override display orientation. Normally this is available via DisplayContent, but DC
+ // is mocked-out.
+ display.getRequestedOverrideConfiguration().orientation =
+ Configuration.ORIENTATION_LANDSCAPE;
+ display.onRequestedOverrideConfigurationChanged(
+ display.getRequestedOverrideConfiguration());
ActivityStack stack = new StackBuilder(mRootActivityContainer)
.setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build();
TaskRecord task = stack.getChildAt(0);
- ActivityRecord root = task.getRootActivity();
- ActivityRecord top = new ActivityBuilder(mService).setTask(task).setStack(stack).build();
- assertEquals(root, task.getRootActivity());
+ ActivityRecord root = task.getTopActivity();
+ assertEquals(root, task.getTopActivity());
assertEquals(fullScreenBounds, task.getBounds());
@@ -233,16 +246,22 @@
assertTrue(task.getBounds().width() < task.getBounds().height());
assertEquals(fullScreenBounds.height(), task.getBounds().height());
- // Setting non-root app has no effect
- setActivityRequestedOrientation(root, SCREEN_ORIENTATION_LANDSCAPE);
- assertTrue(task.getBounds().width() < task.getBounds().height());
+ // Top activity gets used
+ ActivityRecord top = new ActivityBuilder(mService).setTask(task).setStack(stack).build();
+ assertEquals(top, task.getTopActivity());
+ setActivityRequestedOrientation(top, SCREEN_ORIENTATION_LANDSCAPE);
+ assertTrue(task.getBounds().width() > task.getBounds().height());
+ assertEquals(task.getBounds().width(), fullScreenBounds.width());
// Setting app to unspecified restores
- setActivityRequestedOrientation(root, SCREEN_ORIENTATION_UNSPECIFIED);
+ setActivityRequestedOrientation(top, SCREEN_ORIENTATION_UNSPECIFIED);
assertEquals(fullScreenBounds, task.getBounds());
// Setting app to fixed landscape and changing display
- setActivityRequestedOrientation(root, SCREEN_ORIENTATION_LANDSCAPE);
+ setActivityRequestedOrientation(top, SCREEN_ORIENTATION_LANDSCAPE);
+ // simulate display orientation changing (normally done via DisplayContent)
+ display.getRequestedOverrideConfiguration().orientation =
+ Configuration.ORIENTATION_PORTRAIT;
display.setBounds(fullScreenBoundsPort);
assertTrue(task.getBounds().width() > task.getBounds().height());
assertEquals(fullScreenBoundsPort.width(), task.getBounds().width());
@@ -265,6 +284,53 @@
assertEquals(freeformBounds, task.getBounds());
}
+ @Test
+ public void testUpdatesForcedOrientationInBackground() {
+ final DisplayInfo info = new DisplayInfo();
+ info.logicalWidth = 1920;
+ info.logicalHeight = 1080;
+ final ActivityDisplay display = addNewActivityDisplayAt(info, POSITION_TOP);
+ doCallRealMethod().when(display.mDisplayContent).setDisplayRotation(any());
+ display.mDisplayContent.setDisplayRotation(mock(DisplayRotation.class));
+ doCallRealMethod().when(display.mDisplayContent).onDescendantOrientationChanged(any(),
+ any());
+ doCallRealMethod().when(display.mDisplayContent).setRotation(anyInt());
+ doAnswer(invocation -> {
+ display.mDisplayContent.setRotation(Surface.ROTATION_0);
+ return null;
+ }).when(display.mDisplayContent).updateOrientationFromAppTokens(any(), any(), anyBoolean());
+
+ final ActivityStack stack = new StackBuilder(mRootActivityContainer)
+ .setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build();
+ final TaskRecord task = stack.getChildAt(0);
+ final ActivityRecord activity = task.getRootActivity();
+
+ // Wire up app window token and task.
+ doCallRealMethod().when(activity.mAppWindowToken).setOrientation(anyInt(), any(), any());
+ doCallRealMethod().when(activity.mAppWindowToken).onDescendantOrientationChanged(any(),
+ any());
+ doReturn(task.mTask).when(activity.mAppWindowToken).getParent();
+
+ // Wire up task and stack.
+ task.mTask.mTaskRecord = task;
+ doCallRealMethod().when(task.mTask).onDescendantOrientationChanged(any(), any());
+ doReturn(stack.getWindowContainerController().mContainer).when(task.mTask).getParent();
+
+ // Wire up stack and display content.
+ doCallRealMethod().when(stack.mWindowContainerController.mContainer)
+ .onDescendantOrientationChanged(any(), any());
+ doReturn(display.mDisplayContent).when(stack.mWindowContainerController.mContainer)
+ .getParent();
+
+ activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+ assertTrue("Bounds of the task should be pillarboxed.",
+ task.getBounds().width() < task.getBounds().height());
+
+ activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
+ assertTrue("Bounds of the task should be fullscreen.",
+ task.getBounds().equals(new Rect(0, 0, 1920, 1080)));
+ }
+
/** Ensures that the alias intent won't have target component resolved. */
@Test
public void testTaskIntentActivityAlias() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackContainersTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackContainersTests.java
index f01e9f0..74ccccc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackContainersTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackContainersTests.java
@@ -47,8 +47,8 @@
@Before
public void setUp() throws Exception {
- mPinnedStack = createStackControllerOnStackOnDisplay(
- WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer;
+ mPinnedStack = createTaskStackOnDisplay(
+ WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mDisplayContent);
// Stack should contain visible app window to be considered visible.
final Task pinnedTask = createTaskInStack(mPinnedStack, 0 /* userId */);
assertFalse(mPinnedStack.isVisible());
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
index 7ac3318..2554237 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
@@ -20,8 +20,12 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
@@ -106,4 +110,62 @@
assertNull(stack.getDisplayContent());
assertNull(task.mStack);
}
+
+ @Test
+ public void testRemoveContainer() {
+ final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
+ final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stack);
+
+ assertNotNull(stack);
+ assertNotNull(task);
+ stack.removeIfPossible();
+ // Assert that the container was removed.
+ assertNull(stack.getParent());
+ assertEquals(0, stack.getChildCount());
+ assertNull(stack.getDisplayContent());
+ assertNull(task.getDisplayContent());
+ assertNull(task.mStack);
+ }
+
+ @Test
+ public void testRemoveContainer_deferRemoval() {
+ final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
+ final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stack);
+
+ // Stack removal is deferred if one of its child is animating.
+ task.setLocalIsAnimating(true);
+
+ stack.removeIfPossible();
+ // For the case of deferred removal the task controller will still be connected to the its
+ // container until the stack window container is removed.
+ assertNotNull(stack.getParent());
+ assertNotEquals(0, stack.getChildCount());
+ assertNotNull(task);
+
+ stack.removeImmediately();
+ // After removing, the task will be isolated.
+ assertNull(task.getParent());
+ assertEquals(0, task.getChildCount());
+ assertNull(task.getController());
+ }
+
+ @Test
+ public void testReparent() {
+ // Create first stack on primary display.
+ final TaskStack stack1 = createTaskStackOnDisplay(mDisplayContent);
+ final WindowTestUtils.TestTask task1 = WindowTestUtils.createTestTask(stack1);
+ task1.mOnDisplayChangedCalled = false;
+
+ // Create second display and put second stack on it.
+ final DisplayContent dc = createNewDisplay();
+ final TaskStack stack2 = createTaskStackOnDisplay(dc);
+
+ // Reparent
+ stack1.reparent(dc.getDisplayId(), new Rect(), true /* onTop */);
+ assertEquals(dc, stack1.getDisplayContent());
+ final int stack1PositionInParent = stack1.getParent().mChildren.indexOf(stack1);
+ final int stack2PositionInParent = stack1.getParent().mChildren.indexOf(stack2);
+ assertEquals(stack1PositionInParent, stack2PositionInParent + 1);
+ assertTrue(task1.mOnDisplayChangedCalled);
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index 3e32ed3..ae211d3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -40,8 +40,7 @@
@Test
public void testRemoveContainer() {
- final StackWindowController stackController1 =
- createStackControllerOnDisplay(mDisplayContent);
+ final TaskStack stackController1 = createTaskStackOnDisplay(mDisplayContent);
final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stackController1);
final WindowTestUtils.TestAppWindowToken appToken =
WindowTestUtils.createAppWindowTokenInTask(mDisplayContent, task);
@@ -49,14 +48,13 @@
task.removeIfPossible();
// Assert that the container was removed.
assertNull(task.getParent());
- assertEquals(task.getChildCount(), 0);
+ assertEquals(0, task.getChildCount());
assertNull(appToken.getParent());
}
@Test
public void testRemoveContainer_deferRemoval() {
- final StackWindowController stackController1 =
- createStackControllerOnDisplay(mDisplayContent);
+ final TaskStack stackController1 = createTaskStackOnDisplay(mDisplayContent);
final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stackController1);
final WindowTestUtils.TestAppWindowToken appToken =
WindowTestUtils.createAppWindowTokenInTask(mDisplayContent, task);
@@ -67,22 +65,20 @@
// For the case of deferred removal the task will still be connected to the its app token
// until the task window container is removed.
assertNotNull(task.getParent());
- assertNotEquals(task.getChildCount(), 0);
+ assertNotEquals(0, task.getChildCount());
assertNotNull(appToken.getParent());
task.removeImmediately();
assertNull(task.getParent());
- assertEquals(task.getChildCount(), 0);
+ assertEquals(0, task.getChildCount());
assertNull(appToken.getParent());
}
@Test
public void testReparent() {
- final StackWindowController stackController1 =
- createStackControllerOnDisplay(mDisplayContent);
+ final TaskStack stackController1 = createTaskStackOnDisplay(mDisplayContent);
final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stackController1);
- final StackWindowController stackController2 =
- createStackControllerOnDisplay(mDisplayContent);
+ final TaskStack stackController2 = createTaskStackOnDisplay(mDisplayContent);
final WindowTestUtils.TestTask task2 = WindowTestUtils.createTestTask(stackController2);
boolean gotException = false;
@@ -93,20 +89,17 @@
}
assertTrue("Should not be able to reparent to the same parent", gotException);
- final StackWindowController stackController3 =
- createStackControllerOnDisplay(mDisplayContent);
- stackController3.setContainer(null);
gotException = false;
try {
- task.reparent(stackController3, 0, false/* moveParents */);
+ task.reparent(null, 0, false/* moveParents */);
} catch (IllegalArgumentException e) {
gotException = true;
}
- assertTrue("Should not be able to reparent to a stack that doesn't have a container",
+ assertTrue("Should not be able to reparent to a stack that doesn't exist",
gotException);
task.reparent(stackController2, 0, false/* moveParents */);
- assertEquals(stackController2.mContainer, task.getParent());
+ assertEquals(stackController2, task.getParent());
assertEquals(0, task.positionInParent());
assertEquals(1, task2.positionInParent());
}
@@ -114,20 +107,17 @@
@Test
public void testReparent_BetweenDisplays() {
// Create first stack on primary display.
- final StackWindowController stack1Controller =
- createStackControllerOnDisplay(mDisplayContent);
- final TaskStack stack1 = stack1Controller.mContainer;
- final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stack1Controller);
+ final TaskStack stack1 = createTaskStackOnDisplay(mDisplayContent);
+ final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stack1);
task.mOnDisplayChangedCalled = false;
assertEquals(mDisplayContent, stack1.getDisplayContent());
// Create second display and put second stack on it.
final DisplayContent dc = createNewDisplay();
- final StackWindowController stack2Controller = createStackControllerOnDisplay(dc);
- final TaskStack stack2 = stack2Controller.mContainer;
- final WindowTestUtils.TestTask task2 = WindowTestUtils.createTestTask(stack2Controller);
+ final TaskStack stack2 = createTaskStackOnDisplay(dc);
+ final WindowTestUtils.TestTask task2 = WindowTestUtils.createTestTask(stack2);
// Reparent and check state
- task.reparent(stack2Controller, 0, false /* moveParents */);
+ task.reparent(stack2, 0, false /* moveParents */);
assertEquals(stack2, task.getParent());
assertEquals(0, task.positionInParent());
assertEquals(1, task2.positionInParent());
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
index d9ef10d..0a4a8a4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
@@ -16,12 +16,15 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
import static android.view.DisplayCutout.fromBoundingRect;
import static android.view.WindowManager.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
import android.app.ActivityManager.TaskDescription;
import android.content.res.Configuration;
@@ -58,7 +61,7 @@
boolean mDockedResizingForTest = false;
WindowStateWithTask(WindowManagerService wm, IWindow iWindow, WindowToken windowToken,
WindowManager.LayoutParams attrs, Task t) {
- super(wm, null, iWindow, windowToken, null, 0, 0, attrs, 0, 0,
+ super(wm, mock(Session.class), iWindow, windowToken, null, 0, 0, attrs, 0, 0,
false /* ownerCanAddInternalSystemWindow */);
mTask = t;
}
@@ -113,9 +116,9 @@
@Before
public void setUp() throws Exception {
- mWindowToken = WindowTestUtils.createTestAppWindowToken(
- mWm.getDefaultDisplayContentLocked());
- mStubStack = new TaskStack(mWm, 0, null);
+ mWindowToken = createAppWindowToken(mWm.getDefaultDisplayContentLocked(),
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ mStubStack = WindowTestUtils.createMockTaskStack();
}
// Do not use this function directly in the tests below. Instead, use more explicit function
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
index 20fc5ae..44e998b7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
@@ -103,12 +103,10 @@
}
/**
- * Creates a mock instance of {@link StackWindowController}.
+ * Creates a mock instance of {@link TestTaskStack}.
*/
- public static StackWindowController createMockStackWindowContainerController() {
- StackWindowController controller = mock(StackWindowController.class);
- controller.mContainer = mock(TestTaskStack.class);
- return controller;
+ public static TaskStack createMockTaskStack() {
+ return mock(TestTaskStack.class);
}
/** Creates a {@link Task} and adds it to the specified {@link TaskStack}. */
@@ -201,6 +199,11 @@
}
@Override
+ void onParentSet() {
+ // Do nothing.
+ }
+
+ @Override
boolean isOnTop() {
return mOnTop;
}
@@ -283,10 +286,9 @@
}
}
- public static TestTask createTestTask(StackWindowController stackWindowController) {
- return new TestTask(sNextTaskId++, stackWindowController.mContainer, 0,
- stackWindowController.mService, RESIZE_MODE_UNRESIZEABLE, false,
- mock(TaskRecord.class));
+ public static TestTask createTestTask(TaskStack stack) {
+ return new TestTask(sNextTaskId++, stack, 0, stack.mWmService, RESIZE_MODE_UNRESIZEABLE,
+ false, mock(TaskRecord.class));
}
public static class TestIApplicationToken implements IApplicationToken {
@@ -334,5 +336,10 @@
mHasSurface = hadSurface;
}
+
+ @Override
+ void onParentSet() {
+ // Do nothing;
+ }
}
}
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 cdc0a47..89c1551 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -41,7 +41,6 @@
import android.content.Context;
import android.content.res.Configuration;
-import android.graphics.Rect;
import android.hardware.display.DisplayManagerGlobal;
import android.testing.DexmakerShareClassLoaderRule;
import android.util.Log;
@@ -240,8 +239,7 @@
WindowTestUtils.TestAppWindowToken createTestAppWindowToken(DisplayContent dc, int
windowingMode, int activityType) {
- final TaskStack stack = createStackControllerOnStackOnDisplay(windowingMode, activityType,
- dc).mContainer;
+ final TaskStack stack = createTaskStackOnDisplay(windowingMode, activityType, dc);
final Task task = createTaskInStack(stack, 0 /* userId */);
final WindowTestUtils.TestAppWindowToken appWindowToken =
WindowTestUtils.createTestAppWindowToken(dc);
@@ -350,28 +348,20 @@
/** Creates a {@link TaskStack} and adds it to the specified {@link DisplayContent}. */
TaskStack createTaskStackOnDisplay(DisplayContent dc) {
synchronized (mWm.mGlobalLock) {
- return createStackControllerOnDisplay(dc).mContainer;
+ return createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, dc);
}
}
- StackWindowController createStackControllerOnDisplay(DisplayContent dc) {
- synchronized (mWm.mGlobalLock) {
- return createStackControllerOnStackOnDisplay(
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, dc);
- }
- }
-
- StackWindowController createStackControllerOnStackOnDisplay(
- int windowingMode, int activityType, DisplayContent dc) {
+ TaskStack createTaskStackOnDisplay(int windowingMode, int activityType, DisplayContent dc) {
synchronized (mWm.mGlobalLock) {
final Configuration overrideConfig = new Configuration();
overrideConfig.windowConfiguration.setWindowingMode(windowingMode);
overrideConfig.windowConfiguration.setActivityType(activityType);
final int stackId = ++sNextStackId;
- final StackWindowController controller = new StackWindowController(stackId, null,
- dc.getDisplayId(), true /* onTop */, new Rect(), mWm);
- controller.onRequestedOverrideConfigurationChanged(overrideConfig);
- return controller;
+ final TaskStack stack = new TaskStack(mWm, stackId, mock(ActivityStack.class));
+ dc.setStackOnDisplay(stackId, true, stack);
+ stack.onRequestedOverrideConfigurationChanged(overrideConfig);
+ return stack;
}
}
diff --git a/services/usage/java/com/android/server/usage/IntervalStats.java b/services/usage/java/com/android/server/usage/IntervalStats.java
index 94cc650..9a5bd13 100644
--- a/services/usage/java/com/android/server/usage/IntervalStats.java
+++ b/services/usage/java/com/android/server/usage/IntervalStats.java
@@ -22,6 +22,7 @@
import static android.app.usage.UsageEvents.Event.CONFIGURATION_CHANGE;
import static android.app.usage.UsageEvents.Event.CONTINUE_PREVIOUS_DAY;
import static android.app.usage.UsageEvents.Event.CONTINUING_FOREGROUND_SERVICE;
+import static android.app.usage.UsageEvents.Event.DEVICE_SHUTDOWN;
import static android.app.usage.UsageEvents.Event.END_OF_DAY;
import static android.app.usage.UsageEvents.Event.FLUSH_TO_DISK;
import static android.app.usage.UsageEvents.Event.FOREGROUND_SERVICE_START;
@@ -66,7 +67,7 @@
public final ArrayMap<String, UsageStats> packageStats = new ArrayMap<>();
public final ArrayMap<Configuration, ConfigurationStats> configurations = new ArrayMap<>();
public Configuration activeConfiguration;
- public EventList events;
+ public EventList events = new EventList();
// A string cache. This is important as when we're parsing XML files, we don't want to
// keep hundreds of strings that have the same contents. We will read the string
@@ -112,6 +113,9 @@
}
+ public IntervalStats() {
+ }
+
/**
* Gets the UsageStats object for the given package, or creates one and adds it internally.
*/
@@ -253,6 +257,7 @@
case ROLLOVER_FOREGROUND_SERVICE:
case CONTINUE_PREVIOUS_DAY:
case CONTINUING_FOREGROUND_SERVICE:
+ case DEVICE_SHUTDOWN:
return true;
}
return false;
@@ -281,8 +286,9 @@
@VisibleForTesting
public void update(String packageName, String className, long timeStamp, int eventType,
int instanceId) {
- if (eventType == FLUSH_TO_DISK) {
- // FLUSH_TO_DISK are sent to all packages.
+ if (eventType == DEVICE_SHUTDOWN
+ || eventType == FLUSH_TO_DISK) {
+ // DEVICE_SHUTDOWN and FLUSH_TO_DISK are sent to all packages.
final int size = packageStats.size();
for (int i = 0; i < size; i++) {
UsageStats usageStats = packageStats.valueAt(i);
@@ -321,9 +327,6 @@
*/
@VisibleForTesting
public void addEvent(Event event) {
- if (events == null) {
- events = new EventList();
- }
// Cache common use strings
event.mPackage = getCachedStringRef(event.mPackage);
if (event.mClass != null) {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index f146370..76a3aa8 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -18,6 +18,7 @@
import static android.app.usage.UsageEvents.Event.CHOOSER_ACTION;
import static android.app.usage.UsageEvents.Event.CONFIGURATION_CHANGE;
+import static android.app.usage.UsageEvents.Event.DEVICE_SHUTDOWN;
import static android.app.usage.UsageEvents.Event.FLUSH_TO_DISK;
import static android.app.usage.UsageEvents.Event.NOTIFICATION_INTERRUPTION;
import static android.app.usage.UsageEvents.Event.SHORTCUT_INVOCATION;
@@ -416,11 +417,30 @@
*/
void shutdown() {
synchronized (mLock) {
+ mHandler.removeMessages(MSG_REPORT_EVENT);
+ Event event = new Event(DEVICE_SHUTDOWN, SystemClock.elapsedRealtime());
+ // orderly shutdown, the last event is DEVICE_SHUTDOWN.
+ reportEventToAllUserId(event);
flushToDiskLocked();
}
}
/**
+ * After power button is pressed for 3.5 seconds
+ * (as defined in {@link com.android.internal.R.integer#config_veryLongPressTimeout}),
+ * report DEVICE_SHUTDOWN event and persist the database. If the power button is pressed for 10
+ * seconds and the device is shutdown, the database is already persisted and we are not losing
+ * data.
+ * This method is called from PhoneWindowManager, do not synchronize on mLock otherwise
+ * PhoneWindowManager may be blocked.
+ */
+ void prepareForPossibleShutdown() {
+ Event event = new Event(DEVICE_SHUTDOWN, SystemClock.elapsedRealtime());
+ mHandler.obtainMessage(MSG_REPORT_EVENT_TO_ALL_USERID, event).sendToTarget();
+ mHandler.sendEmptyMessage(MSG_FLUSH_TO_DISK);
+ }
+
+ /**
* Called by the Binder stub.
*/
void reportEvent(Event event, int userId) {
@@ -1487,6 +1507,11 @@
}
@Override
+ public void prepareForPossibleShutdown() {
+ UsageStatsService.this.prepareForPossibleShutdown();
+ }
+
+ @Override
public void addAppIdleStateChangeListener(AppIdleStateChangeListener listener) {
mAppStandby.addListener(listener);
listener.onParoleStateChanged(isAppIdleParoleOn());
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index 5128ae1..2d1098c7 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -16,6 +16,7 @@
package com.android.server.usage;
+import static android.app.usage.UsageEvents.Event.DEVICE_SHUTDOWN;
import static android.app.usage.UsageStatsManager.INTERVAL_BEST;
import static android.app.usage.UsageStatsManager.INTERVAL_COUNT;
import static android.app.usage.UsageStatsManager.INTERVAL_DAILY;
@@ -134,6 +135,18 @@
updateRolloverDeadline();
}
+ // During system reboot, add a DEVICE_SHUTDOWN event to the end of event list, the timestamp
+ // is last time UsageStatsDatabase is persisted to disk.
+ final IntervalStats currentDailyStats = mCurrentStats[INTERVAL_DAILY];
+ if (currentDailyStats != null) {
+ final int size = currentDailyStats.events.size();
+ if (size == 0 || currentDailyStats.events.get(size - 1).mEventType != DEVICE_SHUTDOWN) {
+ // The last event in event list is not DEVICE_SHUTDOWN, then we insert one.
+ final Event event = new Event(DEVICE_SHUTDOWN, currentDailyStats.lastTimeSaved);
+ currentDailyStats.addEvent(event);
+ }
+ }
+
if (mDatabase.isNewUpdate()) {
notifyNewUpdate();
}
@@ -175,7 +188,9 @@
// ACTIVITY_STOPPED.
&& event.mEventType != Event.ACTIVITY_DESTROYED
// FLUSH_TO_DISK is a private event.
- && event.mEventType != Event.FLUSH_TO_DISK) {
+ && event.mEventType != Event.FLUSH_TO_DISK
+ // DEVICE_SHUTDOWN is added to event list after reboot.
+ && event.mEventType != Event.DEVICE_SHUTDOWN) {
currentDailyStats.addEvent(event);
}
@@ -393,10 +408,6 @@
@Override
public void combine(IntervalStats stats, boolean mutable,
List<Event> accumulatedResult) {
- if (stats.events == null) {
- return;
- }
-
final int startIndex = stats.events.firstIndexOnOrAfter(beginTime);
final int size = stats.events.size();
for (int i = startIndex; i < size; i++) {
@@ -434,10 +445,6 @@
names.add(packageName);
final List<Event> results = queryStats(INTERVAL_DAILY,
beginTime, endTime, (stats, mutable, accumulatedResult) -> {
- if (stats.events == null) {
- return;
- }
-
final int startIndex = stats.events.firstIndexOnOrAfter(beginTime);
final int size = stats.events.size();
for (int i = startIndex; i < size; i++) {
@@ -696,10 +703,6 @@
@Override
public void combine(IntervalStats stats, boolean mutable,
List<Event> accumulatedResult) {
- if (stats.events == null) {
- return;
- }
-
final int startIndex = stats.events.firstIndexOnOrAfter(beginTime);
final int size = stats.events.size();
for (int i = startIndex; i < size; i++) {
@@ -925,10 +928,12 @@
return "SCREEN_INTERACTIVE";
case Event.SCREEN_NON_INTERACTIVE:
return "SCREEN_NON_INTERACTIVE";
- case UsageEvents.Event.KEYGUARD_SHOWN:
+ case Event.KEYGUARD_SHOWN:
return "KEYGUARD_SHOWN";
- case UsageEvents.Event.KEYGUARD_HIDDEN:
+ case Event.KEYGUARD_HIDDEN:
return "KEYGUARD_HIDDEN";
+ case Event.DEVICE_SHUTDOWN:
+ return "DEVICE_SHUTDOWN";
default:
return "UNKNOWN_TYPE_" + eventType;
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index bbf3d45..613c4ff 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -371,14 +371,15 @@
}
private boolean shouldEnableService(Context context) {
- // VoiceInteractionService should not be enabled on any low RAM devices
- // or devices that have not declared the recognition feature, unless the
- // device's configuration has explicitly set the config flag for a fixed
+ // VoiceInteractionService should not be enabled on devices that have not declared the
+ // recognition feature (including low-ram devices where notLowRam="true" takes effect),
+ // unless the device's configuration has explicitly set the config flag for a fixed
// voice interaction service.
- return (!ActivityManager.isLowRamDeviceStatic()
- && context.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_VOICE_RECOGNIZERS)) ||
- getForceVoiceInteractionServicePackage(context.getResources()) != null;
+ if (getForceVoiceInteractionServicePackage(context.getResources()) != null) {
+ return true;
+ }
+ return context.getPackageManager()
+ .hasSystemFeature(PackageManager.FEATURE_VOICE_RECOGNIZERS);
}
private String getForceVoiceInteractionServicePackage(Resources res) {
diff --git a/startop/view_compiler/apk_layout_compiler.cc b/startop/view_compiler/apk_layout_compiler.cc
index e95041b..09cdbd5 100644
--- a/startop/view_compiler/apk_layout_compiler.cc
+++ b/startop/view_compiler/apk_layout_compiler.cc
@@ -79,9 +79,9 @@
return visitor.can_compile();
}
-void CompileApkLayouts(const std::string& filename, CompilationTarget target,
- std::ostream& target_out) {
- auto assets = android::ApkAssets::Load(filename);
+namespace {
+void CompileApkAssetsLayouts(const std::unique_ptr<const android::ApkAssets>& assets,
+ CompilationTarget target, std::ostream& target_out) {
android::AssetManager2 resources;
resources.SetApkAssets({assets.get()});
@@ -155,5 +155,20 @@
target_out.write(image.ptr<const char>(), image.size());
}
}
+} // namespace
+
+void CompileApkLayouts(const std::string& filename, CompilationTarget target,
+ std::ostream& target_out) {
+ auto assets = android::ApkAssets::Load(filename);
+ CompileApkAssetsLayouts(assets, target, target_out);
+}
+
+void CompileApkLayoutsFd(android::base::unique_fd fd, CompilationTarget target,
+ std::ostream& target_out) {
+ constexpr const char* friendly_name{"viewcompiler assets"};
+ auto assets = android::ApkAssets::LoadFromFd(
+ std::move(fd), friendly_name, /*system=*/false, /*force_shared_lib=*/false);
+ CompileApkAssetsLayouts(assets, target, target_out);
+}
} // namespace startop
diff --git a/startop/view_compiler/apk_layout_compiler.h b/startop/view_compiler/apk_layout_compiler.h
index c85ddd6..03bd545 100644
--- a/startop/view_compiler/apk_layout_compiler.h
+++ b/startop/view_compiler/apk_layout_compiler.h
@@ -19,12 +19,16 @@
#include <string>
+#include "android-base/unique_fd.h"
+
namespace startop {
enum class CompilationTarget { kJavaLanguage, kDex };
void CompileApkLayouts(const std::string& filename, CompilationTarget target,
std::ostream& target_out);
+void CompileApkLayoutsFd(android::base::unique_fd fd, CompilationTarget target,
+ std::ostream& target_out);
} // namespace startop
diff --git a/startop/view_compiler/main.cc b/startop/view_compiler/main.cc
index 871a421..11ecde2 100644
--- a/startop/view_compiler/main.cc
+++ b/startop/view_compiler/main.cc
@@ -49,6 +49,7 @@
DEFINE_bool(apk, false, "Compile layouts in an APK");
DEFINE_bool(dex, false, "Generate a DEX file instead of Java");
+DEFINE_int32(infd, -1, "Read input from the given file descriptor");
DEFINE_string(out, kStdoutFilename, "Where to write the generated class");
DEFINE_string(package, "", "The package name for the generated class (required)");
@@ -95,7 +96,7 @@
int main(int argc, char** argv) {
constexpr size_t kProgramName = 0;
constexpr size_t kFileNameParam = 1;
- constexpr size_t kNumRequiredArgs = 2;
+ constexpr size_t kNumRequiredArgs = 1;
gflags::SetUsageMessage(
"Compile XML layout files into equivalent Java language code\n"
@@ -104,12 +105,11 @@
gflags::ParseCommandLineFlags(&argc, &argv, /*remove_flags*/ true);
gflags::CommandLineFlagInfo cmd = gflags::GetCommandLineFlagInfoOrDie("package");
- if (argc != kNumRequiredArgs || cmd.is_default) {
+ if (argc < kNumRequiredArgs || cmd.is_default) {
gflags::ShowUsageWithFlags(argv[kProgramName]);
return 1;
}
- const char* const filename = argv[kFileNameParam];
const bool is_stdout = FLAGS_out == kStdoutFilename;
std::ofstream outfile;
@@ -118,13 +118,23 @@
}
if (FLAGS_apk) {
- startop::CompileApkLayouts(
- filename,
- FLAGS_dex ? startop::CompilationTarget::kDex : startop::CompilationTarget::kJavaLanguage,
- is_stdout ? std::cout : outfile);
+ const startop::CompilationTarget target =
+ FLAGS_dex ? startop::CompilationTarget::kDex : startop::CompilationTarget::kJavaLanguage;
+ if (FLAGS_infd >= 0) {
+ startop::CompileApkLayoutsFd(
+ android::base::unique_fd{FLAGS_infd}, target, is_stdout ? std::cout : outfile);
+ } else {
+ if (argc < 2) {
+ gflags::ShowUsageWithFlags(argv[kProgramName]);
+ return 1;
+ }
+ const char* const filename = argv[kFileNameParam];
+ startop::CompileApkLayouts(filename, target, is_stdout ? std::cout : outfile);
+ }
return 0;
}
+ const char* const filename = argv[kFileNameParam];
const string layout_name = startop::util::FindLayoutNameFromFilename(filename);
XMLDocument xml;
diff --git a/telephony/java/android/telephony/AvailableNetworkInfo.java b/telephony/java/android/telephony/AvailableNetworkInfo.java
index fe07370..4da79b3 100644
--- a/telephony/java/android/telephony/AvailableNetworkInfo.java
+++ b/telephony/java/android/telephony/AvailableNetworkInfo.java
@@ -110,6 +110,7 @@
private AvailableNetworkInfo(Parcel in) {
mSubId = in.readInt();
mPriority = in.readInt();
+ mMccMncs = new ArrayList<>();
in.readStringList(mMccMncs);
}
diff --git a/telephony/java/android/telephony/CellConfigLte.java b/telephony/java/android/telephony/CellConfigLte.java
index 35769f0..eafbfbc 100644
--- a/telephony/java/android/telephony/CellConfigLte.java
+++ b/telephony/java/android/telephony/CellConfigLte.java
@@ -34,6 +34,11 @@
}
/** @hide */
+ public CellConfigLte(android.hardware.radio.V1_4.CellConfigLte cellConfig) {
+ mIsEndcAvailable = cellConfig.isEndcAvailable;
+ }
+
+ /** @hide */
public CellConfigLte(boolean isEndcAvailable) {
mIsEndcAvailable = isEndcAvailable;
}
diff --git a/telephony/java/android/telephony/CellInfo.java b/telephony/java/android/telephony/CellInfo.java
index b761bd7..8ce5c54 100644
--- a/telephony/java/android/telephony/CellInfo.java
+++ b/telephony/java/android/telephony/CellInfo.java
@@ -19,8 +19,10 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.UnsupportedAppUsage;
+import android.hardware.radio.V1_4.CellInfo.Info;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.SystemClock;
import com.android.internal.annotations.VisibleForTesting;
@@ -318,6 +320,13 @@
}
/** @hide */
+ protected CellInfo(android.hardware.radio.V1_4.CellInfo ci) {
+ this.mRegistered = ci.isRegistered;
+ this.mTimeStamp = SystemClock.elapsedRealtimeNanos();
+ this.mCellConnectionStatus = ci.connectionStatus;
+ }
+
+ /** @hide */
public static CellInfo create(android.hardware.radio.V1_0.CellInfo ci) {
if (ci == null) return null;
switch(ci.cellInfoType) {
@@ -342,4 +351,17 @@
default: return null;
}
}
+
+ /** @hide */
+ public static CellInfo create(android.hardware.radio.V1_4.CellInfo ci) {
+ if (ci == null) return null;
+ switch (ci.info.getDiscriminator()) {
+ case Info.hidl_discriminator.gsm: return new CellInfoGsm(ci);
+ case Info.hidl_discriminator.cdma: return new CellInfoCdma(ci);
+ case Info.hidl_discriminator.lte: return new CellInfoLte(ci);
+ case Info.hidl_discriminator.wcdma: return new CellInfoWcdma(ci);
+ case Info.hidl_discriminator.tdscdma: return new CellInfoTdscdma(ci);
+ default: return null;
+ }
+ }
}
diff --git a/telephony/java/android/telephony/CellInfoCdma.java b/telephony/java/android/telephony/CellInfoCdma.java
index c9f07da..4440108 100644
--- a/telephony/java/android/telephony/CellInfoCdma.java
+++ b/telephony/java/android/telephony/CellInfoCdma.java
@@ -67,6 +67,15 @@
new CellSignalStrengthCdma(cic.signalStrengthCdma, cic.signalStrengthEvdo);
}
+ /** @hide */
+ public CellInfoCdma(android.hardware.radio.V1_4.CellInfo ci) {
+ super(ci);
+ final android.hardware.radio.V1_2.CellInfoCdma cic = ci.info.cdma();
+ mCellIdentityCdma = new CellIdentityCdma(cic.cellIdentityCdma);
+ mCellSignalStrengthCdma =
+ new CellSignalStrengthCdma(cic.signalStrengthCdma, cic.signalStrengthEvdo);
+ }
+
@Override
public CellIdentityCdma getCellIdentity() {
return mCellIdentityCdma;
diff --git a/telephony/java/android/telephony/CellInfoGsm.java b/telephony/java/android/telephony/CellInfoGsm.java
index ad16dfa..248adfc 100644
--- a/telephony/java/android/telephony/CellInfoGsm.java
+++ b/telephony/java/android/telephony/CellInfoGsm.java
@@ -63,6 +63,14 @@
mCellSignalStrengthGsm = new CellSignalStrengthGsm(cig.signalStrengthGsm);
}
+ /** @hide */
+ public CellInfoGsm(android.hardware.radio.V1_4.CellInfo ci) {
+ super(ci);
+ final android.hardware.radio.V1_2.CellInfoGsm cig = ci.info.gsm();
+ mCellIdentityGsm = new CellIdentityGsm(cig.cellIdentityGsm);
+ mCellSignalStrengthGsm = new CellSignalStrengthGsm(cig.signalStrengthGsm);
+ }
+
@Override
public CellIdentityGsm getCellIdentity() {
return mCellIdentityGsm;
diff --git a/telephony/java/android/telephony/CellInfoLte.java b/telephony/java/android/telephony/CellInfoLte.java
index 7593831..8e8ce8a 100644
--- a/telephony/java/android/telephony/CellInfoLte.java
+++ b/telephony/java/android/telephony/CellInfoLte.java
@@ -70,6 +70,15 @@
mCellConfig = new CellConfigLte();
}
+ /** @hide */
+ public CellInfoLte(android.hardware.radio.V1_4.CellInfo ci) {
+ super(ci);
+ final android.hardware.radio.V1_4.CellInfoLte cil = ci.info.lte();
+ mCellIdentityLte = new CellIdentityLte(cil.base.cellIdentityLte);
+ mCellSignalStrengthLte = new CellSignalStrengthLte(cil.base.signalStrengthLte);
+ mCellConfig = new CellConfigLte(cil.cellConfig);
+ }
+
@Override
public CellIdentityLte getCellIdentity() {
if (DBG) log("getCellIdentity: " + mCellIdentityLte);
diff --git a/telephony/java/android/telephony/CellInfoTdscdma.java b/telephony/java/android/telephony/CellInfoTdscdma.java
index a8c49b7..2ab38fb 100644
--- a/telephony/java/android/telephony/CellInfoTdscdma.java
+++ b/telephony/java/android/telephony/CellInfoTdscdma.java
@@ -64,6 +64,14 @@
mCellSignalStrengthTdscdma = new CellSignalStrengthTdscdma(cit.signalStrengthTdscdma);
}
+ /** @hide */
+ public CellInfoTdscdma(android.hardware.radio.V1_4.CellInfo ci) {
+ super(ci);
+ final android.hardware.radio.V1_2.CellInfoTdscdma cit = ci.info.tdscdma();
+ mCellIdentityTdscdma = new CellIdentityTdscdma(cit.cellIdentityTdscdma);
+ mCellSignalStrengthTdscdma = new CellSignalStrengthTdscdma(cit.signalStrengthTdscdma);
+ }
+
@Override public CellIdentityTdscdma getCellIdentity() {
return mCellIdentityTdscdma;
}
diff --git a/telephony/java/android/telephony/CellInfoWcdma.java b/telephony/java/android/telephony/CellInfoWcdma.java
index a427e80..65e0470 100644
--- a/telephony/java/android/telephony/CellInfoWcdma.java
+++ b/telephony/java/android/telephony/CellInfoWcdma.java
@@ -63,6 +63,14 @@
mCellSignalStrengthWcdma = new CellSignalStrengthWcdma(ciw.signalStrengthWcdma);
}
+ /** @hide */
+ public CellInfoWcdma(android.hardware.radio.V1_4.CellInfo ci) {
+ super(ci);
+ final android.hardware.radio.V1_2.CellInfoWcdma ciw = ci.info.wcdma();
+ mCellIdentityWcdma = new CellIdentityWcdma(ciw.cellIdentityWcdma);
+ mCellSignalStrengthWcdma = new CellSignalStrengthWcdma(ciw.signalStrengthWcdma);
+ }
+
@Override
public CellIdentityWcdma getCellIdentity() {
return mCellIdentityWcdma;
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index babeb7b..3311218 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -9963,7 +9963,7 @@
boolean ret = false;
try {
IOns iOpportunisticNetworkService = getIOns();
- if (iOpportunisticNetworkService != null) {
+ if (iOpportunisticNetworkService != null && availableNetworks != null) {
ret = iOpportunisticNetworkService.updateAvailableNetworks(availableNetworks,
pkgForDebug);
}
diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java
index 96f7a1b..3408291 100644
--- a/telephony/java/com/android/internal/telephony/DctConstants.java
+++ b/telephony/java/com/android/internal/telephony/DctConstants.java
@@ -92,6 +92,7 @@
public static final int EVENT_DATA_RECONNECT = BASE + 47;
public static final int EVENT_ROAMING_SETTING_CHANGE = BASE + 48;
public static final int EVENT_DATA_SERVICE_BINDING_CHANGED = BASE + 49;
+ public static final int EVENT_DEVICE_PROVISIONED_CHANGE = BASE + 50;
/***** Constants *****/
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index 2a648bd..8523554 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -501,4 +501,18 @@
*/
public static final String ACTION_LINE1_NUMBER_ERROR_DETECTED =
"com.android.internal.telephony.ACTION_LINE1_NUMBER_ERROR_DETECTED";
+
+ /**
+ * Broadcast action to notify radio bug.
+ *
+ * Requires the READ_PRIVILEGED_PHONE_STATE permission.
+ *
+ * @hide
+ */
+ public static final String ACTION_REPORT_RADIO_BUG =
+ "com.android.internal.telephony.ACTION_REPORT_RADIO_BUG";
+
+ // ACTION_REPORT_RADIO_BUG extra keys
+ public static final String EXTRA_SLOT_ID = "slotId";
+ public static final String EXTRA_RADIO_BUG_TYPE = "radioBugType";
}
diff --git a/test-base/api/current.txt b/test-base/api/current.txt
index 7ebd6aa..91fcca5 100644
--- a/test-base/api/current.txt
+++ b/test-base/api/current.txt
@@ -48,6 +48,9 @@
method public abstract void startTiming(boolean);
}
+ public abstract deprecated class RepetitiveTest implements java.lang.annotation.Annotation {
+ }
+
public abstract deprecated class UiThreadTest implements java.lang.annotation.Annotation {
}
diff --git a/test-base/src/android/test/RepetitiveTest.java b/test-base/src/android/test/RepetitiveTest.java
index 6a7130e..13e89d2 100644
--- a/test-base/src/android/test/RepetitiveTest.java
+++ b/test-base/src/android/test/RepetitiveTest.java
@@ -26,8 +26,10 @@
* When the annotation is present, the test method is executed the number of times specified by
* numIterations and defaults to 1.
*
- * {@hide} Not needed for public API.
+ * @deprecated New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
*/
+@Deprecated
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RepetitiveTest {
@@ -37,4 +39,4 @@
* @return The total number of iterations, the default is 1.
*/
int numIterations() default 1;
-}
\ No newline at end of file
+}
diff --git a/test-legacy/Android.bp b/test-legacy/Android.bp
index 833c714..a69f422 100644
--- a/test-legacy/Android.bp
+++ b/test-legacy/Android.bp
@@ -25,7 +25,7 @@
static_libs: [
"android.test.base-minus-junit",
"android.test.runner-minus-junit",
- "android.test.mock.impl",
+ "android.test.mock_static",
],
no_framework_libs: true,
diff --git a/test-mock/Android.bp b/test-mock/Android.bp
index e1d6e01..43b765d 100644
--- a/test-mock/Android.bp
+++ b/test-mock/Android.bp
@@ -30,3 +30,19 @@
srcs_lib_whitelist_pkgs: ["android"],
compile_dex: true,
}
+
+// Build the android.test.mock_static library
+// ==========================================
+// This is only intended for inclusion in the legacy-android-test.
+// Must not be used elewhere.
+java_library_static {
+ name: "android.test.mock_static",
+
+ java_version: "1.8",
+ srcs: ["src/**/*.java"],
+
+ no_framework_libs: true,
+ libs: [
+ "framework",
+ ],
+}
diff --git a/tests/net/java/android/net/LinkPropertiesTest.java b/tests/net/java/android/net/LinkPropertiesTest.java
index 932fee0..299fbef 100644
--- a/tests/net/java/android/net/LinkPropertiesTest.java
+++ b/tests/net/java/android/net/LinkPropertiesTest.java
@@ -849,6 +849,18 @@
assertEquals(new ArraySet<>(expectRemoved), (new ArraySet<>(result.removed)));
}
+ private void assertParcelingIsLossless(LinkProperties source) {
+ Parcel p = Parcel.obtain();
+ source.writeToParcel(p, /* flags */ 0);
+ p.setDataPosition(0);
+ final byte[] marshalled = p.marshall();
+ p = Parcel.obtain();
+ p.unmarshall(marshalled, 0, marshalled.length);
+ p.setDataPosition(0);
+ LinkProperties dest = LinkProperties.CREATOR.createFromParcel(p);
+ assertEquals(source, dest);
+ }
+
@Test
public void testLinkPropertiesParcelable() throws Exception {
LinkProperties source = new LinkProperties();
@@ -870,15 +882,12 @@
source.setNat64Prefix(new IpPrefix("2001:db8:1:2:64:64::/96"));
- Parcel p = Parcel.obtain();
- source.writeToParcel(p, /* flags */ 0);
- p.setDataPosition(0);
- final byte[] marshalled = p.marshall();
- p = Parcel.obtain();
- p.unmarshall(marshalled, 0, marshalled.length);
- p.setDataPosition(0);
- LinkProperties dest = LinkProperties.CREATOR.createFromParcel(p);
+ assertParcelingIsLossless(source);
+ }
- assertEquals(source, dest);
+ @Test
+ public void testParcelUninitialized() throws Exception {
+ LinkProperties empty = new LinkProperties();
+ assertParcelingIsLossless(empty);
}
}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index bf39644..2a92a7d 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -4683,7 +4683,7 @@
mCellNetworkAgent.sendLinkProperties(cellLp);
mCellNetworkAgent.connect(true);
networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- verify(mNetworkManagementService, times(1)).startClatd(MOBILE_IFNAME);
+ verify(mMockNetd, times(1)).clatdStart(MOBILE_IFNAME);
Nat464Xlat clat = mService.getNat464Xlat(mCellNetworkAgent);
// Clat iface up, expect stack link updated.
@@ -4710,7 +4710,7 @@
mCellNetworkAgent.sendLinkProperties(cellLp);
waitForIdle();
networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
- verify(mNetworkManagementService, times(1)).stopClatd(MOBILE_IFNAME);
+ verify(mMockNetd, times(1)).clatdStop(MOBILE_IFNAME);
// Clat iface removed, expect linkproperties revert to original one
clat.interfaceRemoved(CLAT_PREFIX + MOBILE_IFNAME);
diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
index 4c52d81..9578ded 100644
--- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -32,11 +32,13 @@
import android.content.Context;
import android.content.res.Resources;
import android.net.ConnectivityManager;
+import android.net.INetd;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkMisc;
import android.net.NetworkStack;
+import android.os.INetworkManagementService;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.text.format.DateUtils;
@@ -66,6 +68,8 @@
LingerMonitor mMonitor;
@Mock ConnectivityService mConnService;
+ @Mock INetd mNetd;
+ @Mock INetworkManagementService mNMS;
@Mock Context mCtx;
@Mock NetworkMisc mMisc;
@Mock NetworkNotificationManager mNotifier;
@@ -352,7 +356,7 @@
caps.addCapability(0);
caps.addTransportType(transport);
NetworkAgentInfo nai = new NetworkAgentInfo(null, null, new Network(netId), info, null,
- caps, 50, mCtx, null, mMisc, mConnService);
+ caps, 50, mCtx, null, mMisc, mConnService, mNetd, mNMS);
nai.everValidated = true;
return nai;
}
diff --git a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
index bf42412..07b1d05 100644
--- a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
+++ b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
@@ -17,9 +17,7 @@
package com.android.server.connectivity;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.any;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -27,6 +25,7 @@
import static org.mockito.Mockito.when;
import android.net.ConnectivityManager;
+import android.net.INetd;
import android.net.InterfaceConfiguration;
import android.net.LinkAddress;
import android.net.LinkProperties;
@@ -57,6 +56,7 @@
@Mock ConnectivityService mConnectivity;
@Mock NetworkMisc mMisc;
+ @Mock INetd mNetd;
@Mock INetworkManagementService mNms;
@Mock InterfaceConfiguration mConfig;
@Mock NetworkAgentInfo mNai;
@@ -65,7 +65,7 @@
Handler mHandler;
Nat464Xlat makeNat464Xlat() {
- return new Nat464Xlat(mNms, mNai);
+ return new Nat464Xlat(mNai, mNetd, mNms);
}
@Before
@@ -129,7 +129,7 @@
nat.start();
verify(mNms).registerObserver(eq(nat));
- verify(mNms).startClatd(eq(BASE_IFACE));
+ verify(mNetd).clatdStart(eq(BASE_IFACE));
// Stacked interface up notification arrives.
nat.interfaceLinkStateChanged(STACKED_IFACE, true);
@@ -144,7 +144,7 @@
// ConnectivityService stops clat (Network disconnects, IPv4 addr appears, ...).
nat.stop();
- verify(mNms).stopClatd(eq(BASE_IFACE));
+ verify(mNetd).clatdStop(eq(BASE_IFACE));
// Stacked interface removed notification arrives.
nat.interfaceRemoved(STACKED_IFACE);
@@ -156,7 +156,7 @@
assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
assertIdle(nat);
- verifyNoMoreInteractions(mNms, mConnectivity);
+ verifyNoMoreInteractions(mNetd, mNms, mConnectivity);
}
@Test
@@ -168,7 +168,7 @@
nat.start();
verify(mNms).registerObserver(eq(nat));
- verify(mNms).startClatd(eq(BASE_IFACE));
+ verify(mNetd).clatdStart(eq(BASE_IFACE));
// Stacked interface up notification arrives.
nat.interfaceLinkStateChanged(STACKED_IFACE, true);
@@ -185,7 +185,7 @@
mLooper.dispatchNext();
verify(mNms).unregisterObserver(eq(nat));
- verify(mNms).stopClatd(eq(BASE_IFACE));
+ verify(mNetd).clatdStop(eq(BASE_IFACE));
verify(mConnectivity, times(2)).handleUpdateLinkProperties(eq(mNai), c.capture());
assertTrue(c.getValue().getStackedLinks().isEmpty());
assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
@@ -194,7 +194,7 @@
// ConnectivityService stops clat: no-op.
nat.stop();
- verifyNoMoreInteractions(mNms, mConnectivity);
+ verifyNoMoreInteractions(mNetd, mNms, mConnectivity);
}
@Test
@@ -205,13 +205,13 @@
nat.start();
verify(mNms).registerObserver(eq(nat));
- verify(mNms).startClatd(eq(BASE_IFACE));
+ verify(mNetd).clatdStart(eq(BASE_IFACE));
// ConnectivityService immediately stops clat (Network disconnects, IPv4 addr appears, ...)
nat.stop();
verify(mNms).unregisterObserver(eq(nat));
- verify(mNms).stopClatd(eq(BASE_IFACE));
+ verify(mNetd).clatdStop(eq(BASE_IFACE));
assertIdle(nat);
// In-flight interface up notification arrives: no-op
@@ -225,7 +225,7 @@
assertIdle(nat);
- verifyNoMoreInteractions(mNms, mConnectivity);
+ verifyNoMoreInteractions(mNetd, mNms, mConnectivity);
}
@Test
@@ -236,16 +236,16 @@
nat.start();
verify(mNms).registerObserver(eq(nat));
- verify(mNms).startClatd(eq(BASE_IFACE));
+ verify(mNetd).clatdStart(eq(BASE_IFACE));
// ConnectivityService immediately stops clat (Network disconnects, IPv4 addr appears, ...)
nat.stop();
verify(mNms).unregisterObserver(eq(nat));
- verify(mNms).stopClatd(eq(BASE_IFACE));
+ verify(mNetd).clatdStop(eq(BASE_IFACE));
assertIdle(nat);
- verifyNoMoreInteractions(mNms, mConnectivity);
+ verifyNoMoreInteractions(mNetd, mNms, mConnectivity);
}
static void assertIdle(Nat464Xlat nat) {
diff --git a/tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java b/tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java
index 859a54d..e63c3b0 100644
--- a/tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java
+++ b/tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java
@@ -16,6 +16,9 @@
package com.android.server.net.ipmemorystore;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doReturn;
+
import android.content.Context;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -26,6 +29,8 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.io.File;
+
/** Unit tests for {@link IpMemoryStoreServiceTest}. */
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -36,6 +41,7 @@
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+ doReturn(new File("/tmp/test.db")).when(mMockContext).getDatabasePath(anyString());
}
@Test
diff --git a/tests/net/java/com/android/server/net/ipmemorystore/RelevanceUtilsTests.java b/tests/net/java/com/android/server/net/ipmemorystore/RelevanceUtilsTests.java
new file mode 100644
index 0000000..8d367e2
--- /dev/null
+++ b/tests/net/java/com/android/server/net/ipmemorystore/RelevanceUtilsTests.java
@@ -0,0 +1,149 @@
+/*
+ * 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.server.net.ipmemorystore;
+
+import static com.android.server.net.ipmemorystore.RelevanceUtils.CAPPED_RELEVANCE;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Unit tests for {@link RelevanceUtils}. */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RelevanceUtilsTests {
+ @Test
+ public void testComputeRelevanceForTargetDate() {
+ final long dayInMillis = 24L * 60 * 60 * 1000;
+ final long base = 1_000_000L; // any given point in time
+ // Relevance when the network expires in 1000 years must be capped
+ assertEquals(CAPPED_RELEVANCE, RelevanceUtils.computeRelevanceForTargetDate(
+ base + 1000L * dayInMillis, base));
+ // Relevance when expiry is before the date must be 0
+ assertEquals(0, RelevanceUtils.computeRelevanceForTargetDate(base - 1, base));
+ // Make sure the relevance for a given target date is higher if the expiry is further
+ // in the future
+ assertTrue(RelevanceUtils.computeRelevanceForTargetDate(base + 100 * dayInMillis, base)
+ < RelevanceUtils.computeRelevanceForTargetDate(base + 150 * dayInMillis, base));
+
+ // Make sure the relevance falls slower as the expiry is closing in. This is to ensure
+ // the decay is indeed logarithmic.
+ final int relevanceAtExpiry = RelevanceUtils.computeRelevanceForTargetDate(base, base);
+ final int relevance50DaysBeforeExpiry =
+ RelevanceUtils.computeRelevanceForTargetDate(base + 50 * dayInMillis, base);
+ final int relevance100DaysBeforeExpiry =
+ RelevanceUtils.computeRelevanceForTargetDate(base + 100 * dayInMillis, base);
+ final int relevance150DaysBeforeExpiry =
+ RelevanceUtils.computeRelevanceForTargetDate(base + 150 * dayInMillis, base);
+ assertEquals(0, relevanceAtExpiry);
+ assertTrue(relevance50DaysBeforeExpiry - relevanceAtExpiry
+ < relevance100DaysBeforeExpiry - relevance50DaysBeforeExpiry);
+ assertTrue(relevance100DaysBeforeExpiry - relevance50DaysBeforeExpiry
+ < relevance150DaysBeforeExpiry - relevance100DaysBeforeExpiry);
+ }
+
+ @Test
+ public void testIncreaseRelevance() {
+ long expiry = System.currentTimeMillis();
+
+ final long firstBump = RelevanceUtils.bumpExpiryDate(expiry);
+ // Though a few milliseconds might have elapsed, the first bump should push the duration
+ // to days in the future, so unless this test takes literal days between these two lines,
+ // this should always pass.
+ assertTrue(firstBump > expiry);
+
+ expiry = 0;
+ long lastDifference = Long.MAX_VALUE;
+ // The relevance should be capped in at most this many steps. Otherwise, fail.
+ final int steps = 1000;
+ for (int i = 0; i < steps; ++i) {
+ final long newExpiry = RelevanceUtils.bumpExpiryDuration(expiry);
+ if (newExpiry == expiry) {
+ // The relevance should be capped. Make sure it is, then exit without failure.
+ assertEquals(newExpiry, RelevanceUtils.CAPPED_RELEVANCE_LIFETIME_MS);
+ return;
+ }
+ // Make sure the new expiry is further in the future than last time.
+ assertTrue(newExpiry > expiry);
+ // Also check that it was not bumped as much as the last bump, because the
+ // decay must be exponential.
+ assertTrue(newExpiry - expiry < lastDifference);
+ lastDifference = newExpiry - expiry;
+ expiry = newExpiry;
+ }
+ fail("Relevance failed to go to the maximum value after " + steps + " bumps");
+ }
+
+ @Test
+ public void testContinuity() {
+ final long expiry = System.currentTimeMillis();
+
+ // Relevance at expiry and after expiry should be the cap.
+ final int relevanceBeforeMaxLifetime = RelevanceUtils.computeRelevanceForTargetDate(expiry,
+ expiry - (RelevanceUtils.CAPPED_RELEVANCE_LIFETIME_MS + 1_000_000));
+ assertEquals(relevanceBeforeMaxLifetime, CAPPED_RELEVANCE);
+ final int relevanceForMaxLifetime = RelevanceUtils.computeRelevanceForTargetDate(expiry,
+ expiry - RelevanceUtils.CAPPED_RELEVANCE_LIFETIME_MS);
+ assertEquals(relevanceForMaxLifetime, CAPPED_RELEVANCE);
+
+ // If the max relevance is reached at the cap lifetime, one millisecond less than this
+ // should be very close. Strictly speaking this is a bit brittle, but it should be
+ // good enough for the purposes of the memory store.
+ final int relevanceForOneMillisecLessThanCap = RelevanceUtils.computeRelevanceForTargetDate(
+ expiry, expiry - RelevanceUtils.CAPPED_RELEVANCE_LIFETIME_MS + 1);
+ assertTrue(relevanceForOneMillisecLessThanCap <= CAPPED_RELEVANCE);
+ assertTrue(relevanceForOneMillisecLessThanCap >= CAPPED_RELEVANCE - 10);
+
+ // Likewise the relevance one millisecond before expiry should be very close to 0. It's
+ // fine if it rounds down to 0.
+ final int relevanceOneMillisecBeforeExpiry = RelevanceUtils.computeRelevanceForTargetDate(
+ expiry, expiry - 1);
+ assertTrue(relevanceOneMillisecBeforeExpiry <= 10);
+ assertTrue(relevanceOneMillisecBeforeExpiry >= 0);
+
+ final int relevanceAtExpiry = RelevanceUtils.computeRelevanceForTargetDate(expiry, expiry);
+ assertEquals(relevanceAtExpiry, 0);
+ final int relevanceAfterExpiry = RelevanceUtils.computeRelevanceForTargetDate(expiry,
+ expiry + 1_000_000);
+ assertEquals(relevanceAfterExpiry, 0);
+ }
+
+ // testIncreaseRelevance makes sure bumping the expiry continuously always yields a
+ // monotonically increasing date as a side effect, but this tests that the relevance (as
+ // opposed to the expiry date) increases monotonically with increasing periods.
+ @Test
+ public void testMonotonicity() {
+ // Hopefully the relevance is granular enough to give a different value for every one
+ // of this number of steps.
+ final int steps = 40;
+ final long expiry = System.currentTimeMillis();
+
+ int lastRelevance = -1;
+ for (int i = 0; i < steps; ++i) {
+ final long date = expiry - i * (RelevanceUtils.CAPPED_RELEVANCE_LIFETIME_MS / steps);
+ final int relevance = RelevanceUtils.computeRelevanceForTargetDate(expiry, date);
+ assertTrue(relevance > lastRelevance);
+ lastRelevance = relevance;
+ }
+ }
+}
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index c6f9152..ab4805f 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -16,6 +16,7 @@
#include "ResourceUtils.h"
+#include <algorithm>
#include <sstream>
#include "android-base/stringprintf.h"
@@ -503,6 +504,14 @@
if (entry.first == trimmed_str) {
return entry.second;
}
+
+ // Try parsing codename from "[codename].[preview_sdk_fingerprint]" value.
+ const StringPiece::const_iterator begin = std::begin(trimmed_str);
+ const StringPiece::const_iterator end = std::end(trimmed_str);
+ const StringPiece::const_iterator codename_end = std::find(begin, end, '.');
+ if (codename_end != end && entry.first == trimmed_str.substr(begin, codename_end)) {
+ return entry.second;
+ }
return {};
}
diff --git a/tools/aapt2/ResourceUtils_test.cpp b/tools/aapt2/ResourceUtils_test.cpp
index 5ce4640..9018b0f 100644
--- a/tools/aapt2/ResourceUtils_test.cpp
+++ b/tools/aapt2/ResourceUtils_test.cpp
@@ -16,6 +16,7 @@
#include "ResourceUtils.h"
+#include "SdkConstants.h"
#include "Resource.h"
#include "test/Test.h"
@@ -212,6 +213,17 @@
Pointee(ValueEq(BinaryPrimitive(Res_value::TYPE_FLOAT, expected_float_flattened))));
}
+TEST(ResourceUtilsTest, ParseSdkVersionWithCodename) {
+ const android::StringPiece codename =
+ GetDevelopmentSdkCodeNameAndVersion().first;
+ const int version = GetDevelopmentSdkCodeNameAndVersion().second;
+
+ EXPECT_THAT(ResourceUtils::ParseSdkVersion(codename), Eq(Maybe<int>(version)));
+ EXPECT_THAT(
+ ResourceUtils::ParseSdkVersion(codename.to_string() + ".fingerprint"),
+ Eq(Maybe<int>(version)));
+}
+
TEST(ResourceUtilsTest, StringBuilderWhitespaceRemoval) {
EXPECT_THAT(ResourceUtils::StringBuilder()
.AppendText(" hey guys ")
diff --git a/tools/aapt2/format/binary/BinaryResourceParser.cpp b/tools/aapt2/format/binary/BinaryResourceParser.cpp
index c496ff0..7d4c6f3 100644
--- a/tools/aapt2/format/binary/BinaryResourceParser.cpp
+++ b/tools/aapt2/format/binary/BinaryResourceParser.cpp
@@ -42,6 +42,19 @@
namespace {
+static std::u16string strcpy16_dtoh(const char16_t* src, size_t len) {
+ size_t utf16_len = strnlen16(src, len);
+ if (utf16_len == 0) {
+ return {};
+ }
+ std::u16string dst;
+ dst.resize(utf16_len);
+ for (size_t i = 0; i < utf16_len; i++) {
+ dst[i] = util::DeviceToHost16(src[i]);
+ }
+ return dst;
+}
+
// Visitor that converts a reference's resource ID to a resource name, given a mapping from
// resource ID to resource name.
class ReferenceIdToNameVisitor : public DescendingValueVisitor {
@@ -176,12 +189,8 @@
}
// Extract the package name.
- size_t len = strnlen16((const char16_t*)package_header->name, arraysize(package_header->name));
- std::u16string package_name;
- package_name.resize(len);
- for (size_t i = 0; i < len; i++) {
- package_name[i] = util::DeviceToHost16(package_header->name[i]);
- }
+ std::u16string package_name = strcpy16_dtoh((const char16_t*)package_header->name,
+ arraysize(package_header->name));
ResourceTablePackage* package =
table_->CreatePackage(util::Utf16ToUtf8(package_name), static_cast<uint8_t>(package_id));
@@ -435,6 +444,11 @@
}
auto overlayable = std::make_shared<Overlayable>();
+ overlayable->name = util::Utf16ToUtf8(strcpy16_dtoh((const char16_t*)header->name,
+ arraysize(header->name)));
+ overlayable->actor = util::Utf16ToUtf8(strcpy16_dtoh((const char16_t*)header->actor,
+ arraysize(header->name)));
+ overlayable->source = source_.WithLine(0);
ResChunkPullParser parser(GetChunkData(chunk),
GetChunkDataLen(chunk));
diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp
index 931d57b..c4ecbaf 100644
--- a/tools/aapt2/format/binary/TableFlattener.cpp
+++ b/tools/aapt2/format/binary/TableFlattener.cpp
@@ -217,9 +217,10 @@
size_t entry_count_ = 0;
};
-struct PolicyChunk {
- uint32_t policy_flags;
- std::set<ResourceId> ids;
+struct OverlayableChunk {
+ std::string actor;
+ Source source;
+ std::map<OverlayableItem::PolicyFlags, std::set<ResourceId>> policy_ids;
};
class PackageFlattener {
@@ -421,8 +422,9 @@
return sorted_entries;
}
- void FlattenOverlayable(BigBuffer* buffer) {
- std::vector<PolicyChunk> policies;
+ bool FlattenOverlayable(BigBuffer* buffer) {
+ std::set<ResourceId> seen_ids;
+ std::map<std::string, OverlayableChunk> overlayable_chunks;
CHECK(bool(package_->id)) << "package must have an ID set when flattening <overlayable>";
for (auto& type : package_->types) {
@@ -433,79 +435,119 @@
continue;
}
- OverlayableItem& overlayable = entry->overlayable_item.value();
- uint32_t policy_flags = OverlayableItem::Policy::kNone;
- if (overlayable.policies & OverlayableItem::Policy::kPublic) {
- policy_flags |= ResTable_overlayable_policy_header::POLICY_PUBLIC;
- }
- if (overlayable.policies & OverlayableItem::Policy::kSystem) {
- policy_flags |= ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION;
- }
- if (overlayable.policies & OverlayableItem::Policy::kVendor) {
- policy_flags |= ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION;
- }
- if (overlayable.policies & OverlayableItem::Policy::kProduct) {
- policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION;
- }
- if (overlayable.policies & OverlayableItem::Policy::kProductServices) {
- policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_SERVICES_PARTITION;
+ OverlayableItem& item = entry->overlayable_item.value();
+
+ // Resource ids should only appear once in the resource table
+ ResourceId id = android::make_resid(package_->id.value(), type->id.value(),
+ entry->id.value());
+ CHECK(seen_ids.find(id) == seen_ids.end())
+ << "multiple overlayable definitions found for resource "
+ << ResourceName(package_->name, type->type, entry->name).to_string();
+ seen_ids.insert(id);
+
+ // Find the overlayable chunk with the specified name
+ OverlayableChunk* overlayable_chunk = nullptr;
+ auto iter = overlayable_chunks.find(item.overlayable->name);
+ if (iter == overlayable_chunks.end()) {
+ OverlayableChunk chunk{item.overlayable->actor, item.overlayable->source};
+ overlayable_chunk =
+ &overlayable_chunks.insert({item.overlayable->name, chunk}).first->second;
+ } else {
+ OverlayableChunk& chunk = iter->second;
+ if (!(chunk.source == item.overlayable->source)) {
+ // The name of an overlayable set of resources must be unique
+ context_->GetDiagnostics()->Error(DiagMessage(item.overlayable->source)
+ << "duplicate overlayable name"
+ << item.overlayable->name << "'");
+ context_->GetDiagnostics()->Error(DiagMessage(chunk.source)
+ << "previous declaration here");
+ return false;
+ }
+
+ CHECK(chunk.actor == item.overlayable->actor);
+ overlayable_chunk = &chunk;
}
- if (overlayable.policies == OverlayableItem::Policy::kNone) {
+ uint32_t policy_flags = 0;
+ if (item.policies == OverlayableItem::Policy::kNone) {
// Encode overlayable entries defined without a policy as publicly overlayable
policy_flags |= ResTable_overlayable_policy_header::POLICY_PUBLIC;
- }
-
- // Find the overlayable policy chunk with the same policies as the entry
- PolicyChunk* policy_chunk = nullptr;
- for (PolicyChunk& policy : policies) {
- if (policy.policy_flags == policy_flags) {
- policy_chunk = &policy;
- break;
+ } else {
+ if (item.policies & OverlayableItem::Policy::kPublic) {
+ policy_flags |= ResTable_overlayable_policy_header::POLICY_PUBLIC;
+ }
+ if (item.policies & OverlayableItem::Policy::kSystem) {
+ policy_flags |= ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION;
+ }
+ if (item.policies & OverlayableItem::Policy::kVendor) {
+ policy_flags |= ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION;
+ }
+ if (item.policies & OverlayableItem::Policy::kProduct) {
+ policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION;
+ }
+ if (item.policies & OverlayableItem::Policy::kProductServices) {
+ policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_SERVICES_PARTITION;
}
}
- // Create a new policy chunk if an existing one with the same policy cannot be found
- if (policy_chunk == nullptr) {
- PolicyChunk p;
- p.policy_flags = policy_flags;
- policies.push_back(p);
- policy_chunk = &policies.back();
+ auto policy = overlayable_chunk->policy_ids.find(policy_flags);
+ if (policy != overlayable_chunk->policy_ids.end()) {
+ policy->second.insert(id);
+ } else {
+ overlayable_chunk->policy_ids.insert(
+ std::make_pair(policy_flags, std::set<ResourceId>{id}));
}
-
- policy_chunk->ids.insert(android::make_resid(package_->id.value(), type->id.value(),
- entry->id.value()));
}
}
- if (policies.empty()) {
- // Only write the overlayable chunk if the APK has overlayable entries
- return;
- }
+ for (auto& overlayable_pair : overlayable_chunks) {
+ std::string name = overlayable_pair.first;
+ OverlayableChunk& overlayable = overlayable_pair.second;
- ChunkWriter writer(buffer);
- writer.StartChunk<ResTable_overlayable_header>(RES_TABLE_OVERLAYABLE_TYPE);
-
- // Write each policy block for the overlayable
- for (PolicyChunk& policy : policies) {
- ChunkWriter policy_writer(buffer);
- ResTable_overlayable_policy_header* policy_type =
- policy_writer.StartChunk<ResTable_overlayable_policy_header>(
- RES_TABLE_OVERLAYABLE_POLICY_TYPE);
- policy_type->policy_flags = util::HostToDevice32(policy.policy_flags);
- policy_type->entry_count = util::HostToDevice32(static_cast<uint32_t>(policy.ids.size()));
-
- // Write the ids after the policy header
- ResTable_ref* id_block = policy_writer.NextBlock<ResTable_ref>(policy.ids.size());
- for (const ResourceId& id : policy.ids) {
- id_block->ident = util::HostToDevice32(id.id);
- id_block++;
+ // Write the header of the overlayable chunk
+ ChunkWriter overlayable_writer(buffer);
+ auto* overlayable_type =
+ overlayable_writer.StartChunk<ResTable_overlayable_header>(RES_TABLE_OVERLAYABLE_TYPE);
+ if (name.size() >= arraysize(overlayable_type->name)) {
+ diag_->Error(DiagMessage() << "overlayable name '" << name
+ << "' exceeds maximum length ("
+ << arraysize(overlayable_type->name)
+ << " utf16 characters)");
+ return false;
}
+ strcpy16_htod(overlayable_type->name, arraysize(overlayable_type->name),
+ util::Utf8ToUtf16(name));
- policy_writer.Finish();
+ if (overlayable.actor.size() >= arraysize(overlayable_type->actor)) {
+ diag_->Error(DiagMessage() << "overlayable name '" << overlayable.actor
+ << "' exceeds maximum length ("
+ << arraysize(overlayable_type->actor)
+ << " utf16 characters)");
+ return false;
+ }
+ strcpy16_htod(overlayable_type->actor, arraysize(overlayable_type->actor),
+ util::Utf8ToUtf16(overlayable.actor));
+
+ // Write each policy block for the overlayable
+ for (auto& policy_ids : overlayable.policy_ids) {
+ ChunkWriter policy_writer(buffer);
+ auto* policy_type = policy_writer.StartChunk<ResTable_overlayable_policy_header>(
+ RES_TABLE_OVERLAYABLE_POLICY_TYPE);
+ policy_type->policy_flags = util::HostToDevice32(static_cast<uint32_t>(policy_ids.first));
+ policy_type->entry_count = util::HostToDevice32(static_cast<uint32_t>(
+ policy_ids.second.size()));
+ // Write the ids after the policy header
+ auto* id_block = policy_writer.NextBlock<ResTable_ref>(policy_ids.second.size());
+ for (const ResourceId& id : policy_ids.second) {
+ id_block->ident = util::HostToDevice32(id.id);
+ id_block++;
+ }
+ policy_writer.Finish();
+ }
+ overlayable_writer.Finish();
}
- writer.Finish();
+ return true;
}
bool FlattenTypeSpec(ResourceTableType* type, std::vector<ResourceEntry*>* sorted_entries,
diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp
index a5fb6fd..18fecf6 100644
--- a/tools/aapt2/format/binary/TableFlattener_test.cpp
+++ b/tools/aapt2/format/binary/TableFlattener_test.cpp
@@ -657,36 +657,36 @@
TEST_F(TableFlattenerTest, FlattenMultipleOverlayablePolicies) {
auto overlayable = std::make_shared<Overlayable>("TestName", "overlay://theme");
std::string name_zero = "com.app.test:integer/overlayable_zero_item";
- OverlayableItem overlayable_zero_item(overlayable);
- overlayable_zero_item.policies |= OverlayableItem::Policy::kProduct;
- overlayable_zero_item.policies |= OverlayableItem::Policy::kSystem;
- overlayable_zero_item.policies |= OverlayableItem::Policy::kProductServices;
+ OverlayableItem overlayable_item_zero(overlayable);
+ overlayable_item_zero.policies |= OverlayableItem::Policy::kProduct;
+ overlayable_item_zero.policies |= OverlayableItem::Policy::kSystem;
+ overlayable_item_zero.policies |= OverlayableItem::Policy::kProductServices;
std::string name_one = "com.app.test:integer/overlayable_one_item";
- OverlayableItem overlayable_one_item(overlayable);
- overlayable_one_item.policies |= OverlayableItem::Policy::kPublic;
- overlayable_one_item.policies |= OverlayableItem::Policy::kProductServices;
+ OverlayableItem overlayable_item_one(overlayable);
+ overlayable_item_one.policies |= OverlayableItem::Policy::kPublic;
+ overlayable_item_one.policies |= OverlayableItem::Policy::kProductServices;
std::string name_two = "com.app.test:integer/overlayable_two_item";
- OverlayableItem overlayable_two_item(overlayable);
- overlayable_two_item.policies |= OverlayableItem::Policy::kProduct;
- overlayable_two_item.policies |= OverlayableItem::Policy::kSystem;
- overlayable_two_item.policies |= OverlayableItem::Policy::kVendor;
+ OverlayableItem overlayable_item_two(overlayable);
+ overlayable_item_two.policies |= OverlayableItem::Policy::kProduct;
+ overlayable_item_two.policies |= OverlayableItem::Policy::kSystem;
+ overlayable_item_two.policies |= OverlayableItem::Policy::kVendor;
std::string name_three = "com.app.test:integer/overlayable_three_item";
- OverlayableItem overlayable_three_item(overlayable);
+ OverlayableItem overlayable_item_three(overlayable);
std::unique_ptr<ResourceTable> table =
test::ResourceTableBuilder()
.SetPackageId("com.app.test", 0x7f)
.AddSimple(name_zero, ResourceId(0x7f020000))
- .SetOverlayable(name_zero, overlayable_zero_item)
+ .SetOverlayable(name_zero, overlayable_item_zero)
.AddSimple(name_one, ResourceId(0x7f020001))
- .SetOverlayable(name_one, overlayable_one_item)
+ .SetOverlayable(name_one, overlayable_item_one)
.AddSimple(name_two, ResourceId(0x7f020002))
- .SetOverlayable(name_two, overlayable_two_item)
+ .SetOverlayable(name_two, overlayable_item_two)
.AddSimple(name_three, ResourceId(0x7f020003))
- .SetOverlayable(name_three, overlayable_three_item)
+ .SetOverlayable(name_three, overlayable_item_three)
.Build();
ResourceTable output_table;
@@ -724,6 +724,84 @@
ASSERT_TRUE(search_result.value().entry->overlayable_item);
overlayable_item = search_result.value().entry->overlayable_item.value();
EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kPublic);
+ EXPECT_EQ(overlayable_item.overlayable->name, "TestName");
+ EXPECT_EQ(overlayable_item.overlayable->actor, "overlay://theme");
+ EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kPublic);
+}
+
+TEST_F(TableFlattenerTest, FlattenMultipleOverlayable) {
+ auto group = std::make_shared<Overlayable>("TestName", "overlay://theme");
+ std::string name_zero = "com.app.test:integer/overlayable_zero";
+ OverlayableItem overlayable_item_zero(group);
+ overlayable_item_zero.policies |= OverlayableItem::Policy::kProduct;
+ overlayable_item_zero.policies |= OverlayableItem::Policy::kSystem;
+ overlayable_item_zero.policies |= OverlayableItem::Policy::kProductServices;
+
+ auto group_one = std::make_shared<Overlayable>("OtherName", "overlay://customization");
+ std::string name_one = "com.app.test:integer/overlayable_one";
+ OverlayableItem overlayable_item_one(group_one);
+ overlayable_item_one.policies |= OverlayableItem::Policy::kPublic;
+ overlayable_item_one.policies |= OverlayableItem::Policy::kProductServices;
+
+ std::string name_two = "com.app.test:integer/overlayable_two";
+ OverlayableItem overlayable_item_two(group);
+ overlayable_item_two.policies |= OverlayableItem::Policy::kProduct;
+ overlayable_item_two.policies |= OverlayableItem::Policy::kSystem;
+ overlayable_item_two.policies |= OverlayableItem::Policy::kVendor;
+
+ std::string name_three = "com.app.test:integer/overlayable_three";
+ OverlayableItem overlayable_item_three(group_one);
+ std::unique_ptr<ResourceTable> table =
+ test::ResourceTableBuilder()
+ .SetPackageId("com.app.test", 0x7f)
+ .AddSimple(name_zero, ResourceId(0x7f020000))
+ .SetOverlayable(name_zero, overlayable_item_zero)
+ .AddSimple(name_one, ResourceId(0x7f020001))
+ .SetOverlayable(name_one, overlayable_item_one)
+ .AddSimple(name_two, ResourceId(0x7f020002))
+ .SetOverlayable(name_two, overlayable_item_two)
+ .AddSimple(name_three, ResourceId(0x7f020003))
+ .SetOverlayable(name_three, overlayable_item_three)
+ .Build();
+ ResourceTable output_table;
+ ASSERT_TRUE(Flatten(context_.get(), {}, table.get(), &output_table));
+ auto search_result = output_table.FindResource(test::ParseNameOrDie(name_zero));
+ ASSERT_TRUE(search_result);
+ ASSERT_THAT(search_result.value().entry, NotNull());
+ ASSERT_TRUE(search_result.value().entry->overlayable_item);
+ OverlayableItem& result_overlayable = search_result.value().entry->overlayable_item.value();
+ EXPECT_EQ(result_overlayable.overlayable->name, "TestName");
+ EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://theme");
+ EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kSystem
+ | OverlayableItem::Policy::kProduct
+ | OverlayableItem::Policy::kProductServices);
+ search_result = output_table.FindResource(test::ParseNameOrDie(name_one));
+ ASSERT_TRUE(search_result);
+ ASSERT_THAT(search_result.value().entry, NotNull());
+ ASSERT_TRUE(search_result.value().entry->overlayable_item);
+ result_overlayable = search_result.value().entry->overlayable_item.value();
+ EXPECT_EQ(result_overlayable.overlayable->name, "OtherName");
+ EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://customization");
+ EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kPublic
+ | OverlayableItem::Policy::kProductServices);
+ search_result = output_table.FindResource(test::ParseNameOrDie(name_two));
+ ASSERT_TRUE(search_result);
+ ASSERT_THAT(search_result.value().entry, NotNull());
+ ASSERT_TRUE(search_result.value().entry->overlayable_item);
+ result_overlayable = search_result.value().entry->overlayable_item.value();
+ EXPECT_EQ(result_overlayable.overlayable->name, "TestName");
+ EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://theme");
+ EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kSystem
+ | OverlayableItem::Policy::kProduct
+ | OverlayableItem::Policy::kVendor);
+ search_result = output_table.FindResource(test::ParseNameOrDie(name_three));
+ ASSERT_TRUE(search_result);
+ ASSERT_THAT(search_result.value().entry, NotNull());
+ ASSERT_TRUE(search_result.value().entry->overlayable_item);
+ result_overlayable = search_result.value().entry->overlayable_item.value();
+ EXPECT_EQ(result_overlayable.overlayable->name, "OtherName");
+ EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://customization");
+ EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kPublic);
}
} // namespace aapt
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index 85bf6f2..5812ec4 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -213,6 +213,27 @@
return true;
}
+static bool AddDeprecatedUsesFeatures(xml::Element* el, SourcePathDiagnostics* diag) {
+ if (xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "name")) {
+ if (attr->value.empty()) {
+ return true;
+ }
+
+ // Add "android.hardware.fingerprint" when "android.hardware.biometric.fingerprint" is found,
+ // since the former is deprecated in Q and the latter is not present pre-Q. (see b/115639644)
+ if (attr->value == "android.hardware.biometrics.fingerprint") {
+ auto element = el->CloneElement([&](const xml::Element& el, xml::Element* out_el) {
+ xml::Attribute* cloned_attr = out_el->FindOrCreateAttribute(xml::kSchemaAndroid, "name");
+ cloned_attr->value = "android.hardware.fingerprint";
+ });
+
+ el->parent->AppendChild(std::move(element));
+ }
+ }
+
+ return true;
+}
+
bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor,
IDiagnostics* diag) {
// First verify some options.
@@ -247,6 +268,7 @@
// Common <uses-feature> actions.
xml::XmlNodeAction uses_feature_action;
uses_feature_action.Action(VerifyUsesFeature);
+ uses_feature_action.Action(AddDeprecatedUsesFeatures);
// Common component actions.
xml::XmlNodeAction component_action;
diff --git a/tools/aapt2/link/ManifestFixer_test.cpp b/tools/aapt2/link/ManifestFixer_test.cpp
index adea627..fcc9f55 100644
--- a/tools/aapt2/link/ManifestFixer_test.cpp
+++ b/tools/aapt2/link/ManifestFixer_test.cpp
@@ -832,4 +832,36 @@
EXPECT_THAT(Verify(input), NotNull());
}
+TEST_F(ManifestFixerTest, UsesFeatureAddDeprecated) {
+ std::string input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android">
+ <uses-feature android:name="android.hardware.biometrics.fingerprint" />
+ <feature-group>
+ <uses-feature android:name="android.hardware.biometrics.fingerprint" />
+ </feature-group>
+ </manifest>)";
+
+ std::unique_ptr<xml::XmlResource> manifest = Verify(input);
+ ASSERT_THAT(manifest, NotNull());
+ EXPECT_THAT(manifest->root->FindChildWithAttribute("", "uses-feature",
+ xml::kSchemaAndroid, "name",
+ "android.hardware.biometrics.fingerprint"),
+ Ne(nullptr));
+ EXPECT_THAT(manifest->root->FindChildWithAttribute("", "uses-feature",
+ xml::kSchemaAndroid, "name",
+ "android.hardware.fingerprint"),
+ Ne(nullptr));
+
+ xml::Element* feature_group = manifest->root->FindChild("", "feature-group");
+ ASSERT_THAT(feature_group, Ne(nullptr));
+
+ EXPECT_THAT(feature_group->FindChildWithAttribute("", "uses-feature", xml::kSchemaAndroid, "name",
+ "android.hardware.biometrics.fingerprint"),
+ Ne(nullptr));
+ EXPECT_THAT(feature_group->FindChildWithAttribute("", "uses-feature", xml::kSchemaAndroid, "name",
+ "android.hardware.fingerprint"),
+ Ne(nullptr));
+}
+
} // namespace aapt
diff --git a/wifi/java/android/net/wifi/DppStatusCallback.java b/wifi/java/android/net/wifi/DppStatusCallback.java
deleted file mode 100644
index fa2ab30..0000000
--- a/wifi/java/android/net/wifi/DppStatusCallback.java
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * 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.net.wifi;
-
-import android.annotation.IntDef;
-import android.annotation.SystemApi;
-import android.os.Handler;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * DPP Status Callback. Use this callback to get status updates (success, failure, progress)
- * from the DPP operation started with {@link WifiManager#startDppAsConfiguratorInitiator(String,
- * int, int, Handler, DppStatusCallback)} or {@link WifiManager#startDppAsEnrolleeInitiator(String,
- * Handler, DppStatusCallback)}
- * @hide
- */
-@SystemApi
-public abstract class DppStatusCallback {
- /**
- * DPP Success event: Configuration sent (Configurator mode).
- */
- public static final int DPP_EVENT_SUCCESS_CONFIGURATION_SENT = 0;
-
- /** @hide */
- @IntDef(prefix = { "DPP_EVENT_SUCCESS_" }, value = {
- DPP_EVENT_SUCCESS_CONFIGURATION_SENT,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface DppSuccessStatusCode {}
-
- /**
- * DPP Progress event: Initial authentication with peer succeeded.
- */
- public static final int DPP_EVENT_PROGRESS_AUTHENTICATION_SUCCESS = 0;
-
- /**
- * DPP Progress event: Peer requires more time to process bootstrapping.
- */
- public static final int DPP_EVENT_PROGRESS_RESPONSE_PENDING = 1;
-
- /** @hide */
- @IntDef(prefix = { "DPP_EVENT_PROGRESS_" }, value = {
- DPP_EVENT_PROGRESS_AUTHENTICATION_SUCCESS,
- DPP_EVENT_PROGRESS_RESPONSE_PENDING,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface DppProgressStatusCode {}
-
- /**
- * DPP Failure event: Scanned QR code is either not a DPP URI, or the DPP URI has errors.
- */
- public static final int DPP_EVENT_FAILURE_INVALID_URI = -1;
-
- /**
- * DPP Failure event: Bootstrapping/Authentication initialization process failure.
- */
- public static final int DPP_EVENT_FAILURE_AUTHENTICATION = -2;
-
- /**
- * DPP Failure event: Both devices are implementing the same role and are incompatible.
- */
- public static final int DPP_EVENT_FAILURE_NOT_COMPATIBLE = -3;
-
- /**
- * DPP Failure event: Configuration process has failed due to malformed message.
- */
- public static final int DPP_EVENT_FAILURE_CONFIGURATION = -4;
-
- /**
- * DPP Failure event: DPP request while in another DPP exchange.
- */
- public static final int DPP_EVENT_FAILURE_BUSY = -5;
-
- /**
- * DPP Failure event: No response from the peer.
- */
- public static final int DPP_EVENT_FAILURE_TIMEOUT = -6;
-
- /**
- * DPP Failure event: General protocol failure.
- */
- public static final int DPP_EVENT_FAILURE = -7;
-
- /**
- * DPP Failure event: Feature or option is not supported.
- */
- public static final int DPP_EVENT_FAILURE_NOT_SUPPORTED = -8;
-
- /**
- * DPP Failure event: Invalid network provided to DPP configurator.
- * Network must either be WPA3-Personal (SAE) or WPA2-Personal (PSK).
- */
- public static final int DPP_EVENT_FAILURE_INVALID_NETWORK = -9;
-
-
- /** @hide */
- @IntDef(prefix = {"DPP_EVENT_FAILURE_"}, value = {
- DPP_EVENT_FAILURE_INVALID_URI,
- DPP_EVENT_FAILURE_AUTHENTICATION,
- DPP_EVENT_FAILURE_NOT_COMPATIBLE,
- DPP_EVENT_FAILURE_CONFIGURATION,
- DPP_EVENT_FAILURE_BUSY,
- DPP_EVENT_FAILURE_TIMEOUT,
- DPP_EVENT_FAILURE,
- DPP_EVENT_FAILURE_NOT_SUPPORTED,
- DPP_EVENT_FAILURE_INVALID_NETWORK,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface DppFailureStatusCode {
- }
-
- /**
- * Called when local DPP Enrollee successfully receives a new Wi-Fi configuration from the
- * peer DPP configurator. This callback marks the successful end of the DPP current DPP
- * session, and no further callbacks will be called. This callback is the successful outcome
- * of a DPP flow starting with {@link WifiManager#startDppAsEnrolleeInitiator(String, Handler,
- * DppStatusCallback)}.
- *
- * @param newNetworkId New Wi-Fi configuration with a network ID received from the configurator
- */
- public abstract void onEnrolleeSuccess(int newNetworkId);
-
- /**
- * Called when a DPP success event takes place, except for when configuration is received from
- * an external Configurator. The callback onSuccessConfigReceived will be used in this case.
- * This callback marks the successful end of the current DPP session, and no further
- * callbacks will be called. This callback is the successful outcome of a DPP flow starting with
- * {@link WifiManager#startDppAsConfiguratorInitiator(String, int, int, Handler,
- * DppStatusCallback)}.
- *
- * @param code DPP success status code.
- */
- public abstract void onConfiguratorSuccess(@DppSuccessStatusCode int code);
-
- /**
- * Called when a DPP Failure event takes place. This callback marks the unsuccessful end of the
- * current DPP session, and no further callbacks will be called.
- *
- * @param code DPP failure status code.
- */
- public abstract void onFailure(@DppFailureStatusCode int code);
-
- /**
- * Called when DPP events that indicate progress take place. Can be used by UI elements
- * to show progress.
- *
- * @param code DPP progress status code.
- */
- public abstract void onProgress(@DppProgressStatusCode int code);
-}
diff --git a/wifi/java/android/net/wifi/EasyConnectStatusCallback.java b/wifi/java/android/net/wifi/EasyConnectStatusCallback.java
new file mode 100644
index 0000000..3b4a6cd
--- /dev/null
+++ b/wifi/java/android/net/wifi/EasyConnectStatusCallback.java
@@ -0,0 +1,179 @@
+/*
+ * 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.net.wifi;
+
+import android.annotation.IntDef;
+import android.annotation.SystemApi;
+import android.os.Handler;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Easy Connect (DPP) Status Callback. Use this callback to get status updates (success, failure,
+ * progress) from the Easy Connect operation started with
+ * {@link WifiManager#startEasyConnectAsConfiguratorInitiator(String,
+ * int, int, Handler, EasyConnectStatusCallback)} or
+ * {@link WifiManager#startEasyConnectAsEnrolleeInitiator(String,
+ * Handler, EasyConnectStatusCallback)}
+ *
+ * @hide
+ */
+@SystemApi
+public abstract class EasyConnectStatusCallback {
+ /**
+ * Easy Connect Success event: Configuration sent (Configurator mode).
+ */
+ public static final int EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_SENT = 0;
+
+ /** @hide */
+ @IntDef(prefix = {"EASY_CONNECT_EVENT_SUCCESS_"}, value = {
+ EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_SENT,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface EasyConnectSuccessStatusCode {
+ }
+
+ /**
+ * Easy Connect Progress event: Initial authentication with peer succeeded.
+ */
+ public static final int EASY_CONNECT_EVENT_PROGRESS_AUTHENTICATION_SUCCESS = 0;
+
+ /**
+ * Easy Connect Progress event: Peer requires more time to process bootstrapping.
+ */
+ public static final int EASY_CONNECT_EVENT_PROGRESS_RESPONSE_PENDING = 1;
+
+ /** @hide */
+ @IntDef(prefix = {"EASY_CONNECT_EVENT_PROGRESS_"}, value = {
+ EASY_CONNECT_EVENT_PROGRESS_AUTHENTICATION_SUCCESS,
+ EASY_CONNECT_EVENT_PROGRESS_RESPONSE_PENDING,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface EasyConnectProgressStatusCode {
+ }
+
+ /**
+ * Easy Connect Failure event: Scanned QR code is either not a Easy Connect URI, or the Easy
+ * Connect URI has errors.
+ */
+ public static final int EASY_CONNECT_EVENT_FAILURE_INVALID_URI = -1;
+
+ /**
+ * Easy Connect Failure event: Bootstrapping/Authentication initialization process failure.
+ */
+ public static final int EASY_CONNECT_EVENT_FAILURE_AUTHENTICATION = -2;
+
+ /**
+ * Easy Connect Failure event: Both devices are implementing the same role and are incompatible.
+ */
+ public static final int EASY_CONNECT_EVENT_FAILURE_NOT_COMPATIBLE = -3;
+
+ /**
+ * Easy Connect Failure event: Configuration process has failed due to malformed message.
+ */
+ public static final int EASY_CONNECT_EVENT_FAILURE_CONFIGURATION = -4;
+
+ /**
+ * Easy Connect Failure event: Easy Connect request while in another Easy Connect exchange.
+ */
+ public static final int EASY_CONNECT_EVENT_FAILURE_BUSY = -5;
+
+ /**
+ * Easy Connect Failure event: No response from the peer.
+ */
+ public static final int EASY_CONNECT_EVENT_FAILURE_TIMEOUT = -6;
+
+ /**
+ * Easy Connect Failure event: General protocol failure.
+ */
+ public static final int EASY_CONNECT_EVENT_FAILURE = -7;
+
+ /**
+ * Easy Connect Failure event: Feature or option is not supported.
+ */
+ public static final int EASY_CONNECT_EVENT_FAILURE_NOT_SUPPORTED = -8;
+
+ /**
+ * Easy Connect Failure event: Invalid network provided to Easy Connect configurator.
+ * Network must either be WPA3-Personal (SAE) or WPA2-Personal (PSK).
+ */
+ public static final int EASY_CONNECT_EVENT_FAILURE_INVALID_NETWORK = -9;
+
+
+ /** @hide */
+ @IntDef(prefix = {"EASY_CONNECT_EVENT_FAILURE_"}, value = {
+ EASY_CONNECT_EVENT_FAILURE_INVALID_URI,
+ EASY_CONNECT_EVENT_FAILURE_AUTHENTICATION,
+ EASY_CONNECT_EVENT_FAILURE_NOT_COMPATIBLE,
+ EASY_CONNECT_EVENT_FAILURE_CONFIGURATION,
+ EASY_CONNECT_EVENT_FAILURE_BUSY,
+ EASY_CONNECT_EVENT_FAILURE_TIMEOUT,
+ EASY_CONNECT_EVENT_FAILURE,
+ EASY_CONNECT_EVENT_FAILURE_NOT_SUPPORTED,
+ EASY_CONNECT_EVENT_FAILURE_INVALID_NETWORK,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface EasyConnectFailureStatusCode {
+ }
+
+ /**
+ * Called when local Easy Connect Enrollee successfully receives a new Wi-Fi configuration from
+ * the
+ * peer Easy Connect configurator. This callback marks the successful end of the Easy Connect
+ * current Easy Connect
+ * session, and no further callbacks will be called. This callback is the successful outcome
+ * of a Easy Connect flow starting with
+ * {@link WifiManager#startEasyConnectAsEnrolleeInitiator(String,
+ * Handler,
+ * EasyConnectStatusCallback)}.
+ *
+ * @param newNetworkId New Wi-Fi configuration with a network ID received from the configurator
+ */
+ public abstract void onEnrolleeSuccess(int newNetworkId);
+
+ /**
+ * Called when a Easy Connect success event takes place, except for when configuration is
+ * received from
+ * an external Configurator. The callback onSuccessConfigReceived will be used in this case.
+ * This callback marks the successful end of the current Easy Connect session, and no further
+ * callbacks will be called. This callback is the successful outcome of a Easy Connect flow
+ * starting with
+ * {@link WifiManager#startEasyConnectAsConfiguratorInitiator(String, int, int, Handler,
+ * EasyConnectStatusCallback)}.
+ *
+ * @param code Easy Connect success status code.
+ */
+ public abstract void onConfiguratorSuccess(@EasyConnectSuccessStatusCode int code);
+
+ /**
+ * Called when a Easy Connect Failure event takes place. This callback marks the unsuccessful
+ * end of the
+ * current Easy Connect session, and no further callbacks will be called.
+ *
+ * @param code Easy Connect failure status code.
+ */
+ public abstract void onFailure(@EasyConnectFailureStatusCode int code);
+
+ /**
+ * Called when Easy Connect events that indicate progress take place. Can be used by UI elements
+ * to show progress.
+ *
+ * @param code Easy Connect progress status code.
+ */
+ public abstract void onProgress(@EasyConnectProgressStatusCode int code);
+}
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 28dd9b4..e019f28 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -145,11 +145,23 @@
*/
public static final int SUITE_B_192 = 10;
+ /**
+ * WPA pre-shared key with stronger SHA256-based algorithms.
+ * @hide
+ */
+ public static final int WPA_PSK_SHA256 = 11;
+
+ /**
+ * WPA using EAP authentication with stronger SHA256-based algorithms.
+ * @hide
+ */
+ public static final int WPA_EAP_SHA256 = 12;
+
public static final String varName = "key_mgmt";
public static final String[] strings = { "NONE", "WPA_PSK", "WPA_EAP",
"IEEE8021X", "WPA2_PSK", "OSEN", "FT_PSK", "FT_EAP",
- "SAE", "OWE", "SUITE_B_192"};
+ "SAE", "OWE", "SUITE_B_192", "WPA_PSK_SHA256", "WPA_EAP_SHA256" };
}
/**
@@ -1886,6 +1898,7 @@
if (creatorName != null) sbuf.append(" cname=" + creatorName);
if (lastUpdateUid != 0) sbuf.append(" luid=" + lastUpdateUid);
if (lastUpdateName != null) sbuf.append(" lname=" + lastUpdateName);
+ if (updateIdentifier != null) sbuf.append(" updateIdentifier=" + updateIdentifier);
sbuf.append(" lcuid=" + lastConnectUid);
sbuf.append(" userApproved=" + userApprovedAsString(userApproved));
sbuf.append(" noInternetAccessExpected=" + noInternetAccessExpected);
@@ -2281,6 +2294,7 @@
mRandomizedMacAddress = source.mRandomizedMacAddress;
macRandomizationSetting = source.macRandomizationSetting;
requirePMF = source.requirePMF;
+ updateIdentifier = source.updateIdentifier;
}
}
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index af5ad51..840af5d 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -93,12 +93,22 @@
private int mRssi;
/**
- * Link speed in Mbps
+ * The unit in which links speeds are expressed.
*/
public static final String LINK_SPEED_UNITS = "Mbps";
private int mLinkSpeed;
/**
+ * Tx(transmit) Link speed in Mbps
+ */
+ private int mTxLinkSpeed;
+
+ /**
+ * Rx(receive) Link speed in Mbps
+ */
+ private int mRxLinkSpeed;
+
+ /**
* Frequency in MHz
*/
public static final String FREQUENCY_UNITS = "MHz";
@@ -192,6 +202,8 @@
setNetworkId(-1);
setRssi(INVALID_RSSI);
setLinkSpeed(-1);
+ setTxLinkSpeedMbps(-1);
+ setRxLinkSpeedMbps(-1);
setFrequency(-1);
setMeteredHint(false);
setEphemeral(false);
@@ -219,6 +231,8 @@
mNetworkId = source.mNetworkId;
mRssi = source.mRssi;
mLinkSpeed = source.mLinkSpeed;
+ mTxLinkSpeed = source.mTxLinkSpeed;
+ mRxLinkSpeed = source.mRxLinkSpeed;
mFrequency = source.mFrequency;
mIpAddress = source.mIpAddress;
mMacAddress = source.mMacAddress;
@@ -313,7 +327,7 @@
/**
* Returns the current link speed in {@link #LINK_SPEED_UNITS}.
- * @return the link speed.
+ * @return the link speed or -1 if there is no valid value.
* @see #LINK_SPEED_UNITS
*/
public int getLinkSpeed() {
@@ -323,7 +337,39 @@
/** @hide */
@UnsupportedAppUsage
public void setLinkSpeed(int linkSpeed) {
- this.mLinkSpeed = linkSpeed;
+ mLinkSpeed = linkSpeed;
+ }
+
+ /**
+ * Returns the current transmit link speed in Mbps.
+ * @return the Tx link speed or -1 if there is no valid value.
+ */
+ public int getTxLinkSpeedMbps() {
+ return mTxLinkSpeed;
+ }
+
+ /**
+ * Update the last transmitted packet bit rate in Mbps.
+ * @hide
+ */
+ public void setTxLinkSpeedMbps(int txLinkSpeed) {
+ mTxLinkSpeed = txLinkSpeed;
+ }
+
+ /**
+ * Returns the current receive link speed in Mbps.
+ * @return the Rx link speed or -1 if there is no valid value.
+ */
+ public int getRxLinkSpeedMbps() {
+ return mRxLinkSpeed;
+ }
+
+ /**
+ * Update the last received packet bit rate in Mbps.
+ * @hide
+ */
+ public void setRxLinkSpeedMbps(int rxLinkSpeed) {
+ mRxLinkSpeed = rxLinkSpeed;
}
/**
@@ -529,17 +575,19 @@
StringBuffer sb = new StringBuffer();
String none = "<none>";
- sb.append("SSID: ").append(mWifiSsid == null ? WifiSsid.NONE : mWifiSsid).
- append(", BSSID: ").append(mBSSID == null ? none : mBSSID).
- append(", MAC: ").append(mMacAddress == null ? none : mMacAddress).
- append(", Supplicant state: ").
- append(mSupplicantState == null ? none : mSupplicantState).
- append(", RSSI: ").append(mRssi).
- append(", Link speed: ").append(mLinkSpeed).append(LINK_SPEED_UNITS).
- append(", Frequency: ").append(mFrequency).append(FREQUENCY_UNITS).
- append(", Net ID: ").append(mNetworkId).
- append(", Metered hint: ").append(mMeteredHint).
- append(", score: ").append(Integer.toString(score));
+ sb.append("SSID: ").append(mWifiSsid == null ? WifiSsid.NONE : mWifiSsid)
+ .append(", BSSID: ").append(mBSSID == null ? none : mBSSID)
+ .append(", MAC: ").append(mMacAddress == null ? none : mMacAddress)
+ .append(", Supplicant state: ")
+ .append(mSupplicantState == null ? none : mSupplicantState)
+ .append(", RSSI: ").append(mRssi)
+ .append(", Link speed: ").append(mLinkSpeed).append(LINK_SPEED_UNITS)
+ .append(", Tx Link speed: ").append(mTxLinkSpeed).append(LINK_SPEED_UNITS)
+ .append(", Rx Link speed: ").append(mRxLinkSpeed).append(LINK_SPEED_UNITS)
+ .append(", Frequency: ").append(mFrequency).append(FREQUENCY_UNITS)
+ .append(", Net ID: ").append(mNetworkId)
+ .append(", Metered hint: ").append(mMeteredHint)
+ .append(", score: ").append(Integer.toString(score));
return sb.toString();
}
@@ -553,6 +601,8 @@
dest.writeInt(mNetworkId);
dest.writeInt(mRssi);
dest.writeInt(mLinkSpeed);
+ dest.writeInt(mTxLinkSpeed);
+ dest.writeInt(mRxLinkSpeed);
dest.writeInt(mFrequency);
if (mIpAddress != null) {
dest.writeByte((byte)1);
@@ -593,6 +643,8 @@
info.setNetworkId(in.readInt());
info.setRssi(in.readInt());
info.setLinkSpeed(in.readInt());
+ info.setTxLinkSpeedMbps(in.readInt());
+ info.setRxLinkSpeedMbps(in.readInt());
info.setFrequency(in.readInt());
if (in.readByte() == 1) {
try {
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 517bf3b..559f4ad 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -4586,93 +4586,100 @@
}
}
- /* DPP - Device Provisioning Protocol AKA "Easy Connect" */
+ /* Easy Connect - AKA Device Provisioning Protocol (DPP) */
/**
- * DPP Network role: Station.
+ * Easy Connect Network role: Station.
+ *
* @hide
*/
@SystemApi
- public static final int DPP_NETWORK_ROLE_STA = 0;
+ public static final int EASY_CONNECT_NETWORK_ROLE_STA = 0;
/**
- * DPP Network role: Access Point.
+ * Easy Connect Network role: Access Point.
+ *
* @hide
*/
@SystemApi
- public static final int DPP_NETWORK_ROLE_AP = 1;
+ public static final int EASY_CONNECT_NETWORK_ROLE_AP = 1;
/** @hide */
- @IntDef(prefix = {"DPP_NETWORK_ROLE_"}, value = {
- DPP_NETWORK_ROLE_STA,
- DPP_NETWORK_ROLE_AP,
+ @IntDef(prefix = {"EASY_CONNECT_NETWORK_ROLE_"}, value = {
+ EASY_CONNECT_NETWORK_ROLE_STA,
+ EASY_CONNECT_NETWORK_ROLE_AP,
})
@Retention(RetentionPolicy.SOURCE)
- public @interface DppNetworkRole {}
+ public @interface EasyConnectNetworkRole {
+ }
/**
- * Start DPP in Configurator-Initiator role. The current device will initiate DPP bootstrapping
- * with a peer, and configure the peer with the SSID and password of the specified network using
- * the DPP protocol on an encrypted link.
+ * Start Easy Connect (DPP) in Configurator-Initiator role. The current device will initiate
+ * Easy Connect bootstrapping with a peer, and configure the peer with the SSID and password of
+ * the specified network using the Easy Connect protocol on an encrypted link.
*
- * @param enrolleeUri URI of the Enrollee obtained separately (e.g. QR code scanning)
- * @param selectedNetworkId Selected network ID to be sent to the peer
+ * @param enrolleeUri URI of the Enrollee obtained separately (e.g. QR code scanning)
+ * @param selectedNetworkId Selected network ID to be sent to the peer
* @param enrolleeNetworkRole The network role of the enrollee
- * @param callback Callback for status updates
- * @param handler The handler on whose thread to execute the callbacks. Null for main thread.
+ * @param callback Callback for status updates
+ * @param handler The handler on whose thread to execute the callbacks. Null for
+ * main thread.
* @hide
*/
@SystemApi
@RequiresPermission(anyOf = {
android.Manifest.permission.NETWORK_SETTINGS,
android.Manifest.permission.NETWORK_SETUP_WIZARD})
- public void startDppAsConfiguratorInitiator(@NonNull String enrolleeUri,
- int selectedNetworkId, @DppNetworkRole int enrolleeNetworkRole,
- @Nullable Handler handler, @NonNull DppStatusCallback callback) {
+ public void startEasyConnectAsConfiguratorInitiator(@NonNull String enrolleeUri,
+ int selectedNetworkId, @EasyConnectNetworkRole int enrolleeNetworkRole,
+ @Nullable Handler handler, @NonNull EasyConnectStatusCallback callback) {
Looper looper = (handler == null) ? Looper.getMainLooper() : handler.getLooper();
Binder binder = new Binder();
try {
mService.startDppAsConfiguratorInitiator(binder, enrolleeUri, selectedNetworkId,
- enrolleeNetworkRole, new DppCallbackProxy(looper, callback));
+ enrolleeNetworkRole, new EasyConnectCallbackProxy(looper, callback));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
- * Start DPP in Enrollee-Initiator role. The current device will initiate DPP bootstrapping
- * with a peer, and receive the SSID and password from the peer configurator.
+ * Start Easy Connect (DPP) in Enrollee-Initiator role. The current device will initiate Easy
+ * Connect bootstrapping with a peer, and receive the SSID and password from the peer
+ * configurator.
*
* @param configuratorUri URI of the Configurator obtained separately (e.g. QR code scanning)
- * @param callback Callback for status updates
- * @param handler The handler on whose thread to execute the callbacks. Null for main thread.
+ * @param callback Callback for status updates
+ * @param handler The handler on whose thread to execute the callbacks. Null for main
+ * thread.
* @hide
*/
@SystemApi
@RequiresPermission(anyOf = {
android.Manifest.permission.NETWORK_SETTINGS,
android.Manifest.permission.NETWORK_SETUP_WIZARD})
- public void startDppAsEnrolleeInitiator(@NonNull String configuratorUri,
- @Nullable Handler handler, @NonNull DppStatusCallback callback) {
+ public void startEasyConnectAsEnrolleeInitiator(@NonNull String configuratorUri,
+ @Nullable Handler handler, @NonNull EasyConnectStatusCallback callback) {
Looper looper = (handler == null) ? Looper.getMainLooper() : handler.getLooper();
Binder binder = new Binder();
try {
mService.startDppAsEnrolleeInitiator(binder, configuratorUri,
- new DppCallbackProxy(looper, callback));
+ new EasyConnectCallbackProxy(looper, callback));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
- * Stop or abort a current DPP session.
+ * Stop or abort a current Easy Connect (DPP) session.
+ *
* @hide
*/
@SystemApi
@RequiresPermission(anyOf = {
android.Manifest.permission.NETWORK_SETTINGS,
android.Manifest.permission.NETWORK_SETUP_WIZARD})
- public void stopDppSession() {
+ public void stopEasyConnectSession() {
try {
/* Request lower layers to stop/abort and clear resources */
mService.stopDppSession();
@@ -4682,48 +4689,50 @@
}
/**
- * Helper class to support DPP callbacks
+ * Helper class to support Easy Connect (DPP) callbacks
+ *
* @hide
*/
@SystemApi
- private static class DppCallbackProxy extends IDppCallback.Stub {
+ private static class EasyConnectCallbackProxy extends IDppCallback.Stub {
private final Handler mHandler;
- private final DppStatusCallback mDppStatusCallback;
+ private final EasyConnectStatusCallback mEasyConnectStatusCallback;
- DppCallbackProxy(Looper looper, DppStatusCallback dppStatusCallback) {
+ EasyConnectCallbackProxy(Looper looper,
+ EasyConnectStatusCallback easyConnectStatusCallback) {
mHandler = new Handler(looper);
- mDppStatusCallback = dppStatusCallback;
+ mEasyConnectStatusCallback = easyConnectStatusCallback;
}
@Override
public void onSuccessConfigReceived(int newNetworkId) {
- Log.d(TAG, "DPP onSuccessConfigReceived callback");
+ Log.d(TAG, "Easy Connect onSuccessConfigReceived callback");
mHandler.post(() -> {
- mDppStatusCallback.onEnrolleeSuccess(newNetworkId);
+ mEasyConnectStatusCallback.onEnrolleeSuccess(newNetworkId);
});
}
@Override
public void onSuccess(int status) {
- Log.d(TAG, "DPP onSuccess callback");
+ Log.d(TAG, "Easy Connect onSuccess callback");
mHandler.post(() -> {
- mDppStatusCallback.onConfiguratorSuccess(status);
+ mEasyConnectStatusCallback.onConfiguratorSuccess(status);
});
}
@Override
public void onFailure(int status) {
- Log.d(TAG, "DPP onFailure callback");
+ Log.d(TAG, "Easy Connect onFailure callback");
mHandler.post(() -> {
- mDppStatusCallback.onFailure(status);
+ mEasyConnectStatusCallback.onFailure(status);
});
}
@Override
public void onProgress(int status) {
- Log.d(TAG, "DPP onProgress callback");
+ Log.d(TAG, "Easy Connect onProgress callback");
mHandler.post(() -> {
- mDppStatusCallback.onProgress(status);
+ mEasyConnectStatusCallback.onProgress(status);
});
}
}
diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
index c744f18..7bff68a 100644
--- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -59,6 +59,7 @@
WifiConfiguration config = new WifiConfiguration();
config.setPasspointManagementObjectTree(cookie);
config.trusted = false;
+ config.updateIdentifier = "1234";
MacAddress macBeforeParcel = config.getOrCreateRandomizedMacAddress();
Parcel parcelW = Parcel.obtain();
config.writeToParcel(parcelW, 0);
@@ -73,6 +74,7 @@
// lacking a useful config.equals, check two fields near the end.
assertEquals(cookie, reconfig.getMoTree());
assertEquals(macBeforeParcel, reconfig.getOrCreateRandomizedMacAddress());
+ assertEquals(config.updateIdentifier, reconfig.updateIdentifier);
assertFalse(reconfig.trusted);
Parcel parcelWW = Parcel.obtain();
@@ -251,6 +253,18 @@
}
/**
+ * Verifies that updateIdentifier should be copied for copy constructor.
+ */
+ @Test
+ public void testUpdateIdentifierForCopyConstructor() {
+ WifiConfiguration config = new WifiConfiguration();
+ config.updateIdentifier = "1234";
+ WifiConfiguration copyConfig = new WifiConfiguration(config);
+
+ assertEquals(config.updateIdentifier, copyConfig.updateIdentifier);
+ }
+
+ /**
* Verifies that the serialization/de-serialization for softap config works.
*/
@Test