Merge "Update string referring UDSActivity package name"
diff --git a/Android.bp b/Android.bp
index 05fb3c0..e65ba0f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -249,8 +249,7 @@
"core/java/android/os/storage/IStorageEventListener.aidl",
"core/java/android/os/storage/IStorageShutdownObserver.aidl",
"core/java/android/os/storage/IObbActionListener.aidl",
- "core/java/android/security/IConfirmationPromptCallback.aidl",
- "core/java/android/security/IKeystoreService.aidl",
+ ":keystore_aidl",
"core/java/android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl",
"core/java/android/service/autofill/IAutoFillService.aidl",
"core/java/android/service/autofill/IAutofillFieldClassificationService.aidl",
@@ -425,6 +424,7 @@
"media/java/android/media/IAudioFocusDispatcher.aidl",
"media/java/android/media/IAudioRoutesObserver.aidl",
"media/java/android/media/IAudioService.aidl",
+ "media/java/android/media/IAudioServerStateDispatcher.aidl",
"media/java/android/media/IMediaHTTPConnection.aidl",
"media/java/android/media/IMediaHTTPService.aidl",
"media/java/android/media/IMediaResourceMonitor.aidl",
@@ -642,6 +642,7 @@
"system/netd/server/binder",
"system/vold/binder",
"system/bt/binder",
+ "system/security/keystore/binder",
],
},
diff --git a/Android.mk b/Android.mk
index a78a01a..3b8d6a8 100644
--- a/Android.mk
+++ b/Android.mk
@@ -36,7 +36,7 @@
define stubs-to-aidl-parcelables
gen := $(TARGET_OUT_COMMON_INTERMEDIATES)/$1.aidl
aidl_parcelables += $$(gen)
- $$(gen): $(call java-lib-header-files,$1) | $(HOST_OUT_EXECUTABLES)/sdkparcelables
+ $$(gen): $(call java-lib-header-files,$1) $(HOST_OUT_EXECUTABLES)/sdkparcelables
@echo Extract SDK parcelables: $$@
rm -f $$@
$(HOST_OUT_EXECUTABLES)/sdkparcelables $$< $$@
@@ -804,7 +804,7 @@
-Iexternal/protobuf/src
LOCAL_PROTO_JAVA_OUTPUT_PARAMS := \
store_unknown_fields = true
-LOCAL_JAVA_LIBRARIES := core-oj core-libart
+LOCAL_SDK_VERSION := current
LOCAL_SRC_FILES := \
$(call all-proto-files-under, core/proto) \
$(call all-proto-files-under, libs/incident/proto/android/os)
diff --git a/api/current.txt b/api/current.txt
index 14d61f7..df18f10 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -73,7 +73,6 @@
field public static final java.lang.String DUMP = "android.permission.DUMP";
field public static final java.lang.String EXPAND_STATUS_BAR = "android.permission.EXPAND_STATUS_BAR";
field public static final java.lang.String FACTORY_TEST = "android.permission.FACTORY_TEST";
- field public static final java.lang.String FOREGROUND_SERVICE = "android.permission.FOREGROUND_SERVICE";
field public static final java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
field public static final java.lang.String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED";
field public static final java.lang.String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE";
@@ -1469,6 +1468,7 @@
field public static final deprecated int unfocusedMonthDateColor = 16843588; // 0x1010344
field public static final int unselectedAlpha = 16843278; // 0x101020e
field public static final int updatePeriodMillis = 16843344; // 0x1010250
+ field public static final int urlBarResourceId = 16844164; // 0x1010584
field public static final int use32bitAbi = 16844053; // 0x1010515
field public static final int useDefaultMargins = 16843641; // 0x1010379
field public static final int useIntrinsicSizeAsMinimum = 16843536; // 0x1010310
@@ -3696,7 +3696,7 @@
method public boolean onCreateOptionsMenu(android.view.Menu);
method public boolean onCreatePanelMenu(int, android.view.Menu);
method public android.view.View onCreatePanelView(int);
- method public boolean onCreateThumbnail(android.graphics.Bitmap, android.graphics.Canvas);
+ method public deprecated boolean onCreateThumbnail(android.graphics.Bitmap, android.graphics.Canvas);
method public android.view.View onCreateView(java.lang.String, android.content.Context, android.util.AttributeSet);
method public android.view.View onCreateView(android.view.View, java.lang.String, android.content.Context, android.util.AttributeSet);
method protected void onDestroy();
@@ -6706,6 +6706,7 @@
field public static final int USER_OPERATION_ERROR_MAX_RUNNING_USERS = 3; // 0x3
field public static final int USER_OPERATION_ERROR_UNKNOWN = 1; // 0x1
field public static final int USER_OPERATION_SUCCESS = 0; // 0x0
+ field public static final int WIPE_EUICC = 4; // 0x4
field public static final int WIPE_EXTERNAL_STORAGE = 1; // 0x1
field public static final int WIPE_RESET_PROTECTION_DATA = 2; // 0x2
}
@@ -6740,6 +6741,7 @@
field public static final int TAG_APP_PROCESS_START = 210005; // 0x33455
field public static final int TAG_CERT_AUTHORITY_INSTALLED = 210029; // 0x3346d
field public static final int TAG_CERT_AUTHORITY_REMOVED = 210030; // 0x3346e
+ field public static final int TAG_CERT_VALIDATION_FAILURE = 210033; // 0x33471
field public static final int TAG_CRYPTO_SELF_TEST_COMPLETED = 210031; // 0x3346f
field public static final int TAG_KEYGUARD_DISABLED_FEATURES_SET = 210021; // 0x33465
field public static final int TAG_KEYGUARD_DISMISSED = 210006; // 0x33456
@@ -6748,6 +6750,7 @@
field public static final int TAG_KEY_DESTRUCTION = 210026; // 0x3346a
field public static final int TAG_KEY_GENERATED = 210024; // 0x33468
field public static final int TAG_KEY_IMPORT = 210025; // 0x33469
+ field public static final int TAG_KEY_INTEGRITY_VIOLATION = 210032; // 0x33470
field public static final int TAG_LOGGING_STARTED = 210011; // 0x3345b
field public static final int TAG_LOGGING_STOPPED = 210012; // 0x3345c
field public static final int TAG_LOG_BUFFER_SIZE_CRITICAL = 210015; // 0x3345f
@@ -9442,6 +9445,7 @@
field public static final java.lang.String DISPLAY_SERVICE = "display";
field public static final java.lang.String DOWNLOAD_SERVICE = "download";
field public static final java.lang.String DROPBOX_SERVICE = "dropbox";
+ field public static final java.lang.String EUICC_SERVICE = "euicc";
field public static final java.lang.String FINGERPRINT_SERVICE = "fingerprint";
field public static final java.lang.String HARDWARE_PROPERTIES_SERVICE = "hardware_properties";
field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
@@ -11267,6 +11271,7 @@
field public static final java.lang.String FEATURE_STRONGBOX_KEYSTORE = "android.hardware.strongbox_keystore";
field public static final java.lang.String FEATURE_TELEPHONY = "android.hardware.telephony";
field public static final java.lang.String FEATURE_TELEPHONY_CDMA = "android.hardware.telephony.cdma";
+ field public static final java.lang.String FEATURE_TELEPHONY_EUICC = "android.hardware.telephony.euicc";
field public static final java.lang.String FEATURE_TELEPHONY_GSM = "android.hardware.telephony.gsm";
field public static final java.lang.String FEATURE_TELEPHONY_MBMS = "android.hardware.telephony.mbms";
field public static final deprecated java.lang.String FEATURE_TELEVISION = "android.hardware.type.television";
@@ -12550,6 +12555,7 @@
method public abstract void onUpgrade(android.database.sqlite.SQLiteDatabase, int, int);
method public void setIdleConnectionTimeout(long);
method public void setLookasideConfig(int, int);
+ method public void setOpenParams(android.database.sqlite.SQLiteDatabase.OpenParams);
method public void setWriteAheadLoggingEnabled(boolean);
}
@@ -15844,8 +15850,6 @@
method public abstract void createReprocessableCaptureSessionByConfigurations(android.hardware.camera2.params.InputConfiguration, java.util.List<android.hardware.camera2.params.OutputConfiguration>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
method public abstract java.lang.String getId();
field public static final int TEMPLATE_MANUAL = 6; // 0x6
- field public static final int TEMPLATE_MOTION_TRACKING_BEST = 8; // 0x8
- field public static final int TEMPLATE_MOTION_TRACKING_PREVIEW = 7; // 0x7
field public static final int TEMPLATE_PREVIEW = 1; // 0x1
field public static final int TEMPLATE_RECORD = 3; // 0x3
field public static final int TEMPLATE_STILL_CAPTURE = 2; // 0x2
@@ -26752,7 +26756,7 @@
field public static final deprecated java.lang.String ACTION_BACKGROUND_DATA_SETTING_CHANGED = "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
field public static final java.lang.String ACTION_CAPTIVE_PORTAL_SIGN_IN = "android.net.conn.CAPTIVE_PORTAL";
field public static final java.lang.String ACTION_RESTRICT_BACKGROUND_CHANGED = "android.net.conn.RESTRICT_BACKGROUND_CHANGED";
- field public static final java.lang.String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
+ field public static final deprecated java.lang.String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
field public static final deprecated int DEFAULT_NETWORK_PREFERENCE = 1; // 0x1
field public static final java.lang.String EXTRA_CAPTIVE_PORTAL = "android.net.extra.CAPTIVE_PORTAL";
field public static final java.lang.String EXTRA_CAPTIVE_PORTAL_URL = "android.net.extra.CAPTIVE_PORTAL_URL";
@@ -27028,6 +27032,7 @@
field public static final int NET_CAPABILITY_CBS = 5; // 0x5
field public static final int NET_CAPABILITY_DUN = 2; // 0x2
field public static final int NET_CAPABILITY_EIMS = 10; // 0xa
+ field public static final int NET_CAPABILITY_FOREGROUND = 19; // 0x13
field public static final int NET_CAPABILITY_FOTA = 3; // 0x3
field public static final int NET_CAPABILITY_IA = 7; // 0x7
field public static final int NET_CAPABILITY_IMS = 4; // 0x4
@@ -27036,6 +27041,7 @@
field public static final int NET_CAPABILITY_NOT_METERED = 11; // 0xb
field public static final int NET_CAPABILITY_NOT_RESTRICTED = 13; // 0xd
field public static final int NET_CAPABILITY_NOT_ROAMING = 18; // 0x12
+ field public static final int NET_CAPABILITY_NOT_SUSPENDED = 21; // 0x15
field public static final int NET_CAPABILITY_NOT_VPN = 15; // 0xf
field public static final int NET_CAPABILITY_RCS = 8; // 0x8
field public static final int NET_CAPABILITY_SUPL = 1; // 0x1
@@ -28555,6 +28561,7 @@
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.net.wifi.rtt.RangingResult> CREATOR;
field public static final int STATUS_FAIL = 1; // 0x1
+ field public static final int STATUS_RESPONDER_DOES_NOT_SUPPORT_IEEE80211MC = 2; // 0x2
field public static final int STATUS_SUCCESS = 0; // 0x0
}
@@ -38680,14 +38687,14 @@
}
public final class DateTransformation implements android.os.Parcelable android.service.autofill.Transformation {
- ctor public DateTransformation(android.view.autofill.AutofillId, java.text.DateFormat);
+ ctor public DateTransformation(android.view.autofill.AutofillId, android.icu.text.DateFormat);
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.service.autofill.DateTransformation> CREATOR;
}
public final class DateValueSanitizer implements android.os.Parcelable android.service.autofill.Sanitizer {
- ctor public DateValueSanitizer(java.text.DateFormat);
+ ctor public DateValueSanitizer(android.icu.text.DateFormat);
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.service.autofill.DateValueSanitizer> CREATOR;
@@ -38698,7 +38705,7 @@
}
public static final class FieldClassification.Match {
- method public java.lang.String getRemoteId();
+ method public java.lang.String getCategoryId();
method public float getScore();
}
@@ -38863,6 +38870,7 @@
method public int describeContents();
method public java.lang.String getFieldClassificationAlgorithm();
method public java.lang.String getId();
+ method public static int getMaxCategoryCount();
method public static int getMaxFieldClassificationIdsSize();
method public static int getMaxUserDataSize();
method public static int getMaxValueLength();
@@ -40730,8 +40738,8 @@
method public final void setActive();
method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
method public final void setConnectionCapabilities(int);
- method public final void setConnectionElapsedTime(long);
method public final void setConnectionProperties(int);
+ method public final void setConnectionStartElapsedRealTime(long);
method public final void setConnectionTime(long);
method public final void setDialing();
method public final void setDisconnected(android.telecom.DisconnectCause);
@@ -42207,13 +42215,16 @@
method public java.lang.String getNumber();
method public int getSimSlotIndex();
method public int getSubscriptionId();
+ method public boolean isEmbedded();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.telephony.SubscriptionInfo> CREATOR;
}
public class SubscriptionManager {
method public void addOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener);
+ method public boolean canManageSubscription(android.telephony.SubscriptionInfo);
method public static deprecated android.telephony.SubscriptionManager from(android.content.Context);
+ method public java.util.List<android.telephony.SubscriptionInfo> getAccessibleSubscriptionInfoList();
method public android.telephony.SubscriptionInfo getActiveSubscriptionInfo(int);
method public int getActiveSubscriptionInfoCount();
method public int getActiveSubscriptionInfoCountMax();
@@ -42598,6 +42609,44 @@
}
+package android.telephony.euicc {
+
+ public final class DownloadableSubscription implements android.os.Parcelable {
+ method public int describeContents();
+ method public static android.telephony.euicc.DownloadableSubscription forActivationCode(java.lang.String);
+ method public java.lang.String getConfirmationCode();
+ method public java.lang.String getEncodedActivationCode();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.euicc.DownloadableSubscription> CREATOR;
+ }
+
+ public final class EuiccInfo implements android.os.Parcelable {
+ ctor public EuiccInfo(java.lang.String);
+ method public int describeContents();
+ method public java.lang.String getOsVersion();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.euicc.EuiccInfo> CREATOR;
+ }
+
+ public class EuiccManager {
+ method public void deleteSubscription(int, android.app.PendingIntent);
+ method public void downloadSubscription(android.telephony.euicc.DownloadableSubscription, boolean, android.app.PendingIntent);
+ method public java.lang.String getEid();
+ method public android.telephony.euicc.EuiccInfo getEuiccInfo();
+ method public boolean isEnabled();
+ method public void startResolutionActivity(android.app.Activity, int, android.content.Intent, android.app.PendingIntent) throws android.content.IntentSender.SendIntentException;
+ method public void switchToSubscription(int, android.app.PendingIntent);
+ field public static final java.lang.String ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS = "android.telephony.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS";
+ field public static final java.lang.String ACTION_NOTIFY_CARRIER_SETUP_INCOMPLETE = "android.telephony.euicc.action.NOTIFY_CARRIER_SETUP_INCOMPLETE";
+ field public static final int EMBEDDED_SUBSCRIPTION_RESULT_ERROR = 2; // 0x2
+ field public static final int EMBEDDED_SUBSCRIPTION_RESULT_OK = 0; // 0x0
+ field public static final int EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR = 1; // 0x1
+ field public static final java.lang.String EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE = "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DETAILED_CODE";
+ field public static final java.lang.String META_DATA_CARRIER_ICON = "android.telephony.euicc.carriericon";
+ }
+
+}
+
package android.telephony.gsm {
public class GsmCellLocation extends android.telephony.CellLocation {
diff --git a/api/system-current.txt b/api/system-current.txt
index 71df272..8001ee3 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -20,6 +20,7 @@
field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
field public static final deprecated java.lang.String BIND_CONNECTION_SERVICE = "android.permission.BIND_CONNECTION_SERVICE";
field public static final java.lang.String BIND_DIRECTORY_SEARCH = "android.permission.BIND_DIRECTORY_SEARCH";
+ field public static final java.lang.String BIND_EUICC_SERVICE = "android.permission.BIND_EUICC_SERVICE";
field public static final java.lang.String BIND_IMS_SERVICE = "android.permission.BIND_IMS_SERVICE";
field public static final java.lang.String BIND_KEYGUARD_APPWIDGET = "android.permission.BIND_KEYGUARD_APPWIDGET";
field public static final java.lang.String BIND_NETWORK_RECOMMENDATION_SERVICE = "android.permission.BIND_NETWORK_RECOMMENDATION_SERVICE";
@@ -186,6 +187,7 @@
field public static final java.lang.String USE_RESERVED_DISK = "android.permission.USE_RESERVED_DISK";
field public static final java.lang.String WRITE_APN_SETTINGS = "android.permission.WRITE_APN_SETTINGS";
field public static final java.lang.String WRITE_DREAM_STATE = "android.permission.WRITE_DREAM_STATE";
+ field public static final java.lang.String WRITE_EMBEDDED_SUBSCRIPTIONS = "android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS";
field public static final java.lang.String WRITE_GSERVICES = "android.permission.WRITE_GSERVICES";
field public static final java.lang.String WRITE_MEDIA_STORAGE = "android.permission.WRITE_MEDIA_STORAGE";
field public static final java.lang.String WRITE_SECURE_SETTINGS = "android.permission.WRITE_SECURE_SETTINGS";
@@ -227,7 +229,6 @@
method public boolean convertToTranslucent(android.app.Activity.TranslucentConversionListener, android.app.ActivityOptions);
method public deprecated boolean isBackgroundVisibleBehind();
method public deprecated void onBackgroundVisibleBehindChanged(boolean);
- method public void setDisablePreviewScreenshots(boolean);
}
public static abstract interface Activity.TranslucentConversionListener {
@@ -341,11 +342,13 @@
method public java.lang.String getChannelId();
method public android.app.PendingIntent getContentIntent();
method public android.app.PendingIntent getDeleteIntent();
+ method public boolean getSuppressShowOverApps();
method public boolean isAvailableOnTv();
method public android.app.Notification.TvExtender setChannel(java.lang.String);
method public android.app.Notification.TvExtender setChannelId(java.lang.String);
method public android.app.Notification.TvExtender setContentIntent(android.app.PendingIntent);
method public android.app.Notification.TvExtender setDeleteIntent(android.app.PendingIntent);
+ method public android.app.Notification.TvExtender setSuppressShowOverApps(boolean);
}
public final class NotificationChannel implements android.os.Parcelable {
@@ -433,6 +436,19 @@
field public static final int STATE_USER_UNMANAGED = 0; // 0x0
}
+ public class SystemUpdatePolicy implements android.os.Parcelable {
+ method public int describeContents();
+ method public android.app.admin.SystemUpdatePolicy.InstallationOption getInstallationOptionAt(long);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.app.admin.SystemUpdatePolicy> CREATOR;
+ field public static final int TYPE_PAUSE = 4; // 0x4
+ }
+
+ public static class SystemUpdatePolicy.InstallationOption {
+ method public long getEffectiveTime();
+ method public int getType();
+ }
+
}
package android.app.backup {
@@ -791,6 +807,7 @@
method public abstract void sendOrderedBroadcast(android.content.Intent, java.lang.String, android.os.Bundle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
field public static final java.lang.String BACKUP_SERVICE = "backup";
field public static final java.lang.String CONTEXTHUB_SERVICE = "contexthub";
+ field public static final java.lang.String EUICC_CARD_SERVICE = "euicc_card";
field public static final java.lang.String HDMI_CONTROL_SERVICE = "hdmi_control";
field public static final java.lang.String NETWORK_SCORE_SERVICE = "network_score";
field public static final java.lang.String OEM_LOCK_SERVICE = "oem_lock";
@@ -2519,12 +2536,15 @@
public class AudioManager {
method public deprecated int abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes);
+ method public void clearAudioServerStateCallback();
method public int dispatchAudioFocusChange(android.media.AudioFocusInfo, int, android.media.audiopolicy.AudioPolicy);
+ method public boolean isAudioServerRunning();
method public boolean isHdmiSystemAudioSupported();
method public int registerAudioPolicy(android.media.audiopolicy.AudioPolicy);
method public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes, int, int) throws java.lang.IllegalArgumentException;
method public deprecated int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes, int, int, android.media.audiopolicy.AudioPolicy) throws java.lang.IllegalArgumentException;
method public int requestAudioFocus(android.media.AudioFocusRequest, android.media.audiopolicy.AudioPolicy);
+ method public void setAudioServerStateCallback(java.util.concurrent.Executor, android.media.AudioManager.AudioServerStateCallback);
method public void setFocusRequestResult(android.media.AudioFocusInfo, int, android.media.audiopolicy.AudioPolicy);
method public void unregisterAudioPolicyAsync(android.media.audiopolicy.AudioPolicy);
field public static final int AUDIOFOCUS_FLAG_DELAY_OK = 1; // 0x1
@@ -2532,6 +2552,12 @@
field public static final int AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS = 2; // 0x2
}
+ public static abstract class AudioManager.AudioServerStateCallback {
+ ctor public AudioManager.AudioServerStateCallback();
+ method public void onAudioServerDown();
+ method public void onAudioServerUp();
+ }
+
public final class AudioPlaybackConfiguration implements android.os.Parcelable {
method public int getClientPid();
method public int getClientUid();
@@ -3579,11 +3605,14 @@
}
public abstract class HwBinder implements android.os.IHwBinder {
+ ctor public HwBinder();
method public static final void configureRpcThreadpool(long, boolean);
method public static void enableInstrumentation();
method public static final android.os.IHwBinder getService(java.lang.String, java.lang.String) throws java.util.NoSuchElementException, android.os.RemoteException;
method public static final android.os.IHwBinder getService(java.lang.String, java.lang.String, boolean) throws java.util.NoSuchElementException, android.os.RemoteException;
method public static final void joinRpcThreadpool();
+ method public abstract void onTransact(int, android.os.HwParcel, android.os.HwParcel, int) throws android.os.RemoteException;
+ method public final void registerService(java.lang.String) throws android.os.RemoteException;
method public final void transact(int, android.os.HwParcel, android.os.HwParcel, int) throws android.os.RemoteException;
}
@@ -4134,6 +4163,9 @@
method public static boolean putString(android.content.ContentResolver, java.lang.String, java.lang.String, java.lang.String, boolean);
method public static void resetToDefaults(android.content.ContentResolver, java.lang.String);
field public static final java.lang.String AUTOFILL_COMPAT_ALLOWED_PACKAGES = "autofill_compat_allowed_packages";
+ field public static final java.lang.String DEFAULT_SM_DP_PLUS = "default_sm_dp_plus";
+ field public static final java.lang.String INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT = "install_carrier_app_notification_persistent";
+ field public static final java.lang.String INSTALL_CARRIER_APP_NOTIFICATION_SLEEP_MILLIS = "install_carrier_app_notification_sleep_millis";
field public static final java.lang.String OTA_DISABLE_AUTOMATIC_UPDATE = "ota_disable_automatic_update";
field public static final java.lang.String THEATER_MODE_ON = "theater_mode_on";
field public static final java.lang.String WEBVIEW_MULTIPROCESS = "webview_multiprocess";
@@ -4145,6 +4177,7 @@
method public static boolean putString(android.content.ContentResolver, java.lang.String, java.lang.String, java.lang.String, boolean);
method public static void resetToDefaults(android.content.ContentResolver, java.lang.String);
field public static final java.lang.String AUTOFILL_FEATURE_FIELD_CLASSIFICATION = "autofill_field_classification";
+ field public static final java.lang.String AUTOFILL_USER_DATA_MAX_CATEGORY_COUNT = "autofill_user_data_max_category_count";
field public static final java.lang.String AUTOFILL_USER_DATA_MAX_FIELD_CLASSIFICATION_IDS_SIZE = "autofill_user_data_max_field_classification_size";
field public static final java.lang.String AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE = "autofill_user_data_max_user_data_size";
field public static final java.lang.String AUTOFILL_USER_DATA_MAX_VALUE_LENGTH = "autofill_user_data_max_value_length";
@@ -4307,6 +4340,125 @@
}
+package android.service.euicc {
+
+ public final class EuiccProfileInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method public android.service.carrier.CarrierIdentifier getCarrierIdentifier();
+ method public java.lang.String getIccid();
+ method public java.lang.String getNickname();
+ method public int getPolicyRules();
+ method public int getProfileClass();
+ method public java.lang.String getProfileName();
+ method public java.lang.String getServiceProviderName();
+ method public int getState();
+ method public java.util.List<android.telephony.UiccAccessRule> getUiccAccessRules();
+ method public boolean hasPolicyRule(int);
+ method public boolean hasPolicyRules();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.euicc.EuiccProfileInfo> CREATOR;
+ field public static final int POLICY_RULE_DELETE_AFTER_DISABLING = 4; // 0x4
+ field public static final int POLICY_RULE_DO_NOT_DELETE = 2; // 0x2
+ field public static final int POLICY_RULE_DO_NOT_DISABLE = 1; // 0x1
+ field public static final int PROFILE_CLASS_OPERATIONAL = 2; // 0x2
+ field public static final int PROFILE_CLASS_PROVISIONING = 1; // 0x1
+ field public static final int PROFILE_CLASS_TESTING = 0; // 0x0
+ field public static final int PROFILE_STATE_DISABLED = 0; // 0x0
+ field public static final int PROFILE_STATE_ENABLED = 1; // 0x1
+ }
+
+ public static final class EuiccProfileInfo.Builder {
+ ctor public EuiccProfileInfo.Builder(java.lang.String);
+ ctor public EuiccProfileInfo.Builder(android.service.euicc.EuiccProfileInfo);
+ method public android.service.euicc.EuiccProfileInfo build();
+ method public android.service.euicc.EuiccProfileInfo.Builder setCarrierIdentifier(android.service.carrier.CarrierIdentifier);
+ method public android.service.euicc.EuiccProfileInfo.Builder setIccid(java.lang.String);
+ method public android.service.euicc.EuiccProfileInfo.Builder setNickname(java.lang.String);
+ method public android.service.euicc.EuiccProfileInfo.Builder setPolicyRules(int);
+ method public android.service.euicc.EuiccProfileInfo.Builder setProfileClass(int);
+ method public android.service.euicc.EuiccProfileInfo.Builder setProfileName(java.lang.String);
+ method public android.service.euicc.EuiccProfileInfo.Builder setServiceProviderName(java.lang.String);
+ method public android.service.euicc.EuiccProfileInfo.Builder setState(int);
+ method public android.service.euicc.EuiccProfileInfo.Builder setUiccAccessRule(java.util.List<android.telephony.UiccAccessRule>);
+ }
+
+ public static abstract class EuiccProfileInfo.PolicyRule implements java.lang.annotation.Annotation {
+ }
+
+ public static abstract class EuiccProfileInfo.ProfileClass implements java.lang.annotation.Annotation {
+ }
+
+ public static abstract class EuiccProfileInfo.ProfileState implements java.lang.annotation.Annotation {
+ }
+
+ public abstract class EuiccService extends android.app.Service {
+ ctor public EuiccService();
+ method public android.os.IBinder onBind(android.content.Intent);
+ method public abstract int onDeleteSubscription(int, java.lang.String);
+ method public abstract int onDownloadSubscription(int, android.telephony.euicc.DownloadableSubscription, boolean, boolean);
+ method public abstract int onEraseSubscriptions(int);
+ method public abstract android.service.euicc.GetDefaultDownloadableSubscriptionListResult onGetDefaultDownloadableSubscriptionList(int, boolean);
+ method public abstract android.service.euicc.GetDownloadableSubscriptionMetadataResult onGetDownloadableSubscriptionMetadata(int, android.telephony.euicc.DownloadableSubscription, boolean);
+ method public abstract java.lang.String onGetEid(int);
+ method public abstract android.telephony.euicc.EuiccInfo onGetEuiccInfo(int);
+ method public abstract android.service.euicc.GetEuiccProfileInfoListResult onGetEuiccProfileInfoList(int);
+ method public abstract int onGetOtaStatus(int);
+ method public abstract int onRetainSubscriptionsForFactoryReset(int);
+ method public abstract void onStartOtaIfNecessary(int, android.service.euicc.EuiccService.OtaStatusChangedCallback);
+ method public abstract int onSwitchToSubscription(int, java.lang.String, boolean);
+ method public abstract int onUpdateSubscriptionNickname(int, java.lang.String, java.lang.String);
+ field public static final java.lang.String ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS = "android.service.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS";
+ field public static final java.lang.String ACTION_PROVISION_EMBEDDED_SUBSCRIPTION = "android.service.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION";
+ field public static final java.lang.String ACTION_RESOLVE_CONFIRMATION_CODE = "android.service.euicc.action.RESOLVE_CONFIRMATION_CODE";
+ field public static final java.lang.String ACTION_RESOLVE_DEACTIVATE_SIM = "android.service.euicc.action.RESOLVE_DEACTIVATE_SIM";
+ field public static final java.lang.String ACTION_RESOLVE_NO_PRIVILEGES = "android.service.euicc.action.RESOLVE_NO_PRIVILEGES";
+ field public static final java.lang.String CATEGORY_EUICC_UI = "android.service.euicc.category.EUICC_UI";
+ field public static final java.lang.String EUICC_SERVICE_INTERFACE = "android.service.euicc.EuiccService";
+ field public static final java.lang.String EXTRA_RESOLUTION_CALLING_PACKAGE = "android.service.euicc.extra.RESOLUTION_CALLING_PACKAGE";
+ field public static final java.lang.String EXTRA_RESOLUTION_CONFIRMATION_CODE = "android.service.euicc.extra.RESOLUTION_CONFIRMATION_CODE";
+ field public static final java.lang.String EXTRA_RESOLUTION_CONFIRMATION_CODE_RETRIED = "android.service.euicc.extra.RESOLUTION_CONFIRMATION_CODE_RETRIED";
+ field public static final java.lang.String EXTRA_RESOLUTION_CONSENT = "android.service.euicc.extra.RESOLUTION_CONSENT";
+ field public static final int RESULT_FIRST_USER = 1; // 0x1
+ field public static final int RESULT_MUST_DEACTIVATE_SIM = -1; // 0xffffffff
+ field public static final int RESULT_NEED_CONFIRMATION_CODE = -2; // 0xfffffffe
+ field public static final int RESULT_OK = 0; // 0x0
+ }
+
+ public static abstract class EuiccService.OtaStatusChangedCallback {
+ ctor public EuiccService.OtaStatusChangedCallback();
+ method public abstract void onOtaStatusChanged(int);
+ }
+
+ public final class GetDefaultDownloadableSubscriptionListResult implements android.os.Parcelable {
+ ctor public GetDefaultDownloadableSubscriptionListResult(int, android.telephony.euicc.DownloadableSubscription[]);
+ method public int describeContents();
+ method public java.util.List<android.telephony.euicc.DownloadableSubscription> getDownloadableSubscriptions();
+ method public int getResult();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.euicc.GetDefaultDownloadableSubscriptionListResult> CREATOR;
+ }
+
+ public final class GetDownloadableSubscriptionMetadataResult implements android.os.Parcelable {
+ ctor public GetDownloadableSubscriptionMetadataResult(int, android.telephony.euicc.DownloadableSubscription);
+ method public int describeContents();
+ method public android.telephony.euicc.DownloadableSubscription getDownloadableSubscription();
+ method public int getResult();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.euicc.GetDownloadableSubscriptionMetadataResult> CREATOR;
+ }
+
+ public final class GetEuiccProfileInfoListResult implements android.os.Parcelable {
+ ctor public GetEuiccProfileInfoListResult(int, android.service.euicc.EuiccProfileInfo[], boolean);
+ method public int describeContents();
+ method public boolean getIsRemovable();
+ method public java.util.List<android.service.euicc.EuiccProfileInfo> getProfiles();
+ method public int getResult();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.euicc.GetEuiccProfileInfoListResult> CREATOR;
+ }
+
+}
+
package android.service.notification {
public final class Adjustment implements android.os.Parcelable {
@@ -4907,8 +5059,14 @@
field public static final int RESULT_SYSTEM_ERROR = 15; // 0xf
}
+ public class SubscriptionInfo implements android.os.Parcelable {
+ method public java.util.List<android.telephony.UiccAccessRule> getAccessRules();
+ }
+
public class SubscriptionManager {
+ method public java.util.List<android.telephony.SubscriptionInfo> getAvailableSubscriptionInfoList();
method public java.util.List<android.telephony.SubscriptionPlan> getSubscriptionPlans(int);
+ method public void requestEmbeddedSubscriptionInfoListRefresh();
method public void setSubscriptionOverrideCongested(int, boolean, long);
method public void setSubscriptionOverrideUnmetered(int, boolean, long);
method public void setSubscriptionPlans(int, java.util.List<android.telephony.SubscriptionPlan>);
@@ -5044,6 +5202,16 @@
field public static final int SIM_STATE_PRESENT = 11; // 0xb
}
+ public final class UiccAccessRule implements android.os.Parcelable {
+ ctor public UiccAccessRule(byte[], java.lang.String, long);
+ method public int describeContents();
+ method public int getCarrierPrivilegeStatus(android.content.pm.PackageInfo);
+ method public int getCarrierPrivilegeStatus(android.content.pm.Signature, java.lang.String);
+ method public java.lang.String getPackageName();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.UiccAccessRule> CREATOR;
+ }
+
public class UiccSlotInfo implements android.os.Parcelable {
ctor public UiccSlotInfo(boolean, boolean, java.lang.String, int, int);
method public int describeContents();
@@ -5154,6 +5322,125 @@
}
+package android.telephony.euicc {
+
+ public final class DownloadableSubscription implements android.os.Parcelable {
+ method public java.util.List<android.telephony.UiccAccessRule> getAccessRules();
+ method public java.lang.String getCarrierName();
+ }
+
+ public static final class DownloadableSubscription.Builder {
+ ctor public DownloadableSubscription.Builder();
+ ctor public DownloadableSubscription.Builder(android.telephony.euicc.DownloadableSubscription);
+ method public android.telephony.euicc.DownloadableSubscription build();
+ method public android.telephony.euicc.DownloadableSubscription.Builder setAccessRules(java.util.List<android.telephony.UiccAccessRule>);
+ method public android.telephony.euicc.DownloadableSubscription.Builder setCarrierName(java.lang.String);
+ method public android.telephony.euicc.DownloadableSubscription.Builder setConfirmationCode(java.lang.String);
+ method public android.telephony.euicc.DownloadableSubscription.Builder setEncodedActivationCode(java.lang.String);
+ }
+
+ public class EuiccCardManager {
+ method public void authenticateServer(java.lang.String, java.lang.String, byte[], byte[], byte[], byte[], java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
+ method public void cancelSession(java.lang.String, byte[], int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
+ method public void deleteProfile(java.lang.String, java.lang.String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>);
+ method public void disableProfile(java.lang.String, java.lang.String, boolean, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>);
+ method public void listNotifications(java.lang.String, int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.telephony.euicc.EuiccNotification[]>);
+ method public void loadBoundProfilePackage(java.lang.String, byte[], java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
+ method public void prepareDownload(java.lang.String, byte[], byte[], byte[], byte[], java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
+ method public void removeNotificationFromList(java.lang.String, int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>);
+ method public void requestAllProfiles(java.lang.String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.service.euicc.EuiccProfileInfo[]>);
+ method public void requestDefaultSmdpAddress(java.lang.String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.String>);
+ method public void requestEuiccChallenge(java.lang.String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
+ method public void requestEuiccInfo1(java.lang.String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
+ method public void requestEuiccInfo2(java.lang.String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
+ method public void requestProfile(java.lang.String, java.lang.String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.service.euicc.EuiccProfileInfo>);
+ method public void requestRulesAuthTable(java.lang.String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.telephony.euicc.EuiccRulesAuthTable>);
+ method public void requestSmdsAddress(java.lang.String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.String>);
+ method public void resetMemory(java.lang.String, int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>);
+ method public void retrieveNotification(java.lang.String, int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.telephony.euicc.EuiccNotification>);
+ method public void retrieveNotificationList(java.lang.String, int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.telephony.euicc.EuiccNotification[]>);
+ method public void setDefaultSmdpAddress(java.lang.String, java.lang.String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>);
+ method public void setNickname(java.lang.String, java.lang.String, java.lang.String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>);
+ method public void switchToProfile(java.lang.String, java.lang.String, boolean, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.service.euicc.EuiccProfileInfo>);
+ field public static final int CANCEL_REASON_END_USER_REJECTED = 0; // 0x0
+ field public static final int CANCEL_REASON_POSTPONED = 1; // 0x1
+ field public static final int CANCEL_REASON_PPR_NOT_ALLOWED = 3; // 0x3
+ field public static final int CANCEL_REASON_TIMEOUT = 2; // 0x2
+ field public static final int RESET_OPTION_DELETE_FIELD_LOADED_TEST_PROFILES = 2; // 0x2
+ field public static final int RESET_OPTION_DELETE_OPERATIONAL_PROFILES = 1; // 0x1
+ field public static final int RESET_OPTION_RESET_DEFAULT_SMDP_ADDRESS = 4; // 0x4
+ field public static final int RESULT_OK = 0; // 0x0
+ field public static final int RESULT_UNKNOWN_ERROR = -1; // 0xffffffff
+ }
+
+ public static abstract class EuiccCardManager.CancelReason implements java.lang.annotation.Annotation {
+ }
+
+ public static abstract class EuiccCardManager.ResetOption implements java.lang.annotation.Annotation {
+ }
+
+ public static abstract interface EuiccCardManager.ResultCallback<T> {
+ method public abstract void onComplete(int, T);
+ }
+
+ public class EuiccManager {
+ method public void continueOperation(android.content.Intent, android.os.Bundle);
+ method public void getDefaultDownloadableSubscriptionList(android.app.PendingIntent);
+ method public void getDownloadableSubscriptionMetadata(android.telephony.euicc.DownloadableSubscription, android.app.PendingIntent);
+ method public int getOtaStatus();
+ field public static final java.lang.String ACTION_OTA_STATUS_CHANGED = "android.telephony.euicc.action.OTA_STATUS_CHANGED";
+ field public static final java.lang.String ACTION_PROVISION_EMBEDDED_SUBSCRIPTION = "android.telephony.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION";
+ field public static final int EUICC_OTA_FAILED = 2; // 0x2
+ field public static final int EUICC_OTA_IN_PROGRESS = 1; // 0x1
+ field public static final int EUICC_OTA_NOT_NEEDED = 4; // 0x4
+ field public static final int EUICC_OTA_STATUS_UNAVAILABLE = 5; // 0x5
+ field public static final int EUICC_OTA_SUCCEEDED = 3; // 0x3
+ field public static final java.lang.String EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION = "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION";
+ field public static final java.lang.String EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTIONS = "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTIONS";
+ }
+
+ public static abstract class EuiccManager.OtaStatus implements java.lang.annotation.Annotation {
+ }
+
+ public final class EuiccNotification implements android.os.Parcelable {
+ ctor public EuiccNotification(int, java.lang.String, int, byte[]);
+ method public int describeContents();
+ method public byte[] getData();
+ method public int getEvent();
+ method public int getSeq();
+ method public java.lang.String getTargetAddr();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final int ALL_EVENTS = 15; // 0xf
+ field public static final android.os.Parcelable.Creator<android.telephony.euicc.EuiccNotification> CREATOR;
+ field public static final int EVENT_DELETE = 8; // 0x8
+ field public static final int EVENT_DISABLE = 4; // 0x4
+ field public static final int EVENT_ENABLE = 2; // 0x2
+ field public static final int EVENT_INSTALL = 1; // 0x1
+ }
+
+ public static abstract class EuiccNotification.Event implements java.lang.annotation.Annotation {
+ }
+
+ public final class EuiccRulesAuthTable implements android.os.Parcelable {
+ method public int describeContents();
+ method public int findIndex(int, android.service.carrier.CarrierIdentifier);
+ method public boolean hasPolicyRuleFlag(int, int);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.euicc.EuiccRulesAuthTable> CREATOR;
+ field public static final int POLICY_RULE_FLAG_CONSENT_REQUIRED = 1; // 0x1
+ }
+
+ public static final class EuiccRulesAuthTable.Builder {
+ ctor public EuiccRulesAuthTable.Builder(int);
+ method public android.telephony.euicc.EuiccRulesAuthTable.Builder add(int, java.util.List<android.service.carrier.CarrierIdentifier>, int);
+ method public android.telephony.euicc.EuiccRulesAuthTable build();
+ }
+
+ public static abstract class EuiccRulesAuthTable.PolicyRuleFlag implements java.lang.annotation.Annotation {
+ }
+
+}
+
package android.telephony.ims {
public final class ImsCallForwardInfo implements android.os.Parcelable {
diff --git a/api/test-current.txt b/api/test-current.txt
index b02da04..9bfc105 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -541,6 +541,7 @@
field public static final java.lang.String ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED = "accessibility_display_magnification_enabled";
field public static final java.lang.String AUTOFILL_FEATURE_FIELD_CLASSIFICATION = "autofill_field_classification";
field public static final java.lang.String AUTOFILL_SERVICE = "autofill_service";
+ field public static final java.lang.String AUTOFILL_USER_DATA_MAX_CATEGORY_COUNT = "autofill_user_data_max_category_count";
field public static final java.lang.String AUTOFILL_USER_DATA_MAX_FIELD_CLASSIFICATION_IDS_SIZE = "autofill_user_data_max_field_classification_size";
field public static final java.lang.String AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE = "autofill_user_data_max_user_data_size";
field public static final java.lang.String AUTOFILL_USER_DATA_MAX_VALUE_LENGTH = "autofill_user_data_max_value_length";
@@ -1047,6 +1048,15 @@
}
+package android.view.animation {
+
+ public class AnimationUtils {
+ method public static void lockAnimationClock(long);
+ method public static void unlockAnimationClock();
+ }
+
+}
+
package android.view.autofill {
public final class AutofillId implements android.os.Parcelable {
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 813335a..c04e61b 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -172,6 +172,8 @@
} else if (opt.equals("--no_window_animation")
|| opt.equals("--no-window-animation")) {
instrument.noWindowAnimation = true;
+ } else if (opt.equals("--no-hidden-api-checks")) {
+ instrument.disableHiddenApiChecks = true;
} else if (opt.equals("--user")) {
instrument.userId = parseUserArg(nextArgRequired());
} else if (opt.equals("--abi")) {
diff --git a/cmds/am/src/com/android/commands/am/Instrument.java b/cmds/am/src/com/android/commands/am/Instrument.java
index d79b1a6..0dade0b 100644
--- a/cmds/am/src/com/android/commands/am/Instrument.java
+++ b/cmds/am/src/com/android/commands/am/Instrument.java
@@ -73,12 +73,17 @@
boolean protoFile = false; // write proto to a file
String logPath = null;
public boolean noWindowAnimation = false;
+ public boolean disableHiddenApiChecks = false;
public String abi = null;
public int userId = UserHandle.USER_CURRENT;
public Bundle args = new Bundle();
// Required
public String componentNameArg;
+ // Disable hidden API checks for the newly started instrumentation.
+ // Must be kept in sync with ActivityManagerService.
+ private static final int INSTRUMENTATION_FLAG_DISABLE_HIDDEN_API_CHECKS = 1 << 0;
+
/**
* Construct the instrument command runner.
*/
@@ -475,7 +480,8 @@
}
// Start the instrumentation
- if (!mAm.startInstrumentation(cn, profileFile, 0, args, watcher, connection, userId,
+ int flags = disableHiddenApiChecks ? INSTRUMENTATION_FLAG_DISABLE_HIDDEN_API_CHECKS : 0;
+ if (!mAm.startInstrumentation(cn, profileFile, flags, args, watcher, connection, userId,
abi)) {
throw new AndroidException("INSTRUMENTATION_FAILED: " + cn.flattenToString());
}
diff --git a/cmds/incident_helper/OWNERS b/cmds/incident_helper/OWNERS
new file mode 100644
index 0000000..1a68a32
--- /dev/null
+++ b/cmds/incident_helper/OWNERS
@@ -0,0 +1,2 @@
+jinyithu@google.com
+kwekua@google.com
diff --git a/cmds/incident_helper/src/parsers/CpuFreqParser.cpp b/cmds/incident_helper/src/parsers/CpuFreqParser.cpp
index 02f1ce7..fde17bd 100644
--- a/cmds/incident_helper/src/parsers/CpuFreqParser.cpp
+++ b/cmds/incident_helper/src/parsers/CpuFreqParser.cpp
@@ -62,15 +62,15 @@
ProtoOutputStream proto;
long jiffyHz = sysconf(_SC_CLK_TCK);
- proto.write(CpuFreq::JIFFY_HZ, (int)jiffyHz);
+ proto.write(CpuFreqProto::JIFFY_HZ, (int)jiffyHz);
for (int i=0; i<numCpus; i++) {
- long long token = proto.start(CpuFreq::CPU_FREQS);
- proto.write(CpuFreqStats::CPU_NAME, header[i+1]);
+ long long token = proto.start(CpuFreqProto::CPU_FREQS);
+ proto.write(CpuFreqProto::Stats::CPU_NAME, header[i+1]);
for (vector<pair<int, long long>>::iterator it = cpucores[i].begin(); it != cpucores[i].end(); it++) {
- long long stateToken = proto.start(CpuFreqStats::TIMES);
- proto.write(CpuFreqStats::TimeInState::STATE_KHZ, it->first);
- proto.write(CpuFreqStats::TimeInState::TIME_JIFFY, it->second);
+ long long stateToken = proto.start(CpuFreqProto::Stats::TIMES);
+ proto.write(CpuFreqProto::Stats::TimeInState::STATE_KHZ, it->first);
+ proto.write(CpuFreqProto::Stats::TimeInState::TIME_JIFFY, it->second);
proto.end(stateToken);
}
proto.end(token);
diff --git a/cmds/incident_helper/src/parsers/CpuInfoParser.cpp b/cmds/incident_helper/src/parsers/CpuInfoParser.cpp
index d73de54..b2b431c 100644
--- a/cmds/incident_helper/src/parsers/CpuInfoParser.cpp
+++ b/cmds/incident_helper/src/parsers/CpuInfoParser.cpp
@@ -54,11 +54,11 @@
bool nextToUsage = false;
ProtoOutputStream proto;
- Table table(CpuInfo::Task::_FIELD_NAMES, CpuInfo::Task::_FIELD_IDS, CpuInfo::Task::_FIELD_COUNT);
- table.addEnumTypeMap("s", CpuInfo::Task::_ENUM_STATUS_NAMES,
- CpuInfo::Task::_ENUM_STATUS_VALUES, CpuInfo::Task::_ENUM_STATUS_COUNT);
- table.addEnumTypeMap("pcy", CpuInfo::Task::_ENUM_POLICY_NAMES,
- CpuInfo::Task::_ENUM_POLICY_VALUES, CpuInfo::Task::_ENUM_POLICY_COUNT);
+ Table table(CpuInfoProto::Task::_FIELD_NAMES, CpuInfoProto::Task::_FIELD_IDS, CpuInfoProto::Task::_FIELD_COUNT);
+ table.addEnumTypeMap("s", CpuInfoProto::Task::_ENUM_STATUS_NAMES,
+ CpuInfoProto::Task::_ENUM_STATUS_VALUES, CpuInfoProto::Task::_ENUM_STATUS_COUNT);
+ table.addEnumTypeMap("pcy", CpuInfoProto::Task::_ENUM_POLICY_NAMES,
+ CpuInfoProto::Task::_ENUM_POLICY_VALUES, CpuInfoProto::Task::_ENUM_POLICY_COUNT);
// parse line by line
while (reader.readLine(&line)) {
@@ -67,33 +67,33 @@
nline++;
if (stripPrefix(&line, "Tasks:")) {
- writeSuffixLine(&proto, CpuInfo::TASK_STATS, line, COMMA_DELIMITER,
- CpuInfo::TaskStats::_FIELD_COUNT,
- CpuInfo::TaskStats::_FIELD_NAMES,
- CpuInfo::TaskStats::_FIELD_IDS);
+ writeSuffixLine(&proto, CpuInfoProto::TASK_STATS, line, COMMA_DELIMITER,
+ CpuInfoProto::TaskStats::_FIELD_COUNT,
+ CpuInfoProto::TaskStats::_FIELD_NAMES,
+ CpuInfoProto::TaskStats::_FIELD_IDS);
continue;
}
if (stripPrefix(&line, "Mem:")) {
- writeSuffixLine(&proto, CpuInfo::MEM, line, COMMA_DELIMITER,
- CpuInfo::MemStats::_FIELD_COUNT,
- CpuInfo::MemStats::_FIELD_NAMES,
- CpuInfo::MemStats::_FIELD_IDS);
+ writeSuffixLine(&proto, CpuInfoProto::MEM, line, COMMA_DELIMITER,
+ CpuInfoProto::MemStats::_FIELD_COUNT,
+ CpuInfoProto::MemStats::_FIELD_NAMES,
+ CpuInfoProto::MemStats::_FIELD_IDS);
continue;
}
if (stripPrefix(&line, "Swap:")) {
- writeSuffixLine(&proto, CpuInfo::SWAP, line, COMMA_DELIMITER,
- CpuInfo::MemStats::_FIELD_COUNT,
- CpuInfo::MemStats::_FIELD_NAMES,
- CpuInfo::MemStats::_FIELD_IDS);
+ writeSuffixLine(&proto, CpuInfoProto::SWAP, line, COMMA_DELIMITER,
+ CpuInfoProto::MemStats::_FIELD_COUNT,
+ CpuInfoProto::MemStats::_FIELD_NAMES,
+ CpuInfoProto::MemStats::_FIELD_IDS);
nextToSwap = true;
continue;
}
if (nextToSwap) {
- writeSuffixLine(&proto, CpuInfo::CPU_USAGE, line, DEFAULT_WHITESPACE,
- CpuInfo::CpuUsage::_FIELD_COUNT,
- CpuInfo::CpuUsage::_FIELD_NAMES,
- CpuInfo::CpuUsage::_FIELD_IDS);
+ writeSuffixLine(&proto, CpuInfoProto::CPU_USAGE, line, DEFAULT_WHITESPACE,
+ CpuInfoProto::CpuUsage::_FIELD_COUNT,
+ CpuInfoProto::CpuUsage::_FIELD_NAMES,
+ CpuInfoProto::CpuUsage::_FIELD_IDS);
nextToUsage = true;
nextToSwap = false;
continue;
@@ -138,7 +138,7 @@
continue;
}
- long long token = proto.start(CpuInfo::TASKS);
+ long long token = proto.start(CpuInfoProto::TASKS);
for (int i=0; i<(int)record.size(); i++) {
if (!table.insertField(&proto, header[i], record[i])) {
fprintf(stderr, "[%s]Line %d fails to insert field %s with value %s\n",
diff --git a/cmds/incident_helper/src/parsers/KernelWakesParser.cpp b/cmds/incident_helper/src/parsers/KernelWakesParser.cpp
index cae51ab..28816ea 100644
--- a/cmds/incident_helper/src/parsers/KernelWakesParser.cpp
+++ b/cmds/incident_helper/src/parsers/KernelWakesParser.cpp
@@ -33,7 +33,9 @@
int nline = 0;
ProtoOutputStream proto;
- Table table(WakeupSourceProto::_FIELD_NAMES, WakeupSourceProto::_FIELD_IDS, WakeupSourceProto::_FIELD_COUNT);
+ Table table(KernelWakeSourcesProto::WakeupSource::_FIELD_NAMES,
+ KernelWakeSourcesProto::WakeupSource::_FIELD_IDS,
+ KernelWakeSourcesProto::WakeupSource::_FIELD_COUNT);
// parse line by line
while (reader.readLine(&line)) {
@@ -57,7 +59,7 @@
continue;
}
- long long token = proto.start(KernelWakeSources::WAKEUP_SOURCES);
+ long long token = proto.start(KernelWakeSourcesProto::WAKEUP_SOURCES);
for (int i=0; i<(int)record.size(); i++) {
if (!table.insertField(&proto, header[i], record[i])) {
fprintf(stderr, "[%s]Line %d has bad value %s of %s\n",
diff --git a/cmds/incident_helper/src/parsers/PageTypeInfoParser.cpp b/cmds/incident_helper/src/parsers/PageTypeInfoParser.cpp
index f1b93ff..45a0e7b 100644
--- a/cmds/incident_helper/src/parsers/PageTypeInfoParser.cpp
+++ b/cmds/incident_helper/src/parsers/PageTypeInfoParser.cpp
@@ -33,7 +33,9 @@
header_t blockHeader;
ProtoOutputStream proto;
- Table table(BlockProto::_FIELD_NAMES, BlockProto::_FIELD_IDS, BlockProto::_FIELD_COUNT);
+ Table table(PageTypeInfoProto::Block::_FIELD_NAMES,
+ PageTypeInfoProto::Block::_FIELD_IDS,
+ PageTypeInfoProto::Block::_FIELD_COUNT);
while (reader.readLine(&line)) {
if (line.empty()) {
@@ -44,11 +46,11 @@
if (stripPrefix(&line, "Page block order:")) {
pageBlockOrder = toInt(line);
- proto.write(PageTypeInfo::PAGE_BLOCK_ORDER, pageBlockOrder);
+ proto.write(PageTypeInfoProto::PAGE_BLOCK_ORDER, pageBlockOrder);
continue;
}
if (stripPrefix(&line, "Pages per block:")) {
- proto.write(PageTypeInfo::PAGES_PER_BLOCK, toInt(line));
+ proto.write(PageTypeInfoProto::PAGES_PER_BLOCK, toInt(line));
continue;
}
if (stripPrefix(&line, "Free pages count per migrate type at order")) {
@@ -62,14 +64,14 @@
record_t record = parseRecord(line, COMMA_DELIMITER);
if (migrateTypeSession && record.size() == 3) {
- long long token = proto.start(PageTypeInfo::MIGRATE_TYPES);
+ long long token = proto.start(PageTypeInfoProto::MIGRATE_TYPES);
// expect part 0 starts with "Node"
if (stripPrefix(&record[0], "Node")) {
- proto.write(MigrateTypeProto::NODE, toInt(record[0]));
+ proto.write(PageTypeInfoProto::MigrateType::NODE, toInt(record[0]));
} else return BAD_VALUE;
// expect part 1 starts with "zone"
if (stripPrefix(&record[1], "zone")) {
- proto.write(MigrateTypeProto::ZONE, record[1]);
+ proto.write(PageTypeInfoProto::MigrateType::ZONE, record[1]);
} else return BAD_VALUE;
// expect part 2 starts with "type"
if (stripPrefix(&record[2], "type")) {
@@ -83,22 +85,22 @@
int pageCountsSize = pageBlockOrder + 2;
if ((int)pageCounts.size() != pageCountsSize) return BAD_VALUE;
- proto.write(MigrateTypeProto::TYPE, pageCounts[0]);
+ proto.write(PageTypeInfoProto::MigrateType::TYPE, pageCounts[0]);
for (auto i=1; i<pageCountsSize; i++) {
- proto.write(MigrateTypeProto::FREE_PAGES_COUNT, toInt(pageCounts[i]));
+ proto.write(PageTypeInfoProto::MigrateType::FREE_PAGES_COUNT, toInt(pageCounts[i]));
}
} else return BAD_VALUE;
proto.end(token);
} else if (!blockHeader.empty() && record.size() == 2) {
- long long token = proto.start(PageTypeInfo::BLOCKS);
+ long long token = proto.start(PageTypeInfoProto::BLOCKS);
if (stripPrefix(&record[0], "Node")) {
- proto.write(BlockProto::NODE, toInt(record[0]));
+ proto.write(PageTypeInfoProto::Block::NODE, toInt(record[0]));
} else return BAD_VALUE;
if (stripPrefix(&record[1], "zone")) {
record_t blockCounts = parseRecord(record[1]);
- proto.write(BlockProto::ZONE, blockCounts[0]);
+ proto.write(PageTypeInfoProto::Block::ZONE, blockCounts[0]);
for (size_t i=0; i<blockHeader.size(); i++) {
if (!table.insertField(&proto, blockHeader[i], blockCounts[i+1])) {
diff --git a/cmds/incident_helper/src/parsers/ProcrankParser.cpp b/cmds/incident_helper/src/parsers/ProcrankParser.cpp
index a4eb0fd..c1c458e 100644
--- a/cmds/incident_helper/src/parsers/ProcrankParser.cpp
+++ b/cmds/incident_helper/src/parsers/ProcrankParser.cpp
@@ -33,7 +33,7 @@
int nline = 0;
ProtoOutputStream proto;
- Table table(ProcessProto::_FIELD_NAMES, ProcessProto::_FIELD_IDS, ProcessProto::_FIELD_COUNT);
+ Table table(ProcrankProto::Process::_FIELD_NAMES, ProcrankProto::Process::_FIELD_IDS, ProcrankProto::Process::_FIELD_COUNT);
string zram, ram, total;
// parse line by line
@@ -66,7 +66,7 @@
continue;
}
- long long token = proto.start(Procrank::PROCESSES);
+ long long token = proto.start(ProcrankProto::PROCESSES);
for (int i=0; i<(int)record.size(); i++) {
if (!table.insertField(&proto, header[i], record[i])) {
fprintf(stderr, "[%s]Line %d has bad value %s of %s\n",
@@ -77,23 +77,23 @@
}
// add summary
- long long token = proto.start(Procrank::SUMMARY);
+ long long token = proto.start(ProcrankProto::SUMMARY);
if (!total.empty()) {
record = parseRecord(total);
- long long token = proto.start(SummaryProto::TOTAL);
+ long long token = proto.start(ProcrankProto::Summary::TOTAL);
for (int i=(int)record.size(); i>0; i--) {
table.insertField(&proto, header[header.size() - i].c_str(), record[record.size() - i].c_str());
}
proto.end(token);
}
if (!zram.empty()) {
- long long token = proto.start(SummaryProto::ZRAM);
- proto.write(ZramProto::RAW_TEXT, zram);
+ long long token = proto.start(ProcrankProto::Summary::ZRAM);
+ proto.write(ProcrankProto::Summary::Zram::RAW_TEXT, zram);
proto.end(token);
}
if (!ram.empty()) {
- long long token = proto.start(SummaryProto::RAM);
- proto.write(RamProto::RAW_TEXT, ram);
+ long long token = proto.start(ProcrankProto::Summary::RAM);
+ proto.write(ProcrankProto::Summary::Ram::RAW_TEXT, ram);
proto.end(token);
}
proto.end(token);
diff --git a/cmds/incident_helper/src/parsers/PsParser.cpp b/cmds/incident_helper/src/parsers/PsParser.cpp
index e9014ca..420775f 100644
--- a/cmds/incident_helper/src/parsers/PsParser.cpp
+++ b/cmds/incident_helper/src/parsers/PsParser.cpp
@@ -33,12 +33,12 @@
int diff = 0;
ProtoOutputStream proto;
- Table table(PsDumpProto::Process::_FIELD_NAMES, PsDumpProto::Process::_FIELD_IDS, PsDumpProto::Process::_FIELD_COUNT);
+ Table table(PsProto::Process::_FIELD_NAMES, PsProto::Process::_FIELD_IDS, PsProto::Process::_FIELD_COUNT);
const char* pcyNames[] = { "fg", "bg", "ta" };
- const int pcyValues[] = {PsDumpProto::Process::POLICY_FG, PsDumpProto::Process::POLICY_BG, PsDumpProto::Process::POLICY_TA};
+ const int pcyValues[] = {PsProto::Process::POLICY_FG, PsProto::Process::POLICY_BG, PsProto::Process::POLICY_TA};
table.addEnumTypeMap("pcy", pcyNames, pcyValues, 3);
const char* sNames[] = { "D", "R", "S", "T", "t", "X", "Z" };
- const int sValues[] = {PsDumpProto::Process::STATE_D, PsDumpProto::Process::STATE_R, PsDumpProto::Process::STATE_S, PsDumpProto::Process::STATE_T, PsDumpProto::Process::STATE_TRACING, PsDumpProto::Process::STATE_X, PsDumpProto::Process::STATE_Z};
+ const int sValues[] = {PsProto::Process::STATE_D, PsProto::Process::STATE_R, PsProto::Process::STATE_S, PsProto::Process::STATE_T, PsProto::Process::STATE_TRACING, PsProto::Process::STATE_X, PsProto::Process::STATE_Z};
table.addEnumTypeMap("s", sNames, sValues, 7);
// Parse line by line
@@ -71,7 +71,7 @@
continue;
}
- long long token = proto.start(PsDumpProto::PROCESSES);
+ long long token = proto.start(PsProto::PROCESSES);
for (int i=0; i<(int)record.size(); i++) {
if (!table.insertField(&proto, header[i], record[i])) {
fprintf(stderr, "[%s]Line %d has bad value %s of %s\n",
diff --git a/cmds/incident_helper/tests/CpuFreqParser_test.cpp b/cmds/incident_helper/tests/CpuFreqParser_test.cpp
index 82deee4..0839a7e 100644
--- a/cmds/incident_helper/tests/CpuFreqParser_test.cpp
+++ b/cmds/incident_helper/tests/CpuFreqParser_test.cpp
@@ -52,14 +52,14 @@
TEST_F(CpuFreqParserTest, Success) {
const string testFile = kTestDataPath + "cpufreq.txt";
CpuFreqParser parser;
- CpuFreq expected;
+ CpuFreqProto expected;
long jiffyHz = sysconf(_SC_CLK_TCK);
expected.set_jiffy_hz(jiffyHz);
- CpuFreqStats::TimeInState* state;
+ CpuFreqProto::Stats::TimeInState* state;
- CpuFreqStats* cpu0 = expected.add_cpu_freqs();
+ CpuFreqProto::Stats* cpu0 = expected.add_cpu_freqs();
cpu0->set_cpu_name("cpu0");
state = cpu0->add_times();
state->set_state_khz(307200);
@@ -71,7 +71,7 @@
state->set_state_khz(768000);
state->set_time_jiffy(22652);
- CpuFreqStats* cpu1 = expected.add_cpu_freqs();
+ CpuFreqProto::Stats* cpu1 = expected.add_cpu_freqs();
cpu1->set_cpu_name("cpu1");
state = cpu1->add_times();
state->set_state_khz(307200);
@@ -83,7 +83,7 @@
state->set_state_khz(768000);
state->set_time_jiffy(22652);
- CpuFreqStats* cpu2 = expected.add_cpu_freqs();
+ CpuFreqProto::Stats* cpu2 = expected.add_cpu_freqs();
cpu2->set_cpu_name("cpu2");
state = cpu2->add_times();
state->set_state_khz(307200);
@@ -98,7 +98,7 @@
state->set_state_khz(825600);
state->set_time_jiffy(13173);
- CpuFreqStats* cpu3 = expected.add_cpu_freqs();
+ CpuFreqProto::Stats* cpu3 = expected.add_cpu_freqs();
cpu3->set_cpu_name("cpu3");
state = cpu3->add_times();
state->set_state_khz(307200);
diff --git a/cmds/incident_helper/tests/CpuInfoParser_test.cpp b/cmds/incident_helper/tests/CpuInfoParser_test.cpp
index 8dce53e..2e50d63 100644
--- a/cmds/incident_helper/tests/CpuInfoParser_test.cpp
+++ b/cmds/incident_helper/tests/CpuInfoParser_test.cpp
@@ -52,28 +52,28 @@
TEST_F(CpuInfoParserTest, Success) {
const string testFile = kTestDataPath + "cpuinfo.txt";
CpuInfoParser parser;
- CpuInfo expected;
+ CpuInfoProto expected;
- CpuInfo::TaskStats* taskStats = expected.mutable_task_stats();
+ CpuInfoProto::TaskStats* taskStats = expected.mutable_task_stats();
taskStats->set_total(2038);
taskStats->set_running(1);
taskStats->set_sleeping(2033);
taskStats->set_stopped(0);
taskStats->set_zombie(0);
- CpuInfo::MemStats* mem = expected.mutable_mem();
+ CpuInfoProto::MemStats* mem = expected.mutable_mem();
mem->set_total(3842668);
mem->set_used(3761936);
mem->set_free(80732);
mem->set_buffers(220188);
- CpuInfo::MemStats* swap = expected.mutable_swap();
+ CpuInfoProto::MemStats* swap = expected.mutable_swap();
swap->set_total(524284);
swap->set_used(25892);
swap->set_free(498392);
swap->set_cached(1316952);
- CpuInfo::CpuUsage* usage = expected.mutable_cpu_usage();
+ CpuInfoProto::CpuUsage* usage = expected.mutable_cpu_usage();
usage->set_cpu(400);
usage->set_user(17);
usage->set_nice(0);
@@ -85,59 +85,59 @@
usage->set_host(0);
// This is a special line which is able to be parsed by the CpuInfoParser
- CpuInfo::Task* task1 = expected.add_tasks();
+ CpuInfoProto::Task* task1 = expected.add_tasks();
task1->set_pid(29438);
task1->set_tid(29438);
task1->set_user("rootabcdefghij");
task1->set_pr("20");
task1->set_ni(0);
task1->set_cpu(57.9);
- task1->set_s(CpuInfo::Task::STATUS_R);
+ task1->set_s(CpuInfoProto::Task::STATUS_R);
task1->set_virt("14M");
task1->set_res("3.8M");
- task1->set_pcy(CpuInfo::Task::POLICY_UNKNOWN);
+ task1->set_pcy(CpuInfoProto::Task::POLICY_UNKNOWN);
task1->set_cmd("top test");
task1->set_name("top");
- CpuInfo::Task* task2 = expected.add_tasks();
+ CpuInfoProto::Task* task2 = expected.add_tasks();
task2->set_pid(916);
task2->set_tid(916);
task2->set_user("system");
task2->set_pr("18");
task2->set_ni(-2);
task2->set_cpu(1.4);
- task2->set_s(CpuInfo::Task::STATUS_S);
+ task2->set_s(CpuInfoProto::Task::STATUS_S);
task2->set_virt("4.6G");
task2->set_res("404M");
- task2->set_pcy(CpuInfo::Task::POLICY_fg);
+ task2->set_pcy(CpuInfoProto::Task::POLICY_fg);
task2->set_cmd("system_server");
task2->set_name("system_server");
- CpuInfo::Task* task3 = expected.add_tasks();
+ CpuInfoProto::Task* task3 = expected.add_tasks();
task3->set_pid(28);
task3->set_tid(28);
task3->set_user("root");
task3->set_pr("-2");
task3->set_ni(0);
task3->set_cpu(1.4);
- task3->set_s(CpuInfo::Task::STATUS_S);
+ task3->set_s(CpuInfoProto::Task::STATUS_S);
task3->set_virt("0");
task3->set_res("0");
- task3->set_pcy(CpuInfo::Task::POLICY_bg);
+ task3->set_pcy(CpuInfoProto::Task::POLICY_bg);
task3->set_cmd("rcuc/3");
task3->set_name("[rcuc/3]");
- CpuInfo::Task* task4 = expected.add_tasks();
+ CpuInfoProto::Task* task4 = expected.add_tasks();
task4->set_pid(27);
task4->set_tid(27);
task4->set_user("root");
task4->set_pr("RT");
task4->set_ni(0);
task4->set_cpu(1.4);
- task4->set_s(CpuInfo::Task::STATUS_S);
+ task4->set_s(CpuInfoProto::Task::STATUS_S);
task4->set_virt("0");
task4->set_res("0");
- task4->set_pcy(CpuInfo::Task::POLICY_ta);
+ task4->set_pcy(CpuInfoProto::Task::POLICY_ta);
task4->set_cmd("migration/3");
task4->set_name("[migration/3]");
diff --git a/cmds/incident_helper/tests/KernelWakesParser_test.cpp b/cmds/incident_helper/tests/KernelWakesParser_test.cpp
index a98c62b..f92d813 100644
--- a/cmds/incident_helper/tests/KernelWakesParser_test.cpp
+++ b/cmds/incident_helper/tests/KernelWakesParser_test.cpp
@@ -52,14 +52,14 @@
TEST_F(KernelWakesParserTest, Short) {
const string testFile = kTestDataPath + "kernel_wakeups_short.txt";
KernelWakesParser parser;
- KernelWakeSources expected;
+ KernelWakeSourcesProto expected;
- WakeupSourceProto* record1 = expected.add_wakeup_sources();
+ KernelWakeSourcesProto::WakeupSource* record1 = expected.add_wakeup_sources();
record1->set_name("ab");
record1->set_active_count(8);
record1->set_last_change(123456123456LL);
- WakeupSourceProto* record2 = expected.add_wakeup_sources();
+ KernelWakeSourcesProto::WakeupSource* record2 = expected.add_wakeup_sources();
record2->set_name("df");
record2->set_active_count(143);
record2->set_last_change(0LL);
@@ -76,9 +76,9 @@
TEST_F(KernelWakesParserTest, Normal) {
const string testFile = kTestDataPath + "kernel_wakeups.txt";
KernelWakesParser parser;
- KernelWakeSources expected;
+ KernelWakeSourcesProto expected;
- WakeupSourceProto* record1 = expected.add_wakeup_sources();
+ KernelWakeSourcesProto::WakeupSource* record1 = expected.add_wakeup_sources();
record1->set_name("ipc000000ab_ATFWD-daemon");
record1->set_active_count(8);
record1->set_event_count(8);
@@ -90,7 +90,7 @@
record1->set_last_change(131348LL);
record1->set_prevent_suspend_time(0LL);
- WakeupSourceProto* record2 = expected.add_wakeup_sources();
+ KernelWakeSourcesProto::WakeupSource* record2 = expected.add_wakeup_sources();
record2->set_name("ipc000000aa_ATFWD-daemon");
record2->set_active_count(143);
record2->set_event_count(143);
diff --git a/cmds/incident_helper/tests/PageTypeInfoParser_test.cpp b/cmds/incident_helper/tests/PageTypeInfoParser_test.cpp
index a9e6e816..9bad7be 100644
--- a/cmds/incident_helper/tests/PageTypeInfoParser_test.cpp
+++ b/cmds/incident_helper/tests/PageTypeInfoParser_test.cpp
@@ -52,12 +52,12 @@
TEST_F(PageTypeInfoParserTest, Success) {
const string testFile = kTestDataPath + "pagetypeinfo.txt";
PageTypeInfoParser parser;
- PageTypeInfo expected;
+ PageTypeInfoProto expected;
expected.set_page_block_order(10);
expected.set_pages_per_block(1024);
- MigrateTypeProto* mt1 = expected.add_migrate_types();
+ PageTypeInfoProto::MigrateType* mt1 = expected.add_migrate_types();
mt1->set_node(0);
mt1->set_zone("DMA");
mt1->set_type("Unmovable");
@@ -66,7 +66,7 @@
mt1->add_free_pages_count(arr1[i]);
}
- MigrateTypeProto* mt2 = expected.add_migrate_types();
+ PageTypeInfoProto::MigrateType* mt2 = expected.add_migrate_types();
mt2->set_node(0);
mt2->set_zone("Normal");
mt2->set_type("Reclaimable");
@@ -75,7 +75,7 @@
mt2->add_free_pages_count(arr2[i]);
}
- BlockProto* block1 = expected.add_blocks();
+ PageTypeInfoProto::Block* block1 = expected.add_blocks();
block1->set_node(0);
block1->set_zone("DMA");
block1->set_unmovable(74);
@@ -86,7 +86,7 @@
block1->set_isolate(0);
- BlockProto* block2 = expected.add_blocks();
+ PageTypeInfoProto::Block* block2 = expected.add_blocks();
block2->set_node(0);
block2->set_zone("Normal");
block2->set_unmovable(70);
diff --git a/cmds/incident_helper/tests/ProcrankParser_test.cpp b/cmds/incident_helper/tests/ProcrankParser_test.cpp
index 76b25d7..0b567ae 100644
--- a/cmds/incident_helper/tests/ProcrankParser_test.cpp
+++ b/cmds/incident_helper/tests/ProcrankParser_test.cpp
@@ -52,9 +52,9 @@
TEST_F(ProcrankParserTest, HasSwapInfo) {
const string testFile = kTestDataPath + "procrank.txt";
ProcrankParser parser;
- Procrank expected;
+ ProcrankProto expected;
- ProcessProto* process1 = expected.add_processes();
+ ProcrankProto::Process* process1 = expected.add_processes();
process1->set_pid(1119);
process1->set_vss(2607640);
process1->set_rss(339564);
@@ -66,7 +66,7 @@
process1->set_zswap(10);
process1->set_cmdline("system_server");
- ProcessProto* process2 = expected.add_processes();
+ ProcrankProto::Process* process2 = expected.add_processes();
process2->set_pid(649);
process2->set_vss(11016);
process2->set_rss(1448);
@@ -78,7 +78,7 @@
process2->set_zswap(75);
process2->set_cmdline("/vendor/bin/qseecomd");
- ProcessProto* total = expected.mutable_summary()->mutable_total();
+ ProcrankProto::Process* total = expected.mutable_summary()->mutable_total();
total->set_pss(1201993);
total->set_uss(935300);
total->set_swap(88164);
@@ -104,9 +104,9 @@
TEST_F(ProcrankParserTest, NoSwapInfo) {
const string testFile = kTestDataPath + "procrank_short.txt";
ProcrankParser parser;
- Procrank expected;
+ ProcrankProto expected;
- ProcessProto* process1 = expected.add_processes();
+ ProcrankProto::Process* process1 = expected.add_processes();
process1->set_pid(1119);
process1->set_vss(2607640);
process1->set_rss(339564);
@@ -114,7 +114,7 @@
process1->set_uss(114216);
process1->set_cmdline("system_server");
- ProcessProto* process2 = expected.add_processes();
+ ProcrankProto::Process* process2 = expected.add_processes();
process2->set_pid(649);
process2->set_vss(11016);
process2->set_rss(1448);
@@ -122,7 +122,7 @@
process2->set_uss(48);
process2->set_cmdline("/vendor/bin/qseecomd");
- ProcessProto* total = expected.mutable_summary()->mutable_total();
+ ProcrankProto::Process* total = expected.mutable_summary()->mutable_total();
total->set_pss(1201993);
total->set_uss(935300);
total->set_cmdline("TOTAL");
diff --git a/cmds/incident_helper/tests/PsParser_test.cpp b/cmds/incident_helper/tests/PsParser_test.cpp
index 1f03a7f..114d634 100644
--- a/cmds/incident_helper/tests/PsParser_test.cpp
+++ b/cmds/incident_helper/tests/PsParser_test.cpp
@@ -52,10 +52,10 @@
TEST_F(PsParserTest, Normal) {
const string testFile = kTestDataPath + "ps.txt";
PsParser parser;
- PsDumpProto expected;
- PsDumpProto got;
+ PsProto expected;
+ PsProto got;
- PsDumpProto::Process* record1 = expected.add_processes();
+ PsProto::Process* record1 = expected.add_processes();
record1->set_label("u:r:init:s0");
record1->set_user("root");
record1->set_pid(1);
@@ -65,16 +65,16 @@
record1->set_rss(2636);
record1->set_wchan("SyS_epoll_wait");
record1->set_addr("0");
- record1->set_s(PsDumpProto_Process_ProcessStateCode_STATE_S);
+ record1->set_s(PsProto_Process_ProcessStateCode_STATE_S);
record1->set_pri(19);
record1->set_ni(0);
record1->set_rtprio("-");
- record1->set_sch(PsDumpProto_Process_SchedulingPolicy_SCH_NORMAL);
- record1->set_pcy(PsDumpProto::Process::POLICY_FG);
+ record1->set_sch(PsProto_Process_SchedulingPolicy_SCH_NORMAL);
+ record1->set_pcy(PsProto::Process::POLICY_FG);
record1->set_time("00:00:01");
record1->set_cmd("init");
- PsDumpProto::Process* record2 = expected.add_processes();
+ PsProto::Process* record2 = expected.add_processes();
record2->set_label("u:r:kernel:s0");
record2->set_user("root");
record2->set_pid(2);
@@ -84,16 +84,16 @@
record2->set_rss(0);
record2->set_wchan("kthreadd");
record2->set_addr("0");
- record2->set_s(PsDumpProto_Process_ProcessStateCode_STATE_S);
+ record2->set_s(PsProto_Process_ProcessStateCode_STATE_S);
record2->set_pri(19);
record2->set_ni(0);
record2->set_rtprio("-");
- record2->set_sch(PsDumpProto_Process_SchedulingPolicy_SCH_NORMAL);
- record2->set_pcy(PsDumpProto::Process::POLICY_FG);
+ record2->set_sch(PsProto_Process_SchedulingPolicy_SCH_NORMAL);
+ record2->set_pcy(PsProto::Process::POLICY_FG);
record2->set_time("00:00:00");
record2->set_cmd("kthreadd");
- PsDumpProto::Process* record3 = expected.add_processes();
+ PsProto::Process* record3 = expected.add_processes();
record3->set_label("u:r:surfaceflinger:s0");
record3->set_user("system");
record3->set_pid(499);
@@ -103,16 +103,16 @@
record3->set_rss(22024);
record3->set_wchan("futex_wait_queue_me");
record3->set_addr("0");
- record3->set_s(PsDumpProto_Process_ProcessStateCode_STATE_S);
+ record3->set_s(PsProto_Process_ProcessStateCode_STATE_S);
record3->set_pri(42);
record3->set_ni(-9);
record3->set_rtprio("2");
- record3->set_sch(PsDumpProto_Process_SchedulingPolicy_SCH_FIFO);
- record3->set_pcy(PsDumpProto::Process::POLICY_FG);
+ record3->set_sch(PsProto_Process_SchedulingPolicy_SCH_FIFO);
+ record3->set_pcy(PsProto::Process::POLICY_FG);
record3->set_time("00:00:00");
record3->set_cmd("EventThread");
- PsDumpProto::Process* record4 = expected.add_processes();
+ PsProto::Process* record4 = expected.add_processes();
record4->set_label("u:r:hal_gnss_default:s0");
record4->set_user("gps");
record4->set_pid(670);
@@ -122,16 +122,16 @@
record4->set_rss(7272);
record4->set_wchan("poll_schedule_timeout");
record4->set_addr("0");
- record4->set_s(PsDumpProto_Process_ProcessStateCode_STATE_S);
+ record4->set_s(PsProto_Process_ProcessStateCode_STATE_S);
record4->set_pri(19);
record4->set_ni(0);
record4->set_rtprio("-");
- record4->set_sch(PsDumpProto_Process_SchedulingPolicy_SCH_NORMAL);
- record4->set_pcy(PsDumpProto::Process::POLICY_FG);
+ record4->set_sch(PsProto_Process_SchedulingPolicy_SCH_NORMAL);
+ record4->set_pcy(PsProto::Process::POLICY_FG);
record4->set_time("00:00:00");
record4->set_cmd("Loc_hal_worker");
- PsDumpProto::Process* record5 = expected.add_processes();
+ PsProto::Process* record5 = expected.add_processes();
record5->set_label("u:r:platform_app:s0:c512,c768");
record5->set_user("u0_a48");
record5->set_pid(1660);
@@ -141,16 +141,16 @@
record5->set_rss(138328);
record5->set_wchan("binder_thread_read");
record5->set_addr("0");
- record5->set_s(PsDumpProto_Process_ProcessStateCode_STATE_S);
+ record5->set_s(PsProto_Process_ProcessStateCode_STATE_S);
record5->set_pri(35);
record5->set_ni(-16);
record5->set_rtprio("-");
- record5->set_sch(PsDumpProto_Process_SchedulingPolicy_SCH_NORMAL);
- record5->set_pcy(PsDumpProto::Process::POLICY_TA);
+ record5->set_sch(PsProto_Process_SchedulingPolicy_SCH_NORMAL);
+ record5->set_pcy(PsProto::Process::POLICY_TA);
record5->set_time("00:00:00");
record5->set_cmd("HwBinder:1660_1");
- PsDumpProto::Process* record6 = expected.add_processes();
+ PsProto::Process* record6 = expected.add_processes();
record6->set_label("u:r:perfd:s0");
record6->set_user("root");
record6->set_pid(1939);
@@ -160,16 +160,16 @@
record6->set_rss(2088);
record6->set_wchan("__skb_recv_datagram");
record6->set_addr("7b9782fd14");
- record6->set_s(PsDumpProto_Process_ProcessStateCode_STATE_S);
+ record6->set_s(PsProto_Process_ProcessStateCode_STATE_S);
record6->set_pri(19);
record6->set_ni(0);
record6->set_rtprio("-");
- record6->set_sch(PsDumpProto_Process_SchedulingPolicy_SCH_NORMAL);
- record6->set_pcy(PsDumpProto::Process::POLICY_UNKNOWN);
+ record6->set_sch(PsProto_Process_SchedulingPolicy_SCH_NORMAL);
+ record6->set_pcy(PsProto::Process::POLICY_UNKNOWN);
record6->set_time("00:00:00");
record6->set_cmd("perfd");
- PsDumpProto::Process* record7 = expected.add_processes();
+ PsProto::Process* record7 = expected.add_processes();
record7->set_label("u:r:perfd:s0");
record7->set_user("root");
record7->set_pid(1939);
@@ -179,16 +179,16 @@
record7->set_rss(2088);
record7->set_wchan("do_sigtimedwait");
record7->set_addr("7b9782ff6c");
- record7->set_s(PsDumpProto_Process_ProcessStateCode_STATE_S);
+ record7->set_s(PsProto_Process_ProcessStateCode_STATE_S);
record7->set_pri(19);
record7->set_ni(0);
record7->set_rtprio("-");
- record7->set_sch(PsDumpProto_Process_SchedulingPolicy_SCH_NORMAL);
- record7->set_pcy(PsDumpProto::Process::POLICY_UNKNOWN);
+ record7->set_sch(PsProto_Process_SchedulingPolicy_SCH_NORMAL);
+ record7->set_pcy(PsProto::Process::POLICY_UNKNOWN);
record7->set_time("00:00:00");
record7->set_cmd("POSIX timer 0");
- PsDumpProto::Process* record8 = expected.add_processes();
+ PsProto::Process* record8 = expected.add_processes();
record8->set_label("u:r:shell:s0");
record8->set_user("shell");
record8->set_pid(2645);
@@ -198,12 +198,12 @@
record8->set_rss(2972);
record8->set_wchan("0");
record8->set_addr("7f67a2f8b4");
- record8->set_s(PsDumpProto_Process_ProcessStateCode_STATE_R);
+ record8->set_s(PsProto_Process_ProcessStateCode_STATE_R);
record8->set_pri(19);
record8->set_ni(0);
record8->set_rtprio("-");
- record8->set_sch(PsDumpProto_Process_SchedulingPolicy_SCH_NORMAL);
- record8->set_pcy(PsDumpProto::Process::POLICY_FG);
+ record8->set_sch(PsProto_Process_SchedulingPolicy_SCH_NORMAL);
+ record8->set_pcy(PsProto::Process::POLICY_FG);
record8->set_time("00:00:00");
record8->set_cmd("ps");
@@ -221,8 +221,8 @@
} else {
int n = got.processes_size();
for (int i = 0; i < n; i++) {
- PsDumpProto::Process g = got.processes(i);
- PsDumpProto::Process e = expected.processes(i);
+ PsProto::Process g = got.processes(i);
+ PsProto::Process e = expected.processes(i);
if (g.label() != e.label()) {
fprintf(stderr, "prcs[%d]: Invalid label. Got %s, want %s\n", i, g.label().c_str(), e.label().c_str());
diff --git a/cmds/incidentd/Android.mk b/cmds/incidentd/Android.mk
index 2b00d9e..23cd2af 100644
--- a/cmds/incidentd/Android.mk
+++ b/cmds/incidentd/Android.mk
@@ -56,6 +56,7 @@
libcutils \
libincident \
liblog \
+ libprotobuf-cpp-lite \
libprotoutil \
libselinux \
libservices \
diff --git a/cmds/incidentd/OWNERS b/cmds/incidentd/OWNERS
new file mode 100644
index 0000000..1a68a32
--- /dev/null
+++ b/cmds/incidentd/OWNERS
@@ -0,0 +1,2 @@
+jinyithu@google.com
+kwekua@google.com
diff --git a/cmds/incidentd/src/Privacy.cpp b/cmds/incidentd/src/Privacy.cpp
index 3f0e331..c5078f0 100644
--- a/cmds/incidentd/src/Privacy.cpp
+++ b/cmds/incidentd/src/Privacy.cpp
@@ -73,11 +73,6 @@
case android::os::DEST_LOCAL:
return PrivacySpec(dest);
default:
- return PrivacySpec();
+ return PrivacySpec(android::os::DEST_AUTOMATIC);
}
}
-
-PrivacySpec PrivacySpec::get_default_dropbox_spec()
-{
- return PrivacySpec(android::os::DEST_AUTOMATIC);
-}
diff --git a/cmds/incidentd/src/Privacy.h b/cmds/incidentd/src/Privacy.h
index 4f3db67..ce1b8e9 100644
--- a/cmds/incidentd/src/Privacy.h
+++ b/cmds/incidentd/src/Privacy.h
@@ -75,7 +75,6 @@
// Constructs spec using static methods below.
static PrivacySpec new_spec(int dest);
- static PrivacySpec get_default_dropbox_spec();
private:
PrivacySpec(uint8_t dest) : dest(dest) {}
};
diff --git a/cmds/incidentd/src/Reporter.cpp b/cmds/incidentd/src/Reporter.cpp
index b9f479b..06baeba 100644
--- a/cmds/incidentd/src/Reporter.cpp
+++ b/cmds/incidentd/src/Reporter.cpp
@@ -18,6 +18,7 @@
#include "Reporter.h"
+#include "Privacy.h"
#include "report_directory.h"
#include "section_list.h"
@@ -65,7 +66,9 @@
:mRequests(),
mSections(),
mMainFd(-1),
- mMainDest(-1)
+ mMainDest(-1),
+ mMetadata(),
+ mSectionStats()
{
}
@@ -79,18 +82,32 @@
{
mRequests.push_back(request);
mSections.merge(request->args);
+ mMetadata.set_request_size(mMetadata.request_size() + 1);
}
void
ReportRequestSet::setMainFd(int fd)
{
mMainFd = fd;
+ mMetadata.set_use_dropbox(fd > 0);
}
void
ReportRequestSet::setMainDest(int dest)
{
mMainDest = dest;
+ PrivacySpec spec = PrivacySpec::new_spec(dest);
+ switch (spec.dest) {
+ case android::os::DEST_AUTOMATIC:
+ mMetadata.set_dest(IncidentMetadata_Destination_AUTOMATIC);
+ break;
+ case android::os::DEST_EXPLICIT:
+ mMetadata.set_dest(IncidentMetadata_Destination_EXPLICIT);
+ break;
+ case android::os::DEST_LOCAL:
+ mMetadata.set_dest(IncidentMetadata_Destination_LOCAL);
+ break;
+ }
}
bool
@@ -98,6 +115,16 @@
return mSections.containsSection(id);
}
+IncidentMetadata::SectionStats*
+ReportRequestSet::sectionStats(int id) {
+ if (mSectionStats.find(id) == mSectionStats.end()) {
+ auto stats = mMetadata.add_sections();
+ stats->set_id(id);
+ mSectionStats[id] = stats;
+ }
+ return mSectionStats[id];
+}
+
// ================================================================================
Reporter::Reporter() : Reporter(INCIDENT_DIRECTORY) { isTest = false; };
@@ -128,12 +155,12 @@
Reporter::run_report_status_t
Reporter::runReport()
{
-
status_t err = NO_ERROR;
bool needMainFd = false;
int mainFd = -1;
int mainDest = -1;
HeaderSection headers;
+ MetadataSection metadataSection;
// See if we need the main file
for (ReportRequestSet::iterator it=batch.begin(); it!=batch.end(); it++) {
@@ -182,7 +209,7 @@
const int id = (*section)->id;
if (this->batch.containsSection(id)) {
ALOGD("Taking incident report section %d '%s'", id, (*section)->name.string());
- // Notify listener of starting
+ // Notify listener of starting.
for (ReportRequestSet::iterator it=batch.begin(); it!=batch.end(); it++) {
if ((*it)->listener != NULL && (*it)->args.containsSection(id)) {
(*it)->listener->onReportSectionStatus(id,
@@ -191,14 +218,20 @@
}
// Execute - go get the data and write it into the file descriptors.
+ auto stats = batch.sectionStats(id);
+ int64_t startTime = uptimeMillis();
err = (*section)->Execute(&batch);
+ int64_t endTime = uptimeMillis();
+
+ stats->set_success(err == NO_ERROR);
+ stats->set_exec_duration_ms(endTime - startTime);
if (err != NO_ERROR) {
ALOGW("Incident section %s (%d) failed: %s. Stopping report.",
(*section)->name.string(), id, strerror(-err));
goto DONE;
}
- // Notify listener of starting
+ // Notify listener of ending.
for (ReportRequestSet::iterator it=batch.begin(); it!=batch.end(); it++) {
if ((*it)->listener != NULL && (*it)->args.containsSection(id)) {
(*it)->listener->onReportSectionStatus(id,
@@ -210,6 +243,9 @@
}
DONE:
+ // Reports the metdadata when taking the incident report.
+ if (!isTest) metadataSection.Execute(&batch);
+
// Close the file.
if (mainFd >= 0) {
close(mainFd);
diff --git a/cmds/incidentd/src/Reporter.h b/cmds/incidentd/src/Reporter.h
index f30ecf0..6058068 100644
--- a/cmds/incidentd/src/Reporter.h
+++ b/cmds/incidentd/src/Reporter.h
@@ -17,9 +17,12 @@
#ifndef REPORTER_H
#define REPORTER_H
+#include "frameworks/base/libs/incident/proto/android/os/metadata.pb.h"
+
#include <android/os/IIncidentReportStatusListener.h>
#include <android/os/IncidentReportArgs.h>
+#include <map>
#include <string>
#include <vector>
@@ -61,13 +64,20 @@
iterator end() { return mRequests.end(); }
int mainFd() { return mMainFd; }
- bool containsSection(int id);
int mainDest() { return mMainDest; }
+ IncidentMetadata& metadata() { return mMetadata; }
+
+ bool containsSection(int id);
+ IncidentMetadata::SectionStats* sectionStats(int id);
+
private:
vector<sp<ReportRequest>> mRequests;
IncidentReportArgs mSections;
int mMainFd;
int mMainDest;
+
+ IncidentMetadata mMetadata;
+ map<int, IncidentMetadata::SectionStats*> mSectionStats;
};
// ================================================================================
@@ -81,8 +91,8 @@
ReportRequestSet batch;
- Reporter();
- Reporter(const char* directory);
+ Reporter(); // PROD must use this constructor.
+ Reporter(const char* directory); // For testing purpose only.
virtual ~Reporter();
// Run the report as described in the batch and args parameters.
diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp
index faeab87..3c76298 100644
--- a/cmds/incidentd/src/Section.cpp
+++ b/cmds/incidentd/src/Section.cpp
@@ -45,6 +45,7 @@
// special section ids
const int FIELD_ID_INCIDENT_HEADER = 1;
+const int FIELD_ID_INCIDENT_METADATA = 2;
// incident section parameters
const int WAIT_MAX = 5;
@@ -149,6 +150,12 @@
EncodedBuffer::iterator data = buffer.data();
PrivacyBuffer privacyBuffer(get_privacy_of_section(id), data);
int writeable = 0;
+ auto stats = requests->sectionStats(id);
+
+ stats->set_dump_size_bytes(data.size());
+ stats->set_dump_duration_ms(buffer.durationMs());
+ stats->set_timed_out(buffer.timedOut());
+ stats->set_is_truncated(buffer.truncated());
// The streaming ones, group requests by spec in order to save unnecessary strip operations
map<PrivacySpec, vector<sp<ReportRequest>>> requestsBySpec;
@@ -182,9 +189,7 @@
// The dropbox file
if (requests->mainFd() >= 0) {
- PrivacySpec spec = requests->mainDest() < 0 ?
- PrivacySpec::get_default_dropbox_spec() :
- PrivacySpec::new_spec(requests->mainDest());
+ PrivacySpec spec = PrivacySpec::new_spec(requests->mainDest());
err = privacyBuffer.strip(spec);
if (err != NO_ERROR) return err; // the buffer data is corrupted.
if (privacyBuffer.size() == 0) goto DONE;
@@ -196,6 +201,7 @@
writeable++;
ALOGD("Section %d flushed %zu bytes to dropbox %d with spec %d", id,
privacyBuffer.size(), requests->mainFd(), spec.dest);
+ stats->set_report_size_bytes(privacyBuffer.size());
}
DONE:
@@ -236,7 +242,7 @@
// So the idea is only requests with negative fd are written to dropbox file.
int fd = request->fd >= 0 ? request->fd : requests->mainFd();
- write_section_header(fd, FIELD_ID_INCIDENT_HEADER, buf->size());
+ write_section_header(fd, id, buf->size());
write_all(fd, (uint8_t const*)buf->data(), buf->size());
// If there was an error now, there will be an error later and we will remove
// it from the list then.
@@ -244,7 +250,35 @@
}
return NO_ERROR;
}
+// ================================================================================
+MetadataSection::MetadataSection()
+ :Section(FIELD_ID_INCIDENT_METADATA, 0)
+{
+}
+MetadataSection::~MetadataSection()
+{
+}
+
+status_t
+MetadataSection::Execute(ReportRequestSet* requests) const
+{
+ std::string metadataBuf;
+ requests->metadata().SerializeToString(&metadataBuf);
+ for (ReportRequestSet::iterator it=requests->begin(); it!=requests->end(); it++) {
+ const sp<ReportRequest> request = *it;
+ if (metadataBuf.empty() || request->fd < 0 || request->err != NO_ERROR) {
+ continue;
+ }
+ write_section_header(request->fd, id, metadataBuf.size());
+ write_all(request->fd, (uint8_t const*)metadataBuf.data(), metadataBuf.size());
+ }
+ if (requests->mainFd() >= 0 && !metadataBuf.empty()) {
+ write_section_header(requests->mainFd(), id, metadataBuf.size());
+ write_all(requests->mainFd(), (uint8_t const*)metadataBuf.data(), metadataBuf.size());
+ }
+ return NO_ERROR;
+}
// ================================================================================
FileSection::FileSection(int id, const char* filename, const int64_t timeoutMs)
:Section(id, timeoutMs),
diff --git a/cmds/incidentd/src/Section.h b/cmds/incidentd/src/Section.h
index d440ee9..80cc033 100644
--- a/cmds/incidentd/src/Section.h
+++ b/cmds/incidentd/src/Section.h
@@ -59,6 +59,18 @@
};
/**
+ * Section that generates incident metadata.
+ */
+class MetadataSection : public Section
+{
+public:
+ MetadataSection();
+ virtual ~MetadataSection();
+
+ virtual status_t Execute(ReportRequestSet* requests) const;
+};
+
+/**
* Section that reads in a file.
*/
class FileSection : public Section
diff --git a/cmds/incidentd/tests/Reporter_test.cpp b/cmds/incidentd/tests/Reporter_test.cpp
index c494bd6..a1e3c34 100644
--- a/cmds/incidentd/tests/Reporter_test.cpp
+++ b/cmds/incidentd/tests/Reporter_test.cpp
@@ -180,3 +180,18 @@
ASSERT_EQ((int)results.size(), 1);
EXPECT_EQ(results[0], "\n\x2" "\b\f\n\x6" "\x12\x4" "abcd");
}
+
+TEST_F(ReporterTest, ReportMetadata) {
+ IncidentReportArgs args;
+ args.addSection(1);
+ args.setDest(android::os::DEST_EXPLICIT);
+ sp<ReportRequest> r = new ReportRequest(args, l, -1);
+ reporter->batch.add(r);
+
+ ASSERT_EQ(Reporter::REPORT_FINISHED, reporter->runReport());
+ auto metadata = reporter->batch.metadata();
+ EXPECT_EQ(IncidentMetadata_Destination_EXPLICIT, metadata.dest());
+ EXPECT_EQ(1, metadata.request_size());
+ EXPECT_TRUE(metadata.use_dropbox());
+ EXPECT_EQ(0, metadata.sections_size());
+}
\ No newline at end of file
diff --git a/cmds/incidentd/tests/Section_test.cpp b/cmds/incidentd/tests/Section_test.cpp
index 2cfd7df..5752a67 100644
--- a/cmds/incidentd/tests/Section_test.cpp
+++ b/cmds/incidentd/tests/Section_test.cpp
@@ -18,6 +18,7 @@
#include <android-base/file.h>
#include <android-base/test_utils.h>
+#include <android/os/IncidentReportArgs.h>
#include <frameworks/base/libs/incident/proto/android/os/header.pb.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -89,6 +90,18 @@
EXPECT_THAT(content, StrEq("\n\x05\x12\x03pup"));
}
+TEST(SectionTest, MetadataSection) {
+ MetadataSection ms;
+ ReportRequestSet requests;
+
+ requests.setMainFd(STDOUT_FILENO);
+ requests.sectionStats(1)->set_success(true);
+
+ CaptureStdout();
+ ASSERT_EQ(NO_ERROR, ms.Execute(&requests));
+ EXPECT_THAT(GetCapturedStdout(), StrEq("\x12\b\x18\x1\"\x4\b\x1\x10\x1"));
+}
+
TEST(SectionTest, FileSection) {
TemporaryFile tf;
FileSection fs(REVERSE_PARSER, tf.path);
@@ -243,8 +256,9 @@
IncidentReportArgs args1, args2, args3;
args1.setAll(true);
- args1.setDest(0); // LOCAL
- args2.setAll(true); // default to explicit
+ args1.setDest(android::os::DEST_LOCAL);
+ args2.setAll(true);
+ args2.setDest(android::os::DEST_EXPLICIT);
sp<SimpleListener> l = new SimpleListener();
requests.add(new ReportRequest(args1, l, output1.fd));
requests.add(new ReportRequest(args2, l, output2.fd));
@@ -283,10 +297,12 @@
ASSERT_TRUE(WriteStringToFile(VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3, input.path));
- IncidentReportArgs args1, args2, args3, args4;
+ IncidentReportArgs args1, args2, args3;
args1.setAll(true);
+ args1.setDest(android::os::DEST_EXPLICIT);
args2.setAll(true);
- args4.setAll(true);
+ args2.setDest(android::os::DEST_EXPLICIT);
+ args3.setAll(true);
sp<SimpleListener> l = new SimpleListener();
requests.add(new ReportRequest(args1, l, output1.fd));
requests.add(new ReportRequest(args2, l, output2.fd));
@@ -307,7 +323,8 @@
EXPECT_TRUE(ReadFileToString(output2.path, &content));
EXPECT_THAT(content, StrEq(string("\x02") + c + expect));
- // because args3 doesn't set section, so it should receive nothing
+ // output3 has only auto field
+ c = (char) STRING_FIELD_2.size();
EXPECT_TRUE(ReadFileToString(output3.path, &content));
- EXPECT_THAT(content, StrEq(""));
+ EXPECT_THAT(content, StrEq(string("\x02") + c + STRING_FIELD_2));
}
\ No newline at end of file
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index 8eea944..740fdc0 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -19,11 +19,9 @@
../../core/java/android/os/IStatsManager.aidl \
src/stats_log.proto \
src/statsd_config.proto \
- src/statsd_internal.proto \
src/atoms.proto \
- src/field_util.cpp \
+ src/FieldValue.cpp \
src/stats_log_util.cpp \
- src/dimension.cpp \
src/anomaly/AnomalyMonitor.cpp \
src/anomaly/AnomalyTracker.cpp \
src/anomaly/DurationAnomalyTracker.cpp \
@@ -118,10 +116,8 @@
LOCAL_CFLAGS += \
-Wall \
+ -Wextra \
-Werror \
- -Wno-missing-field-initializers \
- -Wno-unused-variable \
- -Wno-unused-function \
-Wno-unused-parameter
ifeq (debug,)
@@ -172,7 +168,6 @@
LOCAL_SRC_FILES := \
$(statsd_common_src) \
- tests/dimension_test.cpp \
tests/AnomalyMonitor_test.cpp \
tests/anomaly/AnomalyTracker_test.cpp \
tests/ConfigManager_test.cpp \
@@ -184,6 +179,7 @@
tests/MetricsManager_test.cpp \
tests/StatsLogProcessor_test.cpp \
tests/UidMap_test.cpp \
+ tests/FieldValue_test.cpp \
tests/condition/CombinationConditionTracker_test.cpp \
tests/condition/SimpleConditionTracker_test.cpp \
tests/metrics/OringDurationTracker_test.cpp \
diff --git a/cmds/statsd/OWNERS b/cmds/statsd/OWNERS
new file mode 100644
index 0000000..362d411
--- /dev/null
+++ b/cmds/statsd/OWNERS
@@ -0,0 +1,6 @@
+bookatz@google.com
+jinyithu@google.com
+kwekua@google.com
+stlafon@google.com
+yaochen@google.com
+yanglu@google.com
diff --git a/cmds/statsd/src/FieldValue.cpp b/cmds/statsd/src/FieldValue.cpp
new file mode 100644
index 0000000..6894bcf
--- /dev/null
+++ b/cmds/statsd/src/FieldValue.cpp
@@ -0,0 +1,202 @@
+/*
+ * 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.
+ */
+
+#define DEBUG false
+#include "Log.h"
+#include "FieldValue.h"
+#include "HashableDimensionKey.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+int32_t getEncodedField(int32_t pos[], int32_t depth, bool includeDepth) {
+ int32_t field = 0;
+ for (int32_t i = 0; i <= depth; i++) {
+ int32_t shiftBits = 8 * (kMaxLogDepth - i);
+ field |= (pos[i] << shiftBits);
+ }
+
+ if (includeDepth) {
+ field |= (depth << 24);
+ }
+ return field;
+}
+
+int32_t encodeMatcherMask(int32_t mask[], int32_t depth) {
+ return getEncodedField(mask, depth, false) | 0xff000000;
+}
+
+bool Field::matches(const Matcher& matcher) const {
+ if (mTag != matcher.mMatcher.getTag()) {
+ return false;
+ }
+ if ((mField & matcher.mMask) == matcher.mMatcher.getField()) {
+ return true;
+ }
+
+ return false;
+}
+
+void translateFieldMatcher(int tag, const FieldMatcher& matcher, int depth, int* pos, int* mask,
+ std::vector<Matcher>* output) {
+ if (depth > kMaxLogDepth) {
+ ALOGE("depth > 2");
+ return;
+ }
+
+ pos[depth] = matcher.field();
+ mask[depth] = 0x7f;
+
+ if (matcher.has_position()) {
+ depth++;
+ if (depth > 2) {
+ return;
+ }
+ switch (matcher.position()) {
+ case Position::ANY:
+ pos[depth] = 0;
+ mask[depth] = 0;
+ break;
+ case Position::FIRST:
+ pos[depth] = 1;
+ mask[depth] = 0x7f;
+ break;
+ case Position::LAST:
+ pos[depth] = 0x80;
+ mask[depth] = 0x80;
+ break;
+ case Position::POSITION_UNKNOWN:
+ pos[depth] = 0;
+ mask[depth] = 0;
+ break;
+ }
+ }
+
+ if (matcher.child_size() == 0) {
+ output->push_back(Matcher(Field(tag, pos, depth), encodeMatcherMask(mask, depth)));
+ } else {
+ for (const auto& child : matcher.child()) {
+ translateFieldMatcher(tag, child, depth + 1, pos, mask, output);
+ }
+ }
+}
+
+void translateFieldMatcher(const FieldMatcher& matcher, std::vector<Matcher>* output) {
+ int pos[] = {1, 1, 1};
+ int mask[] = {0x7f, 0x7f, 0x7f};
+ int tag = matcher.field();
+ for (const auto& child : matcher.child()) {
+ translateFieldMatcher(tag, child, 0, pos, mask, output);
+ }
+}
+
+bool isAttributionUidField(const FieldValue& value) {
+ int field = value.mField.getField() & 0xff007f;
+ if (field == 0x10001 && value.mValue.getType() == INT) {
+ return true;
+ }
+ return false;
+}
+
+bool isAttributionUidField(const Field& field, const Value& value) {
+ int f = field.getField() & 0xff007f;
+ if (f == 0x10001 && value.getType() == INT) {
+ return true;
+ }
+ return false;
+}
+
+Value::Value(const Value& from) {
+ type = from.getType();
+ switch (type) {
+ case INT:
+ int_value = from.int_value;
+ break;
+ case LONG:
+ long_value = from.long_value;
+ break;
+ case FLOAT:
+ float_value = from.float_value;
+ break;
+ case STRING:
+ str_value = from.str_value;
+ break;
+ }
+}
+
+std::string Value::toString() const {
+ switch (type) {
+ case INT:
+ return std::to_string(int_value) + "[I]";
+ case LONG:
+ return std::to_string(long_value) + "[L]";
+ case FLOAT:
+ return std::to_string(float_value) + "[F]";
+ case STRING:
+ return str_value + "[S]";
+ }
+}
+
+bool Value::operator==(const Value& that) const {
+ if (type != that.getType()) return false;
+
+ switch (type) {
+ case INT:
+ return int_value == that.int_value;
+ case LONG:
+ return long_value == that.long_value;
+ case FLOAT:
+ return float_value == that.float_value;
+ case STRING:
+ return str_value == that.str_value;
+ }
+}
+
+bool Value::operator!=(const Value& that) const {
+ if (type != that.getType()) return true;
+ switch (type) {
+ case INT:
+ return int_value != that.int_value;
+ case LONG:
+ return long_value != that.long_value;
+ case FLOAT:
+ return float_value != that.float_value;
+ case STRING:
+ return str_value != that.str_value;
+ }
+}
+
+bool Value::operator<(const Value& that) const {
+ if (type != that.getType()) return type < that.getType();
+
+ switch (type) {
+ case INT:
+ return int_value < that.int_value;
+ case LONG:
+ return long_value < that.long_value;
+ case FLOAT:
+ return float_value < that.float_value;
+ case STRING:
+ return str_value < that.str_value;
+ default:
+ return false;
+ }
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/src/FieldValue.h b/cmds/statsd/src/FieldValue.h
new file mode 100644
index 0000000..d17dded
--- /dev/null
+++ b/cmds/statsd/src/FieldValue.h
@@ -0,0 +1,323 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+class HashableDimensionKey;
+struct Matcher;
+struct Field;
+struct FieldValue;
+
+const int32_t kAttributionField = 1;
+const int32_t kMaxLogDepth = 2;
+const int32_t kLastBitMask = 0x80;
+const int32_t kClearLastBitDeco = 0x7f;
+
+enum Type { INT, LONG, FLOAT, STRING };
+
+int32_t getEncodedField(int32_t pos[], int32_t depth, bool includeDepth);
+
+int32_t encodeMatcherMask(int32_t mask[], int32_t depth);
+
+// Get the encoded field for a leaf with a [field] number at depth 0;
+inline int32_t getSimpleField(size_t field) {
+ return ((int32_t)field << 8 * 2);
+}
+/**
+ * Field is a wrapper class for 2 integers that represents the field of a log element in its Atom
+ * proto.
+ * [mTag]: the atom id.
+ * [mField]: encoded path from the root (atom) to leaf.
+ *
+ * For example:
+ * WakeLockStateChanged {
+ * repeated AttributionNode = 1;
+ * int state = 2;
+ * string tag = 3;
+ * }
+ * Read from logd, the items are structured as below:
+ * [[[1000, "tag"], [2000, "tag2"],], 2,"hello"]
+ *
+ * When we read through the list, we will encode each field in a 32bit integer.
+ * 8bit segments |--------|--------|--------|--------|
+ * Depth field0 [L]field1 [L]field1
+ *
+ * The first 8 bits are the depth of the field. for example, the uid 1000 has depth 2.
+ * The following 3 8-bit are for the item's position at each level.
+ * The first bit of each 8bits field is reserved to mark if the item is the last item at that level
+ * this is to make matching easier later.
+ *
+ * The above wakelock event is translated into FieldValue pairs.
+ * 0x02010101->1000
+ * 0x02010182->tag
+ * 0x02018201->2000
+ * 0x02018282->tag2
+ * 0x00020000->2
+ * 0x00030000->"hello"
+ *
+ * This encoding is the building block for the later operations.
+ * Please see the definition for Matcher below to see how the matching is done.
+ */
+struct Field {
+private:
+ int32_t mTag;
+ int32_t mField;
+
+public:
+ Field(int32_t tag, int32_t pos[], int32_t depth) : mTag(tag) {
+ mField = getEncodedField(pos, depth, true);
+ }
+
+ Field(const Field& from) : mTag(from.getTag()), mField(from.getField()) {
+ }
+
+ Field(int32_t tag, int32_t field) : mTag(tag), mField(field){};
+
+ inline void setField(int32_t field) {
+ mField = field;
+ }
+
+ inline void setTag(int32_t tag) {
+ mTag = tag;
+ }
+
+ inline void decorateLastPos(int32_t depth) {
+ int32_t mask = kLastBitMask << 8 * (kMaxLogDepth - depth);
+ mField |= mask;
+ }
+
+ inline int32_t getTag() const {
+ return mTag;
+ }
+
+ inline int32_t getDepth() const {
+ return (mField >> 24);
+ }
+
+ inline int32_t getPath(int32_t depth) const {
+ if (depth > 2 || depth < 0) return 0;
+
+ int32_t field = (mField & 0x00ffffff);
+ int32_t mask = 0xffffffff;
+ return (field & (mask << 8 * (kMaxLogDepth - depth)));
+ }
+
+ inline int32_t getPrefix(int32_t depth) const {
+ if (depth == 0) return 0;
+ return getPath(depth - 1);
+ }
+
+ inline int32_t getField() const {
+ return mField;
+ }
+
+ inline int32_t getRawPosAtDepth(int32_t depth) const {
+ int32_t field = (mField & 0x00ffffff);
+ int32_t shift = 8 * (kMaxLogDepth - depth);
+ int32_t mask = 0xff << shift;
+
+ return (field & mask) >> shift;
+ }
+
+ inline int32_t getPosAtDepth(int32_t depth) const {
+ return getRawPosAtDepth(depth) & kClearLastBitDeco;
+ }
+
+ // Check if the first bit of the 8-bit segment for depth is 1
+ inline bool isLastPos(int32_t depth) const {
+ int32_t field = (mField & 0x00ffffff);
+ int32_t mask = kLastBitMask << 8 * (kMaxLogDepth - depth);
+ return (field & mask) != 0;
+ }
+
+ // if the 8-bit segment is all 0's
+ inline bool isAnyPosMatcher(int32_t depth) const {
+ return getDepth() >= depth && getRawPosAtDepth(depth) == 0;
+ }
+ // if the 8bit is 0x80 (1000 0000)
+ inline bool isLastPosMatcher(int32_t depth) const {
+ return getDepth() >= depth && getRawPosAtDepth(depth) == kLastBitMask;
+ }
+
+ inline bool operator==(const Field& that) const {
+ return mTag == that.getTag() && mField == that.getField();
+ };
+
+ inline bool operator!=(const Field& that) const {
+ return mTag != that.getTag() || mField != that.getField();
+ };
+
+ bool operator<(const Field& that) const {
+ if (mTag != that.getTag()) {
+ return mTag < that.getTag();
+ }
+
+ if (mField != that.getField()) {
+ return mField < that.getField();
+ }
+
+ return false;
+ }
+ bool matches(const Matcher& that) const;
+};
+
+/**
+ * Matcher represents a leaf matcher in the FieldMatcher in statsd_config.
+ *
+ * It contains all information needed to match one or more leaf node.
+ * All information is encoded in a Field(2 ints) and a bit mask(1 int).
+ *
+ * For example, to match the first/any/last uid field in attribution chain in Atom 10,
+ * we have the following FieldMatcher in statsd_config
+ * FieldMatcher {
+ * field:10
+ * FieldMatcher {
+ * field:1
+ * position: any/last/first
+ * FieldMatcher {
+ * field:1
+ * }
+ * }
+ * }
+ *
+ * We translate the FieldMatcher into a Field, and mask
+ * First: [Matcher Field] 0x02010101 [Mask]0xffff7fff
+ * Last: [Matcher Field] 0x02018001 [Mask]0xffff80ff
+ * Any: [Matcher Field] 0x02010001 [Mask]0xffff00ff
+ *
+ * [To match a log Field with a Matcher] we apply the bit mask to the log Field and check if
+ * the result is equal to the Matcher Field. That's a bit wise AND operation + check if 2 ints are
+ * equal. Nothing can beat the performance of this matching algorithm.
+ *
+ * TODO: ADD EXAMPLE HERE.
+ */
+struct Matcher {
+ Matcher(const Field& matcher, int32_t mask) : mMatcher(matcher), mMask(mask){};
+
+ const Field mMatcher;
+ const int32_t mMask;
+
+ bool hasAnyPositionMatcher(int* prefix) const {
+ if (mMatcher.getDepth() == 2 && mMatcher.getRawPosAtDepth(2) == 0) {
+ (*prefix) = mMatcher.getPrefix(2);
+ return true;
+ }
+ return false;
+ }
+};
+
+/**
+ * A wrapper for a union type to contain multiple types of values.
+ *
+ */
+struct Value {
+ Value(int32_t v) {
+ int_value = v;
+ type = INT;
+ }
+
+ Value(int64_t v) {
+ long_value = v;
+ type = LONG;
+ }
+
+ Value(float v) {
+ float_value = v;
+ type = FLOAT;
+ }
+
+ Value(const std::string& v) {
+ str_value = v;
+ type = STRING;
+ }
+
+ void setInt(int32_t v) {
+ int_value = v;
+ type = INT;
+ }
+
+ void setLong(int64_t v) {
+ long_value = v;
+ type = LONG;
+ }
+
+ union {
+ int32_t int_value;
+ int64_t long_value;
+ float float_value;
+ };
+ std::string str_value;
+
+ Type type;
+
+ std::string toString() const;
+
+ Type getType() const {
+ return type;
+ }
+
+ Value(const Value& from);
+
+ bool operator==(const Value& that) const;
+ bool operator!=(const Value& that) const;
+
+ bool operator<(const Value& that) const;
+
+private:
+ Value(){};
+};
+
+/**
+ * Represents a log item, or a dimension item (They are essentially the same).
+ */
+struct FieldValue {
+ FieldValue(const Field& field, const Value& value) : mField(field), mValue(value) {
+ }
+ bool operator==(const FieldValue& that) const {
+ return mField == that.mField && mValue == that.mValue;
+ }
+ bool operator!=(const FieldValue& that) const {
+ return mField != that.mField || mValue != that.mValue;
+ }
+ bool operator<(const FieldValue& that) const {
+ if (mField != that.mField) {
+ return mField < that.mField;
+ }
+
+ if (mValue != that.mValue) {
+ return mValue < that.mValue;
+ }
+
+ return false;
+ }
+
+ Field mField;
+ Value mValue;
+};
+
+bool isAttributionUidField(const FieldValue& value);
+
+void translateFieldMatcher(const FieldMatcher& matcher, std::vector<Matcher>* output);
+
+bool isAttributionUidField(const Field& field, const Value& value);
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/HashableDimensionKey.cpp b/cmds/statsd/src/HashableDimensionKey.cpp
index 8483b02..d901bd6 100644
--- a/cmds/statsd/src/HashableDimensionKey.cpp
+++ b/cmds/statsd/src/HashableDimensionKey.cpp
@@ -13,177 +13,251 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#define DEBUG false // STOPSHIP if true
+#include "Log.h"
#include "HashableDimensionKey.h"
-#include "dimension.h"
+#include "FieldValue.h"
namespace android {
namespace os {
namespace statsd {
+using std::vector;
-android::hash_t hashDimensionsValue(int64_t seed, const DimensionsValue& value) {
- android::hash_t hash = seed;
- hash = android::JenkinsHashMix(hash, android::hash_type(value.field()));
-
- hash = android::JenkinsHashMix(hash, android::hash_type((int)value.value_case()));
- switch (value.value_case()) {
- case DimensionsValue::ValueCase::kValueStr:
- hash = android::JenkinsHashMix(
- hash,
- static_cast<uint32_t>(std::hash<std::string>()(value.value_str())));
- break;
- case DimensionsValue::ValueCase::kValueInt:
- hash = android::JenkinsHashMix(hash, android::hash_type(value.value_int()));
- break;
- case DimensionsValue::ValueCase::kValueLong:
- hash = android::JenkinsHashMix(
- hash, android::hash_type(static_cast<int64_t>(value.value_long())));
- break;
- case DimensionsValue::ValueCase::kValueBool:
- hash = android::JenkinsHashMix(hash, android::hash_type(value.value_bool()));
- break;
- case DimensionsValue::ValueCase::kValueFloat: {
- float floatVal = value.value_float();
- hash = android::JenkinsHashMixBytes(hash, (uint8_t*)&floatVal, sizeof(float));
- break;
- }
- case DimensionsValue::ValueCase::kValueTuple: {
- hash = android::JenkinsHashMix(hash, android::hash_type(
- value.value_tuple().dimensions_value_size()));
- for (int i = 0; i < value.value_tuple().dimensions_value_size(); ++i) {
- hash = android::JenkinsHashMix(
- hash,
- hashDimensionsValue(value.value_tuple().dimensions_value(i)));
+android::hash_t hashDimension(const HashableDimensionKey& value) {
+ android::hash_t hash = 0;
+ for (const auto& fieldValue : value.getValues()) {
+ hash = android::JenkinsHashMix(hash, android::hash_type((int)fieldValue.mField.getField()));
+ hash = android::JenkinsHashMix(hash, android::hash_type((int)fieldValue.mField.getTag()));
+ hash = android::JenkinsHashMix(hash, android::hash_type((int)fieldValue.mValue.getType()));
+ switch (fieldValue.mValue.getType()) {
+ case INT:
+ hash = android::JenkinsHashMix(hash,
+ android::hash_type(fieldValue.mValue.int_value));
+ break;
+ case LONG:
+ hash = android::JenkinsHashMix(hash,
+ android::hash_type(fieldValue.mValue.long_value));
+ break;
+ case STRING:
+ hash = android::JenkinsHashMix(hash, static_cast<uint32_t>(std::hash<std::string>()(
+ fieldValue.mValue.str_value)));
+ break;
+ case FLOAT: {
+ float floatVal = fieldValue.mValue.float_value;
+ hash = android::JenkinsHashMixBytes(hash, (uint8_t*)&floatVal, sizeof(float));
+ break;
}
- break;
}
- case DimensionsValue::ValueCase::VALUE_NOT_SET:
- break;
}
return JenkinsHashWhiten(hash);
}
-android::hash_t hashDimensionsValue(const DimensionsValue& value) {
- return hashDimensionsValue(0, value);
-}
-
-android::hash_t hashMetricDimensionKey(int64_t seed, const MetricDimensionKey& dimensionKey) {
- android::hash_t hash = seed;
- hash = android::JenkinsHashMix(hash, std::hash<MetricDimensionKey>{}(dimensionKey));
- return JenkinsHashWhiten(hash);
-}
-
-using std::string;
-
-string HashableDimensionKey::toString() const {
- return DimensionsValueToString(getDimensionsValue());
-}
-
-bool EqualsTo(const DimensionsValue& s1, const DimensionsValue& s2) {
- if (s1.field() != s2.field()) {
- return false;
- }
- if (s1.value_case() != s2.value_case()) {
- return false;
- }
- switch (s1.value_case()) {
- case DimensionsValue::ValueCase::kValueStr:
- return (s1.value_str() == s2.value_str());
- case DimensionsValue::ValueCase::kValueInt:
- return s1.value_int() == s2.value_int();
- case DimensionsValue::ValueCase::kValueLong:
- return s1.value_long() == s2.value_long();
- case DimensionsValue::ValueCase::kValueBool:
- return s1.value_bool() == s2.value_bool();
- case DimensionsValue::ValueCase::kValueFloat:
- return s1.value_float() == s2.value_float();
- case DimensionsValue::ValueCase::kValueTuple:
- {
- if (s1.value_tuple().dimensions_value_size() !=
- s2.value_tuple().dimensions_value_size()) {
- return false;
- }
- bool allMatched = true;
- for (int i = 0; allMatched && i < s1.value_tuple().dimensions_value_size(); ++i) {
- allMatched &= EqualsTo(s1.value_tuple().dimensions_value(i),
- s2.value_tuple().dimensions_value(i));
- }
- return allMatched;
+// Filter fields using the matchers and output the results as a HashableDimensionKey.
+// Note: HashableDimensionKey is just a wrapper for vector<FieldValue>
+bool filterValues(const vector<Matcher>& matcherFields, const vector<FieldValue>& values,
+ vector<HashableDimensionKey>* output) {
+ output->push_back(HashableDimensionKey());
+ // Top level is only tag id. Now take the real child matchers
+ int prevAnyMatcherPrefix = 0;
+ size_t prevPrevFanout = 0;
+ size_t prevFanout = 0;
+ // For each matcher get matched results.
+ for (const auto& matcher : matcherFields) {
+ vector<FieldValue> matchedResults;
+ for (const auto& value : values) {
+ // TODO: potential optimization here to break early because all fields are naturally
+ // sorted.
+ if (value.mField.matches(matcher)) {
+ matchedResults.push_back(FieldValue(
+ Field(value.mField.getTag(), (value.mField.getField() & matcher.mMask)),
+ value.mValue));
}
- case DimensionsValue::ValueCase::VALUE_NOT_SET:
- default:
- return true;
- }
-}
+ }
-bool LessThan(const DimensionsValue& s1, const DimensionsValue& s2) {
- if (s1.field() != s2.field()) {
- return s1.field() < s2.field();
- }
- if (s1.value_case() != s2.value_case()) {
- return s1.value_case() < s2.value_case();
- }
- switch (s1.value_case()) {
- case DimensionsValue::ValueCase::kValueStr:
- return s1.value_str() < s2.value_str();
- case DimensionsValue::ValueCase::kValueInt:
- return s1.value_int() < s2.value_int();
- case DimensionsValue::ValueCase::kValueLong:
- return s1.value_long() < s2.value_long();
- case DimensionsValue::ValueCase::kValueBool:
- return (int)s1.value_bool() < (int)s2.value_bool();
- case DimensionsValue::ValueCase::kValueFloat:
- return s1.value_float() < s2.value_float();
- case DimensionsValue::ValueCase::kValueTuple:
- {
- if (s1.value_tuple().dimensions_value_size() !=
- s2.value_tuple().dimensions_value_size()) {
- return s1.value_tuple().dimensions_value_size() <
- s2.value_tuple().dimensions_value_size();
- }
- for (int i = 0; i < s1.value_tuple().dimensions_value_size(); ++i) {
- if (EqualsTo(s1.value_tuple().dimensions_value(i),
- s2.value_tuple().dimensions_value(i))) {
- continue;
- } else {
- return LessThan(s1.value_tuple().dimensions_value(i),
- s2.value_tuple().dimensions_value(i));
- }
- }
+ if (matchedResults.size() == 0) {
+ VLOG("We can't find a dimension value for matcher (%d)%#x.", matcher.mMatcher.getTag(),
+ matcher.mMatcher.getField());
+ continue;
+ }
+
+ if (matchedResults.size() == 1) {
+ for (auto& dimension : *output) {
+ dimension.addValue(matchedResults[0]);
+ }
+ prevAnyMatcherPrefix = 0;
+ prevFanout = 0;
+ continue;
+ }
+
+ // All the complexity below is because we support ANY in dimension.
+ bool createFanout = true;
+ // createFanout is true when the matcher doesn't need to follow the prev matcher's
+ // order.
+ // e.g., get (uid, tag) from any position in attribution. because we have translated
+ // it as 2 matchers, they need to follow the same ordering, we can't create a cross
+ // product of all uid and tags.
+ // However, if the 2 matchers have different prefix, they will create a cross product
+ // e.g., [any uid] [any some other repeated field], we will create a cross product for them
+ if (prevAnyMatcherPrefix != 0) {
+ int anyMatcherPrefix = 0;
+ bool isAnyMatcher = matcher.hasAnyPositionMatcher(&anyMatcherPrefix);
+ if (isAnyMatcher && anyMatcherPrefix == prevAnyMatcherPrefix) {
+ createFanout = false;
+ } else {
+ prevAnyMatcherPrefix = anyMatcherPrefix;
+ }
+ }
+
+ // Each matcher should match exact one field, unless position is ANY
+ // When x number of fields matches a matcher, the returned dimension
+ // size is multiplied by x.
+ int oldSize;
+ if (createFanout) {
+ // First create fanout (fanout size is matchedResults.Size which could be one,
+ // which means we do nothing here)
+ oldSize = output->size();
+ for (size_t i = 1; i < matchedResults.size(); i++) {
+ output->insert(output->end(), output->begin(), output->begin() + oldSize);
+ }
+ prevPrevFanout = oldSize;
+ prevFanout = matchedResults.size();
+ } else {
+ // If we should not create fanout, e.g., uid tag from same position should be remain
+ // together.
+ oldSize = prevPrevFanout;
+ if (prevFanout != matchedResults.size()) {
+ // sanity check.
+ ALOGE("2 Any matcher result in different output");
return false;
}
- case DimensionsValue::ValueCase::VALUE_NOT_SET:
- default:
- return false;
+ }
+ // now add the matched field value to output
+ for (size_t i = 0; i < matchedResults.size(); i++) {
+ for (int j = 0; j < oldSize; j++) {
+ (*output)[i * oldSize + j].addValue(matchedResults[i]);
+ }
+ }
}
+
+ return output->size() > 0 && (*output)[0].getValues().size() > 0;
+}
+
+void filterGaugeValues(const std::vector<Matcher>& matcherFields,
+ const std::vector<FieldValue>& values, std::vector<FieldValue>* output) {
+ for (const auto& field : matcherFields) {
+ for (const auto& value : values) {
+ if (value.mField.matches(field)) {
+ output->push_back(value);
+ }
+ }
+ }
+}
+
+void getDimensionForCondition(const LogEvent& event, Metric2Condition links,
+ vector<HashableDimensionKey>* conditionDimension) {
+ // Get the dimension first by using dimension from what.
+ filterValues(links.metricFields, event.getValues(), conditionDimension);
+
+ // Then replace the field with the dimension from condition.
+ for (auto& dim : *conditionDimension) {
+ size_t count = dim.getValues().size();
+ if (count != links.conditionFields.size()) {
+ // ALOGE("WTF condition link is bad");
+ return;
+ }
+
+ for (size_t i = 0; i < count; i++) {
+ dim.mutableValue(i)->mField.setField(links.conditionFields[i].mMatcher.getField());
+ dim.mutableValue(i)->mField.setTag(links.conditionFields[i].mMatcher.getTag());
+ }
+ }
+}
+
+bool LessThan(const vector<FieldValue>& s1, const vector<FieldValue>& s2) {
+ if (s1.size() != s2.size()) {
+ return s1.size() < s2.size();
+ }
+
+ size_t count = s1.size();
+ for (size_t i = 0; i < count; i++) {
+ if (s1[i] != s2[i]) {
+ return s1[i] < s2[i];
+ }
+ }
+ return false;
}
bool HashableDimensionKey::operator==(const HashableDimensionKey& that) const {
- return EqualsTo(getDimensionsValue(), that.getDimensionsValue());
+ if (mValues.size() != that.getValues().size()) {
+ return false;
+ }
+ size_t count = mValues.size();
+ for (size_t i = 0; i < count; i++) {
+ if (mValues[i] != (that.getValues())[i]) {
+ return false;
+ }
+ }
+ return true;
};
bool HashableDimensionKey::operator<(const HashableDimensionKey& that) const {
- return LessThan(getDimensionsValue(), that.getDimensionsValue());
+ return LessThan(getValues(), that.getValues());
};
-string MetricDimensionKey::toString() const {
- string flattened = mDimensionKeyInWhat.toString();
- flattened += mDimensionKeyInCondition.toString();
- return flattened;
+bool HashableDimensionKey::contains(const HashableDimensionKey& that) const {
+ if (mValues.size() < that.getValues().size()) {
+ return false;
+ }
+
+ if (mValues.size() == that.getValues().size()) {
+ return (*this) == that;
+ }
+
+ for (const auto& value : that.getValues()) {
+ bool found = false;
+ for (const auto& myValue : mValues) {
+ if (value.mField == myValue.mField && value.mValue == myValue.mValue) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+string HashableDimensionKey::toString() const {
+ std::string output;
+ for (const auto& value : mValues) {
+ output += StringPrintf("(%d)%#x->%s ", value.mField.getTag(), value.mField.getField(),
+ value.mValue.toString().c_str());
+ }
+ return output;
}
bool MetricDimensionKey::operator==(const MetricDimensionKey& that) const {
return mDimensionKeyInWhat == that.getDimensionKeyInWhat() &&
- mDimensionKeyInCondition == that.getDimensionKeyInCondition();
+ mDimensionKeyInCondition == that.getDimensionKeyInCondition();
};
+string MetricDimensionKey::toString() const {
+ return mDimensionKeyInWhat.toString() + mDimensionKeyInCondition.toString();
+}
+
bool MetricDimensionKey::operator<(const MetricDimensionKey& that) const {
- return toString().compare(that.toString()) < 0;
-};
+ if (mDimensionKeyInWhat < that.getDimensionKeyInWhat()) {
+ return true;
+ } else if (that.getDimensionKeyInWhat() < mDimensionKeyInWhat) {
+ return false;
+ }
-bool compareDimensionsValue(const DimensionsValue& s1, const DimensionsValue& s2) {
- return EqualsTo(s1, s2);
+ return mDimensionKeyInCondition < that.getDimensionKeyInCondition();
}
+
} // namespace statsd
} // namespace os
} // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/src/HashableDimensionKey.h b/cmds/statsd/src/HashableDimensionKey.h
index a31d7a6..89fe317 100644
--- a/cmds/statsd/src/HashableDimensionKey.h
+++ b/cmds/statsd/src/HashableDimensionKey.h
@@ -17,44 +17,66 @@
#pragma once
#include <utils/JenkinsHash.h>
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
+#include <vector>
+#include "FieldValue.h"
+#include "android-base/stringprintf.h"
+#include "logd/LogEvent.h"
namespace android {
namespace os {
namespace statsd {
+using android::base::StringPrintf;
+
+struct Metric2Condition {
+ int64_t conditionId;
+ std::vector<Matcher> metricFields;
+ std::vector<Matcher> conditionFields;
+};
+
class HashableDimensionKey {
public:
- explicit HashableDimensionKey(const DimensionsValue& dimensionsValue)
- : mDimensionsValue(dimensionsValue){};
+ explicit HashableDimensionKey(const std::vector<FieldValue>& values) {
+ mValues = values;
+ }
HashableDimensionKey(){};
- HashableDimensionKey(const HashableDimensionKey& that)
- : mDimensionsValue(that.getDimensionsValue()){};
+ HashableDimensionKey(const HashableDimensionKey& that) : mValues(that.getValues()){};
- HashableDimensionKey& operator=(const HashableDimensionKey& from) = default;
+ inline void addValue(const FieldValue& value) {
+ mValues.push_back(value);
+ }
+
+ inline const std::vector<FieldValue>& getValues() const {
+ return mValues;
+ }
+
+ inline std::vector<FieldValue>* mutableValues() {
+ return &mValues;
+ }
+
+ inline FieldValue* mutableValue(size_t i) {
+ if (i >= 0 && i < mValues.size()) {
+ return &(mValues[i]);
+ }
+ return nullptr;
+ }
std::string toString() const;
- inline const DimensionsValue& getDimensionsValue() const {
- return mDimensionsValue;
- }
-
- inline DimensionsValue* getMutableDimensionsValue() {
- return &mDimensionsValue;
+ inline const char* c_str() const {
+ return toString().c_str();
}
bool operator==(const HashableDimensionKey& that) const;
bool operator<(const HashableDimensionKey& that) const;
- inline const char* c_str() const {
- return toString().c_str();
- }
+ bool contains(const HashableDimensionKey& that) const;
private:
- DimensionsValue mDimensionsValue;
+ std::vector<FieldValue> mValues;
};
class MetricDimensionKey {
@@ -83,7 +105,7 @@
}
bool hasDimensionKeyInCondition() const {
- return mDimensionKeyInCondition.getDimensionsValue().has_field();
+ return mDimensionKeyInCondition.getValues().size() > 0;
}
bool operator==(const MetricDimensionKey& that) const;
@@ -98,11 +120,32 @@
HashableDimensionKey mDimensionKeyInCondition;
};
-bool compareDimensionsValue(const DimensionsValue& s1, const DimensionsValue& s2);
+android::hash_t hashDimension(const HashableDimensionKey& key);
-android::hash_t hashDimensionsValue(int64_t seed, const DimensionsValue& value);
-android::hash_t hashDimensionsValue(const DimensionsValue& value);
-android::hash_t hashMetricDimensionKey(int64_t see, const MetricDimensionKey& dimensionKey);
+/**
+ * Creating HashableDimensionKeys from FieldValues using matcher.
+ *
+ * This function may make modifications to the Field if the matcher has Position=LAST or ANY in
+ * it. This is because: for example, when we create dimension from last uid in attribution chain,
+ * In one event, uid 1000 is at position 5 and it's the last
+ * In another event, uid 1000 is at position 6, and it's the last
+ * these 2 events should be mapped to the same dimension. So we will remove the original position
+ * from the dimension key for the uid field (by applying 0x80 bit mask).
+ */
+bool filterValues(const std::vector<Matcher>& matcherFields, const std::vector<FieldValue>& values,
+ std::vector<HashableDimensionKey>* output);
+
+/**
+ * Filter the values from FieldValues using the matchers.
+ *
+ * In contrast to the above function, this function will not do any modification to the original
+ * data. Considering it as taking a snapshot on the atom event.
+ */
+void filterGaugeValues(const std::vector<Matcher>& matchers, const std::vector<FieldValue>& values,
+ std::vector<FieldValue>* output);
+
+void getDimensionForCondition(const LogEvent& event, Metric2Condition links,
+ std::vector<HashableDimensionKey>* conditionDimension);
} // namespace statsd
} // namespace os
@@ -116,17 +159,15 @@
template <>
struct hash<HashableDimensionKey> {
std::size_t operator()(const HashableDimensionKey& key) const {
- return hashDimensionsValue(key.getDimensionsValue());
+ return hashDimension(key);
}
};
template <>
struct hash<MetricDimensionKey> {
std::size_t operator()(const MetricDimensionKey& key) const {
- android::hash_t hash = hashDimensionsValue(
- key.getDimensionKeyInWhat().getDimensionsValue());
- hash = android::JenkinsHashMix(hash,
- hashDimensionsValue(key.getDimensionKeyInCondition().getDimensionsValue()));
+ android::hash_t hash = hashDimension(key.getDimensionKeyInWhat());
+ hash = android::JenkinsHashMix(hash, hashDimension(key.getDimensionKeyInCondition()));
return android::JenkinsHashWhiten(hash);
}
};
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 7662c40..87dec5d 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -14,19 +14,18 @@
* limitations under the License.
*/
-#define DEBUG false // STOPSHIP if true
+#define DEBUG true // STOPSHIP if true
#include "Log.h"
#include "statslog.h"
#include <android-base/file.h>
#include <dirent.h>
#include "StatsLogProcessor.h"
+#include "stats_log_util.h"
#include "android-base/stringprintf.h"
#include "guardrail/StatsdStats.h"
#include "metrics/CountMetricProducer.h"
#include "external/StatsPullerManager.h"
-#include "dimension.h"
-#include "field_util.h"
#include "stats_util.h"
#include "storage/StorageManager.h"
@@ -59,10 +58,10 @@
const int FIELD_ID_UID = 1;
const int FIELD_ID_ID = 2;
// for ConfigMetricsReport
-const int FIELD_ID_METRICS = 1;
+// const int FIELD_ID_METRICS = 1; // written in MetricsManager.cpp
const int FIELD_ID_UID_MAP = 2;
-const int FIELD_ID_LAST_REPORT_NANOS = 3;
-const int FIELD_ID_CURRENT_REPORT_NANOS = 4;
+const int FIELD_ID_LAST_REPORT_ELAPSED_NANOS = 3;
+const int FIELD_ID_CURRENT_REPORT_ELAPSED_NANOS = 4;
#define STATS_DATA_DIR "/data/misc/stats-data"
@@ -74,9 +73,6 @@
mAnomalyMonitor(anomalyMonitor),
mSendBroadcast(sendBroadcast),
mTimeBaseSec(timeBaseSec) {
- // On each initialization of StatsLogProcessor, check stats-data directory to see if there is
- // any left over data to be read.
- StorageManager::sendBroadcast(STATS_DATA_DIR, mSendBroadcast);
StatsPullerManager statsPullerManager;
statsPullerManager.SetTimeBaseSec(mTimeBaseSec);
}
@@ -93,27 +89,31 @@
}
}
+void updateUid(Value* value, int hostUid) {
+ int uid = value->int_value;
+ if (uid != hostUid) {
+ value->setInt(hostUid);
+ }
+}
+
void StatsLogProcessor::mapIsolatedUidToHostUidIfNecessaryLocked(LogEvent* event) const {
- std::set<Field, FieldCmp> uidFields;
if (android::util::kAtomsWithAttributionChain.find(event->GetTagId()) !=
android::util::kAtomsWithAttributionChain.end()) {
- FieldMatcher matcher;
- buildAttributionUidFieldMatcher(event->GetTagId(), Position::ANY, &matcher);
- findFields(event->getFieldValueMap(), matcher, &uidFields);
- } else if (android::util::kAtomsWithUidField.find(event->GetTagId()) !=
- android::util::kAtomsWithUidField.end()) {
- FieldMatcher matcher;
- buildSimpleAtomFieldMatcher(
- event->GetTagId(), 1 /* uid is always the 1st field. */, &matcher);
- findFields(event->getFieldValueMap(), matcher, &uidFields);
- }
-
- for (const auto& uidField : uidFields) {
- DimensionsValue* value = event->findFieldValueOrNull(uidField);
- if (value != nullptr && value->value_case() == DimensionsValue::ValueCase::kValueInt) {
- const int uid = mUidMap->getHostUidOrSelf(value->value_int());
- value->set_value_int(uid);
+ for (auto& value : *(event->getMutableValues())) {
+ if (value.mField.getPosAtDepth(0) > kAttributionField) {
+ break;
+ }
+ if (isAttributionUidField(value)) {
+ const int hostUid = mUidMap->getHostUidOrSelf(value.mValue.int_value);
+ updateUid(&value.mValue, hostUid);
+ }
}
+ } else if (android::util::kAtomsWithUidField.find(event->GetTagId()) !=
+ android::util::kAtomsWithUidField.end() &&
+ event->getValues().size() > 0 && (event->getValues())[0].mValue.getType() == INT) {
+ Value& value = (*event->getMutableValues())[0].mValue;
+ const int hostUid = mUidMap->getHostUidOrSelf(value.int_value);
+ updateUid(&value, hostUid);
}
}
@@ -137,7 +137,7 @@
void StatsLogProcessor::OnLogEvent(LogEvent* event) {
std::lock_guard<std::mutex> lock(mMetricsMutex);
StatsdStats::getInstance().noteAtomLogged(
- event->GetTagId(), event->GetTimestampNs() / NS_PER_SEC);
+ event->GetTagId(), event->GetElapsedTimestampNs() / NS_PER_SEC);
// Hard-coded logic to update the isolated uid's in the uid-map.
// The field numbers need to be currently updated by hand with atoms.proto
@@ -149,10 +149,10 @@
return;
}
- long curTime = time(nullptr);
- if (curTime - mLastPullerCacheClearTimeSec > StatsdStats::kPullerCacheClearIntervalSec) {
- mStatsPullerManager.ClearPullerCacheIfNecessary(curTime);
- mLastPullerCacheClearTimeSec = curTime;
+ uint64_t curTimeSec = getElapsedRealtimeSec();
+ if (curTimeSec - mLastPullerCacheClearTimeSec > StatsdStats::kPullerCacheClearIntervalSec) {
+ mStatsPullerManager.ClearPullerCacheIfNecessary(curTimeSec);
+ mLastPullerCacheClearTimeSec = curTimeSec;
}
if (event->GetTagId() != android::util::ISOLATED_UID_CHANGED) {
@@ -163,7 +163,7 @@
// pass the event to metrics managers.
for (auto& pair : mMetricsManagers) {
pair.second->onLogEvent(*event);
- flushIfNecessaryLocked(event->GetTimestampNs(), pair.first, *(pair.second));
+ flushIfNecessaryLocked(event->GetElapsedTimestampNs(), pair.first, *(pair.second));
}
}
@@ -212,27 +212,14 @@
}
}
-void StatsLogProcessor::onDumpReport(const ConfigKey& key, const uint64_t& dumpTimeStampNs,
- ConfigMetricsReportList* report) {
+void StatsLogProcessor::onDumpReport(const ConfigKey& key, const uint64_t dumpTimeStampNs,
+ vector<uint8_t>* outData) {
std::lock_guard<std::mutex> lock(mMetricsMutex);
- auto it = mMetricsManagers.find(key);
- if (it == mMetricsManagers.end()) {
- ALOGW("Config source %s does not exist", key.ToString().c_str());
- return;
- }
- report->mutable_config_key()->set_uid(key.GetUid());
- report->mutable_config_key()->set_id(key.GetId());
- ConfigMetricsReport* configMetricsReport = report->add_reports();
- it->second->onDumpReport(dumpTimeStampNs, configMetricsReport);
- // TODO: dump uid mapping.
+ onDumpReportLocked(key, dumpTimeStampNs, outData);
}
-void StatsLogProcessor::onDumpReport(const ConfigKey& key, vector<uint8_t>* outData) {
- std::lock_guard<std::mutex> lock(mMetricsMutex);
- onDumpReportLocked(key, outData);
-}
-
-void StatsLogProcessor::onDumpReportLocked(const ConfigKey& key, vector<uint8_t>* outData) {
+void StatsLogProcessor::onDumpReportLocked(const ConfigKey& key, const uint64_t dumpTimeStampNs,
+ vector<uint8_t>* outData) {
auto it = mMetricsManagers.find(key);
if (it == mMetricsManagers.end()) {
ALOGW("Config source %s does not exist", key.ToString().c_str());
@@ -256,9 +243,10 @@
long long reportsToken =
proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS);
+ int64_t lastReportTimeNs = it->second->getLastReportTimeNs();
// First, fill in ConfigMetricsReport using current data on memory, which
// starts from filling in StatsLogReport's.
- it->second->onDumpReport(&proto);
+ it->second->onDumpReport(dumpTimeStampNs, &proto);
// Fill in UidMap.
auto uidMap = mUidMap->getOutput(key);
@@ -268,10 +256,10 @@
proto.write(FIELD_TYPE_MESSAGE | FIELD_ID_UID_MAP, uidMapBuffer, uidMapSize);
// Fill in the timestamps.
- proto.write(FIELD_TYPE_INT64 | FIELD_ID_LAST_REPORT_NANOS,
- (long long)it->second->getLastReportTimeNs());
- proto.write(FIELD_TYPE_INT64 | FIELD_ID_CURRENT_REPORT_NANOS,
- (long long)::android::elapsedRealtimeNano());
+ proto.write(FIELD_TYPE_INT64 | FIELD_ID_LAST_REPORT_ELAPSED_NANOS,
+ (long long)lastReportTimeNs);
+ proto.write(FIELD_TYPE_INT64 | FIELD_ID_CURRENT_REPORT_ELAPSED_NANOS,
+ (long long)dumpTimeStampNs);
// End of ConfigMetricsReport (reports).
proto.end(reportsToken);
@@ -292,6 +280,7 @@
iter.rp()->move(toRead);
}
}
+
StatsdStats::getInstance().noteMetricsReportSent(key);
}
@@ -327,7 +316,7 @@
StatsdStats::kMaxMetricsBytesPerConfig) { // Too late. We need to start clearing data.
// TODO(b/70571383): By 12/15/2017 add API to drop data directly
ProtoOutputStream proto;
- metricsManager.onDumpReport(&proto);
+ metricsManager.onDumpReport(time(nullptr) * NS_PER_SEC, &proto);
StatsdStats::getInstance().noteDataDropped(key);
VLOG("StatsD had to toss out metrics for %s", key.ToString().c_str());
} else if (totalBytes > .9 * StatsdStats::kMaxMetricsBytesPerConfig) {
@@ -351,10 +340,10 @@
for (auto& pair : mMetricsManagers) {
const ConfigKey& key = pair.first;
vector<uint8_t> data;
- onDumpReportLocked(key, &data);
+ onDumpReportLocked(key, time(nullptr) * NS_PER_SEC, &data);
// TODO: Add a guardrail to prevent accumulation of file on disk.
- string file_name = StringPrintf("%s/%ld_%d_%lld", STATS_DATA_DIR, time(nullptr),
- key.GetUid(), (long long)key.GetId());
+ string file_name = StringPrintf("%s/%ld_%d_%lld", STATS_DATA_DIR,
+ (long)getWallClockSec(), key.GetUid(), (long long)key.GetId());
StorageManager::writeFile(file_name.c_str(), &data[0], data.size());
}
}
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 8bbcd75..1444306 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -46,9 +46,7 @@
size_t GetMetricsSize(const ConfigKey& key) const;
- void onDumpReport(const ConfigKey& key, vector<uint8_t>* outData);
- void onDumpReport(const ConfigKey& key, const uint64_t& dumpTimeStampNs,
- ConfigMetricsReportList* report);
+ void onDumpReport(const ConfigKey& key, const uint64_t dumpTimeNs, vector<uint8_t>* outData);
/* Tells MetricsManager that the alarms in anomalySet have fired. Modifies anomalySet. */
void onAnomalyAlarmFired(
@@ -80,7 +78,8 @@
sp<AnomalyMonitor> mAnomalyMonitor;
- void onDumpReportLocked(const ConfigKey& key, vector<uint8_t>* outData);
+ void onDumpReportLocked(const ConfigKey& key, const uint64_t dumpTimeNs,
+ vector<uint8_t>* outData);
/* Check if we should send a broadcast if approaching memory limits and if we're over, we
* actually delete the data. */
@@ -105,9 +104,14 @@
FRIEND_TEST(StatsLogProcessorTest, TestRateLimitBroadcast);
FRIEND_TEST(StatsLogProcessorTest, TestDropWhenByteSizeTooLarge);
FRIEND_TEST(StatsLogProcessorTest, TestDropWhenByteSizeTooLarge);
- FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration);
- FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration);
- FRIEND_TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks);
+ FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration1);
+ FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration2);
+ FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration3);
+ FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration1);
+ FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration2);
+ FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration3);
+ FRIEND_TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks1);
+ FRIEND_TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks2);
FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSlice);
FRIEND_TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent);
FRIEND_TEST(DimensionInConditionE2eTest, TestCountMetricNoLink);
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index c24efec..791fb14 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -18,6 +18,7 @@
#include "Log.h"
#include "StatsService.h"
+#include "stats_log_util.h"
#include "android-base/stringprintf.h"
#include "config/ConfigKey.h"
#include "config/ConfigManager.h"
@@ -79,18 +80,20 @@
mUidMap = new UidMap();
StatsPuller::SetUidMap(mUidMap);
mConfigManager = new ConfigManager();
- mProcessor = new StatsLogProcessor(mUidMap, mAnomalyMonitor, time(nullptr), [this](const ConfigKey& key) {
- sp<IStatsCompanionService> sc = getStatsCompanionService();
- auto receiver = mConfigManager->GetConfigReceiver(key);
- if (sc == nullptr) {
- VLOG("Could not find StatsCompanionService");
- } else if (receiver == nullptr) {
- VLOG("Statscompanion could not find a broadcast receiver for %s",
- key.ToString().c_str());
- } else {
- sc->sendDataBroadcast(receiver);
+ mProcessor = new StatsLogProcessor(mUidMap, mAnomalyMonitor, getElapsedRealtimeSec(),
+ [this](const ConfigKey& key) {
+ sp<IStatsCompanionService> sc = getStatsCompanionService();
+ auto receiver = mConfigManager->GetConfigReceiver(key);
+ if (sc == nullptr) {
+ VLOG("Could not find StatsCompanionService");
+ } else if (receiver == nullptr) {
+ VLOG("Statscompanion could not find a broadcast receiver for %s",
+ key.ToString().c_str());
+ } else {
+ sc->sendDataBroadcast(receiver);
+ }
}
- });
+ );
mConfigManager->AddListener(mProcessor);
@@ -121,8 +124,6 @@
*/
status_t StatsService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
uint32_t flags) {
- status_t err;
-
switch (code) {
case SHELL_COMMAND_TRANSACTION: {
int in = data.readFileDescriptor();
@@ -237,8 +238,8 @@
return cmd_write_data_to_disk(out);
}
- if (!args[0].compare(String8("log-app-hook"))) {
- return cmd_log_app_hook(out, args);
+ if (!args[0].compare(String8("log-app-breadcrumb"))) {
+ return cmd_log_app_breadcrumb(out, args);
}
if (!args[0].compare(String8("clear-puller-cache"))) {
@@ -281,8 +282,8 @@
fprintf(out, " Flushes all data on memory to disk.\n");
fprintf(out, "\n");
fprintf(out, "\n");
- fprintf(out, "usage: adb shell cmd stats log-app-hook [UID] LABEL STATE\n");
- fprintf(out, " Writes an AppHook event to the statslog buffer.\n");
+ fprintf(out, "usage: adb shell cmd stats log-app-breadcrumb [UID] LABEL STATE\n");
+ fprintf(out, " Writes an AppBreadcrumbReported event to the statslog buffer.\n");
fprintf(out, " UID The uid to use. It is only possible to pass a UID\n");
fprintf(out, " parameter on eng builds. If UID is omitted the calling\n");
fprintf(out, " uid is used.\n");
@@ -492,7 +493,8 @@
}
if (good) {
vector<uint8_t> data;
- mProcessor->onDumpReport(ConfigKey(uid, StrToInt64(name)), &data);
+ mProcessor->onDumpReport(ConfigKey(uid, StrToInt64(name)), time(nullptr) * NS_PER_SEC,
+ &data);
// TODO: print the returned StatsLogReport to file instead of printing to logcat.
if (proto) {
for (size_t i = 0; i < data.size(); i ++) {
@@ -547,7 +549,7 @@
return NO_ERROR;
}
-status_t StatsService::cmd_log_app_hook(FILE* out, const Vector<String8>& args) {
+status_t StatsService::cmd_log_app_breadcrumb(FILE* out, const Vector<String8>& args) {
bool good = false;
int32_t uid;
int32_t label;
@@ -569,13 +571,13 @@
good = true;
} else {
fprintf(out,
- "Selecting a UID for writing AppHook can only be dumped for other UIDs on eng"
- " or userdebug builds.\n");
+ "Selecting a UID for writing AppBreadcrumb can only be done for other UIDs "
+ "on eng or userdebug builds.\n");
}
}
if (good) {
- fprintf(out, "Logging AppHook(%d, %d, %d) to statslog.\n", uid, label, state);
- android::util::stats_write(android::util::APP_HOOK, uid, label, state);
+ fprintf(out, "Logging AppBreadcrumbReported(%d, %d, %d) to statslog.\n", uid, label, state);
+ android::util::stats_write(android::util::APP_BREADCRUMB_REPORTED, uid, label, state);
} else {
print_cmd_help(out);
return UNKNOWN_ERROR;
@@ -667,12 +669,15 @@
return Status::fromExceptionCode(Status::EX_SECURITY,
"Only system uid can call informAnomalyAlarmFired");
}
-
- VLOG("StatsService::informAnomalyAlarmFired succeeded");
- uint64_t currentTimeSec = time(nullptr);
+ uint64_t currentTimeSec = getElapsedRealtimeSec();
std::unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> anomalySet =
mAnomalyMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
- mProcessor->onAnomalyAlarmFired(currentTimeSec * NS_PER_SEC, anomalySet);
+ if (anomalySet.size() > 0) {
+ VLOG("Found an anomaly alarm that fired.");
+ mProcessor->onAnomalyAlarmFired(currentTimeSec * NS_PER_SEC, anomalySet);
+ } else {
+ VLOG("Cannot find an anomaly alarm that fired. Perhaps it was recently cancelled.");
+ }
return Status::ok();
}
@@ -780,7 +785,7 @@
VLOG("StatsService::getData with Pid %i, Uid %i", ipc->getCallingPid(), ipc->getCallingUid());
if (checkCallingPermission(String16(kPermissionDump))) {
ConfigKey configKey(ipc->getCallingUid(), key);
- mProcessor->onDumpReport(configKey, output);
+ mProcessor->onDumpReport(configKey, time(nullptr) * NS_PER_SEC, output);
return Status::ok();
} else {
return Status::fromExceptionCode(binder::Status::EX_SECURITY);
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 3dc19fe..9690de7 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -193,9 +193,10 @@
status_t cmd_write_data_to_disk(FILE* out);
/**
- * Write an AppHook event to the StatsLog buffer, as though StatsLog.write(APP_HOOK).
+ * Write an AppBreadcrumbReported event to the StatsLog buffer, as if calling
+ * StatsLog.write(APP_BREADCRUMB_REPORTED).
*/
- status_t cmd_log_app_hook(FILE* out, const Vector<String8>& args);
+ status_t cmd_log_app_breadcrumb(FILE* out, const Vector<String8>& args);
/**
* Print contents of a pulled metrics source.
diff --git a/cmds/statsd/src/anomaly/AnomalyMonitor.cpp b/cmds/statsd/src/anomaly/AnomalyMonitor.cpp
index 72d29d0..ca34dc6 100644
--- a/cmds/statsd/src/anomaly/AnomalyMonitor.cpp
+++ b/cmds/statsd/src/anomaly/AnomalyMonitor.cpp
@@ -96,7 +96,7 @@
std::lock_guard<std::mutex> lock(mLock);
for (sp<const AnomalyAlarm> t = mPq.top(); t != nullptr && t->timestampSec <= timestampSec;
- t = mPq.top()) {
+ t = mPq.top()) {
oldAlarms.insert(t);
mPq.pop(); // remove t
}
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.cpp b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
index ba16ec83..443d33d 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
@@ -92,6 +92,9 @@
void AnomalyTracker::addPastBucket(const MetricDimensionKey& key, const int64_t& bucketValue,
const int64_t& bucketNum) {
+ if (mNumOfPastBuckets == 0) {
+ return;
+ }
flushPastBuckets(bucketNum);
auto& bucket = mPastBuckets[index(bucketNum)];
@@ -106,6 +109,9 @@
void AnomalyTracker::addPastBucket(std::shared_ptr<DimToValMap> bucketValues,
const int64_t& bucketNum) {
VLOG("addPastBucket() called.");
+ if (mNumOfPastBuckets == 0) {
+ return;
+ }
flushPastBuckets(bucketNum);
// Replace the oldest bucket with the new bucket we are adding.
mPastBuckets[index(bucketNum)] = bucketValues;
diff --git a/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp b/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
index fa0bc0c..3ba943c 100644
--- a/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
@@ -53,10 +53,11 @@
void DurationAnomalyTracker::startAlarm(const MetricDimensionKey& dimensionKey,
const uint64_t& timestampNs) {
- uint32_t timestampSec = static_cast<uint32_t>(timestampNs / NS_PER_SEC);
+ // Alarms are stored in secs. Must round up, since if it fires early, it is ignored completely.
+ uint32_t timestampSec = static_cast<uint32_t>((timestampNs -1)/ NS_PER_SEC) + 1; // round up
if (isInRefractoryPeriod(timestampNs, dimensionKey)) {
- VLOG("Skipping setting anomaly alarm since it'd fall in the refractory period");
- return;
+ VLOG("Setting a delayed anomaly alarm lest it fall in the refractory period");
+ timestampSec = getRefractoryPeriodEndsSec(dimensionKey) + 1;
}
sp<const AnomalyAlarm> alarm = new AnomalyAlarm{timestampSec};
mAlarms.insert({dimensionKey, alarm});
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 4c6a36b..85e209b 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -85,7 +85,7 @@
PacketWakeupOccurred packet_wakeup_occurred = 44;
DropboxErrorChanged dropbox_error_changed = 45;
AnomalyDetected anomaly_detected = 46;
- AppHook app_hook = 47;
+ AppBreadcrumbReported app_breadcrumb_reported = 47;
AppStartChanged app_start_changed = 48;
AppStartCancelChanged app_start_cancel_changed = 49;
AppStartFullyDrawnChanged app_start_fully_drawn_changed = 50;
@@ -202,9 +202,10 @@
* frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
*/
message ProcessLifeCycleStateChanged {
- optional int32 uid = 1; // TODO: should be a string tagged w/ uid annotation
+ // TODO: should be a string tagged w/ uid annotation
+ optional int32 uid = 1;
- // TODO: What is this?
+ // The process name (usually same as the app name).
optional string name = 2;
// What lifecycle state the process changed to.
@@ -312,7 +313,7 @@
message SyncStateChanged {
repeated AttributionNode attribution_node = 1;
- // Name of the sync (as named in the app)
+ // Name of the sync (as named in the app). Can be chosen at run-time.
optional string name = 2;
enum State {
@@ -615,7 +616,7 @@
optional string wakeup_reason_name = 1;
// Duration (in microseconds) for the wake-up interrupt to be serviced.
- optional int64 duration_usec = 2;
+ optional int64 duration_micros = 2;
}
/**
@@ -692,10 +693,10 @@
// Beginning of shutdown time in ms using wall clock time since unix epoch.
// Default: 0 if no start time received.
- optional int64 start_time_ms = 3;
+ optional int64 start_time_millis = 3;
// Duration of shutdown in ms. Default: 0 if no duration received.
- optional int64 duration_ms = 4;
+ optional int64 duration_millis = 4;
}
@@ -715,13 +716,13 @@
optional string system_reason = 2;
// End of boot time in ms from unix epoch using system wall clock.
- optional int64 end_time_ms = 3;
+ optional int64 end_time_millis = 3;
// Total boot duration in ms.
- optional int64 total_duration_ms = 4;
+ optional int64 total_duration_millis = 4;
// Bootloader duration in ms.
- optional int64 bootloader_duration_ms = 5;
+ optional int64 bootloader_duration_millis = 5;
// Time since last boot in ms. Default: 0 if not available.
optional int64 time_since_last_boot = 6;
@@ -762,7 +763,7 @@
*/
message DaveyOccurred {
// Amount of time it took to render the frame. Should be >=700ms.
- optional int64 jank_duration_ms = 1;
+ optional int64 jank_duration_millis = 1;
}
/**
@@ -863,7 +864,7 @@
* Logged from:
* frameworks/base/core/java/android/util/StatsLog.java
*/
-message AppHook {
+message AppBreadcrumbReported {
// The uid of the application that sent this custom atom.
optional int32 uid = 1;
@@ -924,16 +925,16 @@
optional bool is_instant_app = 6;
// Device uptime when activity started.
- optional int64 activity_start_msec = 7;
+ optional int64 activity_start_millis = 7;
optional android.app.AppTransitionReasonEnum reason = 8;
- optional int32 transition_delay_msec = 9;
+ optional int32 transition_delay_millis = 9;
// -1 if not set.
- optional int32 starting_window_delay_msec = 10;
+ optional int32 starting_window_delay_millis = 10;
// -1 if not set.
- optional int32 bind_application_delay_msec = 11;
- optional int32 windows_drawn_delay_msec = 12;
+ optional int32 bind_application_delay_millis = 11;
+ optional int32 windows_drawn_delay_millis = 12;
// Empty if not set.
optional string launch_token = 13;
@@ -981,7 +982,7 @@
optional bool transition_process_running = 5;
// App startup time (until call to Activity#reportFullyDrawn()).
- optional int64 app_startup_time_ms = 6;
+ optional int64 app_startup_time_millis = 6;
}
/**
@@ -1303,7 +1304,7 @@
// The number of times it entered, or voted for entering the sleep state
optional uint64 count = 3;
// The length of time spent in, or spent voting for, the sleep state
- optional uint64 timeMs = 4;
+ optional uint64 time_millis = 4;
}
/**
@@ -1316,7 +1317,7 @@
message CpuTimePerFreq {
optional uint32 cluster = 1;
optional uint32 freq_index = 2;
- optional uint64 time_ms = 3;
+ optional uint64 time_millis = 3;
}
/**
@@ -1325,8 +1326,8 @@
*/
message CpuTimePerUid {
optional uint64 uid = 1;
- optional uint64 user_time_ms = 2;
- optional uint64 sys_time_ms = 3;
+ optional uint64 user_time_millis = 2;
+ optional uint64 sys_time_millis = 3;
}
/**
@@ -1337,7 +1338,7 @@
message CpuTimePerUidFreq {
optional uint64 uid = 1;
optional uint64 freq_idx = 2;
- optional uint64 time_ms = 3;
+ optional uint64 time_millis = 3;
}
/**
@@ -1345,16 +1346,16 @@
*/
message WifiActivityEnergyInfo {
// timestamp(wall clock) of record creation
- optional uint64 timestamp_ms = 1;
+ optional uint64 timestamp_millis = 1;
// stack reported state
// TODO: replace this with proto enum
optional int32 stack_state = 2;
// tx time in ms
- optional uint64 controller_tx_time_ms = 3;
+ optional uint64 controller_tx_time_millis = 3;
// rx time in ms
- optional uint64 controller_rx_time_ms = 4;
+ optional uint64 controller_rx_time_millis = 4;
// idle time in ms
- optional uint64 controller_idle_time_ms = 5;
+ optional uint64 controller_idle_time_millis = 5;
// product of current(mA), voltage(V) and time(ms)
optional uint64 controller_energy_used = 6;
}
@@ -1364,11 +1365,11 @@
*/
message ModemActivityInfo {
// timestamp(wall clock) of record creation
- optional uint64 timestamp_ms = 1;
+ optional uint64 timestamp_millis = 1;
// sleep time in ms.
- optional uint64 sleep_time_ms = 2;
+ optional uint64 sleep_time_millis = 2;
// idle time in ms
- optional uint64 controller_idle_time_ms = 3;
+ optional uint64 controller_idle_time_millis = 3;
/**
* Tx power index
* index 0 = tx_power < 0dBm
@@ -1378,17 +1379,17 @@
* index 4 = tx_power > 20dBm
*/
// tx time in ms at power level 0
- optional uint64 controller_tx_time_pl0_ms = 4;
+ optional uint64 controller_tx_time_pl0_millis = 4;
// tx time in ms at power level 1
- optional uint64 controller_tx_time_pl1_ms = 5;
+ optional uint64 controller_tx_time_pl1_millis = 5;
// tx time in ms at power level 2
- optional uint64 controller_tx_time_pl2_ms = 6;
+ optional uint64 controller_tx_time_pl2_millis = 6;
// tx time in ms at power level 3
- optional uint64 controller_tx_time_pl3_ms = 7;
+ optional uint64 controller_tx_time_pl3_millis = 7;
// tx time in ms at power level 4
- optional uint64 controller_tx_time_pl4_ms = 8;
+ optional uint64 controller_tx_time_pl4_millis = 8;
// rx time in ms at power level 5
- optional uint64 controller_rx_time_ms = 9;
+ optional uint64 controller_rx_time_millis = 9;
// product of current(mA), voltage(V) and time(ms)
optional uint64 energy_used = 10;
}
@@ -1399,15 +1400,15 @@
*/
message BluetoothActivityInfo {
// timestamp(wall clock) of record creation
- optional uint64 timestamp_ms = 1;
+ optional uint64 timestamp_millis = 1;
// bluetooth stack state
optional int32 bluetooth_stack_state = 2;
// tx time in ms
- optional uint64 controller_tx_time_ms = 3;
+ optional uint64 controller_tx_time_millis = 3;
// rx time in ms
- optional uint64 controller_rx_time_ms = 4;
+ optional uint64 controller_rx_time_millis = 4;
// idle time in ms
- optional uint64 controller_idle_time_ms = 5;
+ optional uint64 controller_idle_time_millis = 5;
// product of current(mA), voltage(V) and time(ms)
optional uint64 energy_used = 6;
}
@@ -1445,7 +1446,7 @@
* Elapsed real time from SystemClock.
*/
message SystemElapsedRealtime {
- optional uint64 time_ms = 1;
+ optional uint64 time_millis = 1;
}
/*
@@ -1456,7 +1457,7 @@
// This clock stops when the system enters deep sleep (CPU off, display dark, device waiting
// for external input).
// It is not affected by clock scaling, idle, or other power saving mechanisms.
- optional uint64 uptime_ms = 1;
+ optional uint64 uptime_millis = 1;
}
/*
@@ -1470,8 +1471,9 @@
*/
message CpuActiveTime {
optional uint64 uid = 1;
- optional uint64 idx = 2;
- optional uint64 time_ms = 3;
+ optional uint32 cluster_number = 2;
+ optional uint64 idx = 3;
+ optional uint64 time_millis = 4;
}
/**
@@ -1486,7 +1488,7 @@
message CpuClusterTime {
optional uint64 uid = 1;
optional uint64 idx = 2;
- optional uint64 time_ms = 3;
+ optional uint64 time_millis = 3;
}
/*
diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.cpp b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
index 4c20ccb..13a2b7b 100644
--- a/cmds/statsd/src/condition/CombinationConditionTracker.cpp
+++ b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
@@ -106,11 +106,9 @@
}
void CombinationConditionTracker::isConditionMet(
- const ConditionKey& conditionParameters,
- const vector<sp<ConditionTracker>>& allConditions,
- const FieldMatcher& dimensionFields,
- vector<ConditionState>& conditionCache,
- std::unordered_set<HashableDimensionKey> &dimensionsKeySet) const {
+ const ConditionKey& conditionParameters, const vector<sp<ConditionTracker>>& allConditions,
+ const std::vector<Matcher>& dimensionFields, vector<ConditionState>& conditionCache,
+ std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const {
// So far, this is fine as there is at most one child having sliced output.
for (const int childIndex : mChildren) {
if (conditionCache[childIndex] == ConditionState::kNotEvaluated) {
@@ -169,8 +167,8 @@
ConditionState CombinationConditionTracker::getMetConditionDimension(
const std::vector<sp<ConditionTracker>>& allConditions,
- const FieldMatcher& dimensionFields,
- std::unordered_set<HashableDimensionKey> &dimensionsKeySet) const {
+ const std::vector<Matcher>& dimensionFields,
+ std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const {
vector<ConditionState> conditionCache(allConditions.size(), ConditionState::kNotEvaluated);
// So far, this is fine as there is at most one child having sliced output.
for (const int childIndex : mChildren) {
diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.h b/cmds/statsd/src/condition/CombinationConditionTracker.h
index 0b7f949..ba185f6 100644
--- a/cmds/statsd/src/condition/CombinationConditionTracker.h
+++ b/cmds/statsd/src/condition/CombinationConditionTracker.h
@@ -41,17 +41,17 @@
std::vector<ConditionState>& conditionCache,
std::vector<bool>& changedCache) override;
- void isConditionMet(
- const ConditionKey& conditionParameters,
- const std::vector<sp<ConditionTracker>>& allConditions,
- const FieldMatcher& dimensionFields,
- std::vector<ConditionState>& conditionCache,
- std::unordered_set<HashableDimensionKey> &dimensionsKeySet) const override;
+ void isConditionMet(const ConditionKey& conditionParameters,
+ const std::vector<sp<ConditionTracker>>& allConditions,
+ const vector<Matcher>& dimensionFields,
+ std::vector<ConditionState>& conditionCache,
+ std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const override;
ConditionState getMetConditionDimension(
const std::vector<sp<ConditionTracker>>& allConditions,
- const FieldMatcher& dimensionFields,
- std::unordered_set<HashableDimensionKey> &dimensionsKeySet) const override;
+ const vector<Matcher>& dimensionFields,
+ std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const override;
+
private:
LogicalOperation mLogicalOperation;
diff --git a/cmds/statsd/src/condition/ConditionTracker.h b/cmds/statsd/src/condition/ConditionTracker.h
index 81abbdb..2612a9a 100644
--- a/cmds/statsd/src/condition/ConditionTracker.h
+++ b/cmds/statsd/src/condition/ConditionTracker.h
@@ -90,14 +90,13 @@
virtual void isConditionMet(
const ConditionKey& conditionParameters,
const std::vector<sp<ConditionTracker>>& allConditions,
- const FieldMatcher& dimensionFields,
- std::vector<ConditionState>& conditionCache,
- std::unordered_set<HashableDimensionKey> &dimensionsKeySet) const = 0;
+ const vector<Matcher>& dimensionFields, std::vector<ConditionState>& conditionCache,
+ std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const = 0;
virtual ConditionState getMetConditionDimension(
const std::vector<sp<ConditionTracker>>& allConditions,
- const FieldMatcher& dimensionFields,
- std::unordered_set<HashableDimensionKey> &dimensionsKeySet) const = 0;
+ const vector<Matcher>& dimensionFields,
+ std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const = 0;
// return the list of LogMatchingTracker index that this ConditionTracker uses.
virtual const std::set<int>& getLogTrackerIndex() const {
diff --git a/cmds/statsd/src/condition/ConditionWizard.cpp b/cmds/statsd/src/condition/ConditionWizard.cpp
index 0427700..c8722c3 100644
--- a/cmds/statsd/src/condition/ConditionWizard.cpp
+++ b/cmds/statsd/src/condition/ConditionWizard.cpp
@@ -24,11 +24,9 @@
using std::string;
using std::vector;
-ConditionState ConditionWizard::query(
- const int index, const ConditionKey& parameters,
- const FieldMatcher& dimensionFields,
- std::unordered_set<HashableDimensionKey> *dimensionKeySet) {
-
+ConditionState ConditionWizard::query(const int index, const ConditionKey& parameters,
+ const vector<Matcher>& dimensionFields,
+ std::unordered_set<HashableDimensionKey>* dimensionKeySet) {
vector<ConditionState> cache(mAllConditions.size(), ConditionState::kNotEvaluated);
mAllConditions[index]->isConditionMet(
@@ -37,9 +35,8 @@
}
ConditionState ConditionWizard::getMetConditionDimension(
- const int index, const FieldMatcher& dimensionFields,
- std::unordered_set<HashableDimensionKey> *dimensionsKeySet) const {
-
+ const int index, const vector<Matcher>& dimensionFields,
+ std::unordered_set<HashableDimensionKey>* dimensionsKeySet) const {
return mAllConditions[index]->getMetConditionDimension(mAllConditions, dimensionFields,
*dimensionsKeySet);
}
diff --git a/cmds/statsd/src/condition/ConditionWizard.h b/cmds/statsd/src/condition/ConditionWizard.h
index b38b59f..4831d56 100644
--- a/cmds/statsd/src/condition/ConditionWizard.h
+++ b/cmds/statsd/src/condition/ConditionWizard.h
@@ -39,16 +39,13 @@
// condition.
// The ConditionTracker at [conditionIndex] can be a CombinationConditionTracker. In this case,
// the conditionParameters contains the parameters for it's children SimpleConditionTrackers.
- virtual ConditionState query(
- const int conditionIndex,
- const ConditionKey& conditionParameters,
- const FieldMatcher& dimensionFields,
- std::unordered_set<HashableDimensionKey> *dimensionKeySet);
+ virtual ConditionState query(const int conditionIndex, const ConditionKey& conditionParameters,
+ const vector<Matcher>& dimensionFields,
+ std::unordered_set<HashableDimensionKey>* dimensionKeySet);
virtual ConditionState getMetConditionDimension(
- const int index,
- const FieldMatcher& dimensionFields,
- std::unordered_set<HashableDimensionKey> *dimensionsKeySet) const;
+ const int index, const vector<Matcher>& dimensionFields,
+ std::unordered_set<HashableDimensionKey>* dimensionsKeySet) const;
private:
std::vector<sp<ConditionTracker>> mAllConditions;
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.cpp b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
index 25265d5..624119f3 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.cpp
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
@@ -19,7 +19,6 @@
#include "SimpleConditionTracker.h"
#include "guardrail/StatsdStats.h"
-#include "dimension.h"
#include <log/logprint.h>
@@ -77,10 +76,12 @@
mStopAllLogMatcherIndex = -1;
}
- mOutputDimensions = simplePredicate.dimensions();
-
- if (mOutputDimensions.child_size() > 0) {
- mSliced = true;
+ if (simplePredicate.has_dimensions()) {
+ translateFieldMatcher(simplePredicate.dimensions(), &mOutputDimensions);
+ if (mOutputDimensions.size() > 0) {
+ mSliced = true;
+ mDimensionTag = mOutputDimensions[0].mMatcher.getTag();
+ }
}
if (simplePredicate.initial_value() == SimplePredicate_InitialValue_FALSE) {
@@ -104,13 +105,10 @@
vector<bool>& stack) {
// SimpleConditionTracker does not have dependency on other conditions, thus we just return
// if the initialization was successful.
- if (mOutputDimensions.has_field() || mOutputDimensions.child_size() > 0) {
- setSliced(true);
- }
return mInitialized;
}
-void print(map<HashableDimensionKey, int>& conditions, const int64_t& id) {
+void print(const map<HashableDimensionKey, int>& conditions, const int64_t& id) {
VLOG("%lld DUMP:", (long long)id);
for (const auto& pair : conditions) {
VLOG("\t%s : %d", pair.first.c_str(), pair.second);
@@ -151,24 +149,15 @@
}
void SimpleConditionTracker::handleConditionEvent(const HashableDimensionKey& outputKey,
- bool matchStart,
- std::vector<ConditionState>& conditionCache,
- std::vector<bool>& conditionChangedCache) {
- if ((int)conditionChangedCache.size() <= mIndex) {
- ALOGE("handleConditionEvent: param conditionChangedCache not initialized.");
- return;
- }
- if ((int)conditionCache.size() <= mIndex) {
- ALOGE("handleConditionEvent: param conditionCache not initialized.");
- return;
- }
+ bool matchStart, ConditionState* conditionCache,
+ bool* conditionChangedCache) {
bool changed = false;
auto outputIt = mSlicedConditionState.find(outputKey);
ConditionState newCondition;
if (hitGuardRail(outputKey)) {
- conditionChangedCache[mIndex] = false;
+ (*conditionChangedCache) = false;
// Tells the caller it's evaluated.
- conditionCache[mIndex] = ConditionState::kUnknown;
+ (*conditionCache) = ConditionState::kUnknown;
return;
}
if (outputIt == mSlicedConditionState.end()) {
@@ -230,9 +219,8 @@
print(mSlicedConditionState, mConditionId);
}
- conditionChangedCache[mIndex] = changed;
- conditionCache[mIndex] = newCondition;
-
+ (*conditionChangedCache) = changed;
+ (*conditionCache) = newCondition;
VLOG("SimplePredicate %lld nonSlicedChange? %d", (long long)mConditionId,
conditionChangedCache[mIndex] == true);
}
@@ -292,42 +280,42 @@
return;
}
- // outputKey is the output values. e.g, uid:1234
- std::vector<DimensionsValue> outputValues;
- getDimensionKeys(event, mOutputDimensions, &outputValues);
- if (outputValues.size() == 0) {
- // The original implementation would generate an empty string dimension hash when condition
- // is not sliced.
- handleConditionEvent(
- DEFAULT_DIMENSION_KEY, matchedState == 1, conditionCache, conditionChangedCache);
- } else if (outputValues.size() == 1) {
- handleConditionEvent(HashableDimensionKey(outputValues[0]), matchedState == 1,
- conditionCache, conditionChangedCache);
+ ConditionState overallState = mInitialValue;
+ bool overallChanged = false;
+
+ if (mOutputDimensions.size() == 0) {
+ handleConditionEvent(DEFAULT_DIMENSION_KEY, matchedState == 1, &overallState,
+ &overallChanged);
} else {
+ std::vector<HashableDimensionKey> outputValues;
+ filterValues(mOutputDimensions, event.getValues(), &outputValues);
+
// If this event has multiple nodes in the attribution chain, this log event probably will
// generate multiple dimensions. If so, we will find if the condition changes for any
// dimension and ask the corresponding metric producer to verify whether the actual sliced
// condition has changed or not.
// A high level assumption is that a predicate is either sliced or unsliced. We will never
// have both sliced and unsliced version of a predicate.
- for (const DimensionsValue& outputValue : outputValues) {
- vector<ConditionState> dimensionalConditionCache(conditionCache.size(),
- ConditionState::kNotEvaluated);
- vector<bool> dimensionalConditionChangedCache(conditionChangedCache.size(), false);
- handleConditionEvent(HashableDimensionKey(outputValue), matchedState == 1,
- dimensionalConditionCache, dimensionalConditionChangedCache);
- OrConditionState(dimensionalConditionCache, &conditionCache);
- OrBooleanVector(dimensionalConditionChangedCache, &conditionChangedCache);
+ for (const HashableDimensionKey& outputValue : outputValues) {
+ // For sliced conditions, the value in the cache is not used. We don't need to update
+ // the overall condition state.
+ ConditionState tempState = ConditionState::kUnknown;
+ bool tempChanged = false;
+ handleConditionEvent(outputValue, matchedState == 1, &tempState, &tempChanged);
+ if (tempChanged) {
+ overallChanged = true;
+ }
}
}
+ conditionCache[mIndex] = overallState;
+ conditionChangedCache[mIndex] = overallChanged;
}
void SimpleConditionTracker::isConditionMet(
- const ConditionKey& conditionParameters,
- const vector<sp<ConditionTracker>>& allConditions,
- const FieldMatcher& dimensionFields,
- vector<ConditionState>& conditionCache,
- std::unordered_set<HashableDimensionKey> &dimensionsKeySet) const {
+ const ConditionKey& conditionParameters, const vector<sp<ConditionTracker>>& allConditions,
+ const vector<Matcher>& dimensionFields, vector<ConditionState>& conditionCache,
+ std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const {
+
if (conditionCache[mIndex] != ConditionState::kNotEvaluated) {
// it has been evaluated.
VLOG("Yes, already evaluated, %lld %d",
@@ -338,8 +326,7 @@
if (pair == conditionParameters.end()) {
ConditionState conditionState = ConditionState::kNotEvaluated;
- if (dimensionFields.has_field() && dimensionFields.child_size() > 0 &&
- dimensionFields.field() == mOutputDimensions.field()) {
+ if (dimensionFields.size() > 0 && dimensionFields[0].mMatcher.getTag() == mDimensionTag) {
conditionState = conditionState | getMetConditionDimension(
allConditions, dimensionFields, dimensionsKeySet);
} else {
@@ -368,12 +355,10 @@
ConditionState sliceState =
startedCountIt->second > 0 ? ConditionState::kTrue : ConditionState::kFalse;
conditionState = conditionState | sliceState;
- if (sliceState == ConditionState::kTrue && dimensionFields.has_field()) {
- HashableDimensionKey dimensionKey;
- if (getSubDimension(startedCountIt->first.getDimensionsValue(), dimensionFields,
- dimensionKey.getMutableDimensionsValue())) {
- dimensionsKeySet.insert(dimensionKey);
- }
+ if (sliceState == ConditionState::kTrue && dimensionFields.size() > 0) {
+ vector<HashableDimensionKey> dimensionKeys;
+ filterValues(dimensionFields, startedCountIt->first.getValues(), &dimensionKeys);
+ dimensionsKeySet.insert(dimensionKeys.begin(), dimensionKeys.end());
}
} else {
// For unseen key, check whether the require dimensions are subset of sliced condition
@@ -382,31 +367,29 @@
for (const auto& slice : mSlicedConditionState) {
ConditionState sliceState =
slice.second > 0 ? ConditionState::kTrue : ConditionState::kFalse;
- if (IsSubDimension(slice.first.getDimensionsValue(), key.getDimensionsValue())) {
+ if (slice.first.contains(key)) {
conditionState = conditionState | sliceState;
- if (sliceState == ConditionState::kTrue && dimensionFields.has_field()) {
- HashableDimensionKey dimensionKey;
- if (getSubDimension(slice.first.getDimensionsValue(),
- dimensionFields, dimensionKey.getMutableDimensionsValue())) {
- dimensionsKeySet.insert(dimensionKey);
- }
+ if (sliceState == ConditionState::kTrue && dimensionFields.size() > 0) {
+ vector<HashableDimensionKey> dimensionKeys;
+ filterValues(dimensionFields, slice.first.getValues(), &dimensionKeys);
+
+ dimensionsKeySet.insert(dimensionKeys.begin(), dimensionKeys.end());
+ }
}
}
}
}
- }
conditionCache[mIndex] = conditionState;
VLOG("Predicate %lld return %d", (long long)mConditionId, conditionCache[mIndex]);
}
ConditionState SimpleConditionTracker::getMetConditionDimension(
const std::vector<sp<ConditionTracker>>& allConditions,
- const FieldMatcher& dimensionFields,
- std::unordered_set<HashableDimensionKey> &dimensionsKeySet) const {
+ const vector<Matcher>& dimensionFields,
+ std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const {
ConditionState conditionState = mInitialValue;
- if (!dimensionFields.has_field() ||
- !mOutputDimensions.has_field() ||
- dimensionFields.field() != mOutputDimensions.field()) {
+ if (dimensionFields.size() == 0 || mOutputDimensions.size() == 0 ||
+ dimensionFields[0].mMatcher.getTag() != mOutputDimensions[0].mMatcher.getTag()) {
const auto& itr = mSlicedConditionState.find(DEFAULT_DIMENSION_KEY);
if (itr != mSlicedConditionState.end()) {
ConditionState sliceState =
@@ -419,13 +402,13 @@
for (const auto& slice : mSlicedConditionState) {
ConditionState sliceState =
slice.second > 0 ? ConditionState::kTrue : ConditionState::kFalse;
- DimensionsValue dimensionsValue;
conditionState = conditionState | sliceState;
- HashableDimensionKey dimensionKey;
- if (sliceState == ConditionState::kTrue &&
- getSubDimension(slice.first.getDimensionsValue(), dimensionFields,
- dimensionKey.getMutableDimensionsValue())) {
- dimensionsKeySet.insert(dimensionKey);
+
+ if (sliceState == ConditionState::kTrue && dimensionFields.size() > 0) {
+ vector<HashableDimensionKey> dimensionKeys;
+ filterValues(dimensionFields, slice.first.getValues(), &dimensionKeys);
+
+ dimensionsKeySet.insert(dimensionKeys.begin(), dimensionKeys.end());
}
}
return conditionState;
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.h b/cmds/statsd/src/condition/SimpleConditionTracker.h
index ce9a02d..c565129 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.h
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.h
@@ -48,14 +48,14 @@
void isConditionMet(const ConditionKey& conditionParameters,
const std::vector<sp<ConditionTracker>>& allConditions,
- const FieldMatcher& dimensionFields,
+ const vector<Matcher>& dimensionFields,
std::vector<ConditionState>& conditionCache,
- std::unordered_set<HashableDimensionKey> &dimensionsKeySet) const override;
+ std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const override;
ConditionState getMetConditionDimension(
const std::vector<sp<ConditionTracker>>& allConditions,
- const FieldMatcher& dimensionFields,
- std::unordered_set<HashableDimensionKey> &dimensionsKeySet) const override;
+ const vector<Matcher>& dimensionFields,
+ std::unordered_set<HashableDimensionKey>& dimensionsKeySet) const override;
private:
const ConfigKey mConfigKey;
@@ -73,17 +73,17 @@
ConditionState mInitialValue;
- FieldMatcher mOutputDimensions;
+ std::vector<Matcher> mOutputDimensions;
+
+ int mDimensionTag;
std::map<HashableDimensionKey, int> mSlicedConditionState;
void handleStopAll(std::vector<ConditionState>& conditionCache,
std::vector<bool>& changedCache);
- void handleConditionEvent(const HashableDimensionKey& outputKey,
- bool matchStart,
- std::vector<ConditionState>& conditionCache,
- std::vector<bool>& changedCache);
+ void handleConditionEvent(const HashableDimensionKey& outputKey, bool matchStart,
+ ConditionState* conditionCache, bool* changedCache);
bool hitGuardRail(const HashableDimensionKey& newKey);
diff --git a/cmds/statsd/src/condition/condition_util.cpp b/cmds/statsd/src/condition/condition_util.cpp
index 0ab33cf..691356b 100644
--- a/cmds/statsd/src/condition/condition_util.cpp
+++ b/cmds/statsd/src/condition/condition_util.cpp
@@ -27,7 +27,6 @@
#include "ConditionTracker.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
#include "stats_util.h"
-#include "dimension.h"
namespace android {
namespace os {
@@ -97,109 +96,6 @@
ConditionState operator|(ConditionState l, ConditionState r) {
return l >= r ? l : r;
}
-
-void OrConditionState(const std::vector<ConditionState>& ref, vector<ConditionState> * ored) {
- if (ref.size() != ored->size()) {
- return;
- }
- for (size_t i = 0; i < ored->size(); ++i) {
- ored->at(i) = ored->at(i) | ref.at(i);
- }
-}
-
-void OrBooleanVector(const std::vector<bool>& ref, vector<bool> * ored) {
- if (ref.size() != ored->size()) {
- return;
- }
- for (size_t i = 0; i < ored->size(); ++i) {
- ored->at(i) = ored->at(i) | ref.at(i);
- }
-}
-
-void getFieldsFromFieldMatcher(const FieldMatcher& matcher, Field* rootField, Field* leafField,
- std::vector<Field> *allFields) {
- if (matcher.has_position()) {
- leafField->set_position_index(0);
- }
- if (matcher.child_size() == 0) {
- allFields->push_back(*rootField);
- return;
- }
- for (int i = 0; i < matcher.child_size(); ++i) {
- Field* newLeafField = leafField->add_child();
- newLeafField->set_field(matcher.child(i).field());
- getFieldsFromFieldMatcher(matcher.child(i), rootField, newLeafField, allFields);
- }
-}
-
-void getFieldsFromFieldMatcher(const FieldMatcher& matcher, std::vector<Field> *allFields) {
- if (!matcher.has_field()) {
- return;
- }
- Field rootField;
- rootField.set_field(matcher.field());
- getFieldsFromFieldMatcher(matcher, &rootField, &rootField, allFields);
-}
-
-void flattenValueLeaves(const DimensionsValue& value,
- std::vector<const DimensionsValue*> *allLaves) {
- switch (value.value_case()) {
- case DimensionsValue::ValueCase::kValueStr:
- case DimensionsValue::ValueCase::kValueInt:
- case DimensionsValue::ValueCase::kValueLong:
- case DimensionsValue::ValueCase::kValueBool:
- case DimensionsValue::ValueCase::kValueFloat:
- case DimensionsValue::ValueCase::VALUE_NOT_SET:
- allLaves->push_back(&value);
- break;
- case DimensionsValue::ValueCase::kValueTuple:
- for (int i = 0; i < value.value_tuple().dimensions_value_size(); ++i) {
- flattenValueLeaves(value.value_tuple().dimensions_value(i), allLaves);
- }
- break;
- }
-}
-
-void getDimensionKeysForCondition(
- const LogEvent& event, const MetricConditionLink& link,
- std::vector<HashableDimensionKey> *hashableDimensionKeys) {
- std::vector<Field> whatFields;
- getFieldsFromFieldMatcher(link.fields_in_what(), &whatFields);
- std::vector<Field> conditionFields;
- getFieldsFromFieldMatcher(link.fields_in_condition(), &conditionFields);
-
- // TODO(yanglu): here we could simplify the logic to get the leaf value node in what and
- // directly construct the full condition value tree.
- std::vector<DimensionsValue> whatValues;
- getDimensionKeys(event, link.fields_in_what(), &whatValues);
-
- for (size_t i = 0; i < whatValues.size(); ++i) {
- std::vector<const DimensionsValue*> whatLeaves;
- flattenValueLeaves(whatValues[i], &whatLeaves);
- if (whatLeaves.size() != whatFields.size() ||
- whatLeaves.size() != conditionFields.size()) {
- ALOGE("Dimensions between what and condition not equal.");
- return;
- }
- FieldValueMap conditionValueMap;
- for (size_t j = 0; j < whatLeaves.size(); ++j) {
- DimensionsValue* conditionValue = &conditionValueMap[conditionFields[j]];
- *conditionValue = *whatLeaves[i];
- if (!setFieldInLeafValueProto(conditionFields[j], conditionValue)) {
- ALOGE("Not able to reset the field for condition leaf value.");
- return;
- }
- }
- std::vector<DimensionsValue> conditionValueTrees;
- findDimensionsValues(conditionValueMap, link.fields_in_condition(), &conditionValueTrees);
- if (conditionValueTrees.size() != 1) {
- ALOGE("Not able to find unambiguous field value in condition atom.");
- continue;
- }
- hashableDimensionKeys->push_back(HashableDimensionKey(conditionValueTrees[0]));
- }
-}
-
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/condition/condition_util.h b/cmds/statsd/src/condition/condition_util.h
index a7288be..fed90ec 100644
--- a/cmds/statsd/src/condition/condition_util.h
+++ b/cmds/statsd/src/condition/condition_util.h
@@ -33,16 +33,10 @@
};
ConditionState operator|(ConditionState l, ConditionState r);
-void OrConditionState(const std::vector<ConditionState>& ref, vector<ConditionState> * ored);
-void OrBooleanVector(const std::vector<bool>& ref, vector<bool> * ored);
ConditionState evaluateCombinationCondition(const std::vector<int>& children,
const LogicalOperation& operation,
const std::vector<ConditionState>& conditionCache);
-
-void getDimensionKeysForCondition(
- const LogEvent& event, const MetricConditionLink& link,
- std::vector<HashableDimensionKey> *dimensionKeys);
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index 06ff603..fbb0fdd 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -101,7 +101,7 @@
}
void ConfigManager::remove_saved_configs(const ConfigKey& key) {
- string suffix = StringPrintf("%d-%lld", key.GetUid(), (long long)key.GetId());
+ string suffix = StringPrintf("%d_%lld", key.GetUid(), (long long)key.GetId());
StorageManager::deleteSuffixedFiles(STATS_SERVICE_DIR, suffix.c_str());
}
diff --git a/cmds/statsd/src/dimension.cpp b/cmds/statsd/src/dimension.cpp
deleted file mode 100644
index 8a2e871..0000000
--- a/cmds/statsd/src/dimension.cpp
+++ /dev/null
@@ -1,400 +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.
- */
-
-#include "Log.h"
-
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-#include "frameworks/base/cmds/statsd/src/statsd_internal.pb.h"
-#include "dimension.h"
-
-
-namespace android {
-namespace os {
-namespace statsd {
-
-const DimensionsValue* getSingleLeafValue(const DimensionsValue* value) {
- if (value->value_case() == DimensionsValue::ValueCase::kValueTuple) {
- return getSingleLeafValue(&value->value_tuple().dimensions_value(0));
- } else {
- return value;
- }
-}
-
-DimensionsValue getSingleLeafValue(const DimensionsValue& value) {
- const DimensionsValue* leafValue = getSingleLeafValue(&value);
- return *leafValue;
-}
-
-void appendLeafNodeToTree(const Field& field,
- const DimensionsValue& value,
- DimensionsValue* parentValue) {
- if (field.child_size() <= 0) {
- *parentValue = value;
- parentValue->set_field(field.field());
- return;
- }
- parentValue->set_field(field.field());
- int idx = -1;
- for (int i = 0; i < parentValue->mutable_value_tuple()->dimensions_value_size(); ++i) {
- if (parentValue->mutable_value_tuple()->dimensions_value(i).field() ==
- field.child(0).field()) {
- idx = i;
- }
- }
- if (idx < 0) {
- parentValue->mutable_value_tuple()->add_dimensions_value();
- idx = parentValue->mutable_value_tuple()->dimensions_value_size() - 1;
- }
- appendLeafNodeToTree(
- field.child(0), value,
- parentValue->mutable_value_tuple()->mutable_dimensions_value(idx));
-}
-
-void appendLeafNodeToTrees(const Field& field,
- const DimensionsValue& node,
- std::vector<DimensionsValue>* rootTrees) {
- if (rootTrees == nullptr) {
- return;
- }
- if (rootTrees->empty()) {
- DimensionsValue tree;
- appendLeafNodeToTree(field, node, &tree);
- rootTrees->push_back(tree);
- } else {
- for (size_t i = 0; i < rootTrees->size(); ++i) {
- appendLeafNodeToTree(field, node, &rootTrees->at(i));
- }
- }
-}
-
-namespace {
-
-void findDimensionsValues(
- const FieldValueMap& fieldValueMap,
- const FieldMatcher& matcher,
- Field* rootField,
- Field* leafField,
- std::vector<DimensionsValue>* rootDimensionsValues);
-
-void findNonRepeatedDimensionsValues(
- const FieldValueMap& fieldValueMap,
- const FieldMatcher& matcher,
- Field* rootField,
- Field* leafField,
- std::vector<DimensionsValue>* rootValues) {
- if (matcher.child_size() > 0) {
- Field* newLeafField = leafField->add_child();
- for (const auto& childMatcher : matcher.child()) {
- newLeafField->set_field(childMatcher.field());
- findDimensionsValues(fieldValueMap, childMatcher, rootField, newLeafField, rootValues);
- }
- leafField->clear_child();
- } else {
- auto ret = fieldValueMap.equal_range(*rootField);
- int found = 0;
- for (auto it = ret.first; it != ret.second; ++it) {
- found++;
- }
- // Not found.
- if (found <= 0) {
- return;
- }
- if (found > 1) {
- ALOGE("Found multiple values for optional field.");
- return;
- }
- appendLeafNodeToTrees(*rootField, ret.first->second, rootValues);
- }
-}
-
-void findRepeatedDimensionsValues(const FieldValueMap& fieldValueMap,
- const FieldMatcher& matcher,
- Field* rootField,
- Field* leafField,
- std::vector<DimensionsValue>* rootValues) {
- if (matcher.position() == Position::FIRST) {
- leafField->set_position_index(0);
- findNonRepeatedDimensionsValues(fieldValueMap, matcher, rootField, leafField, rootValues);
- leafField->clear_position_index();
- } else {
- auto itLower = fieldValueMap.lower_bound(*rootField);
- if (itLower == fieldValueMap.end()) {
- return;
- }
- const int leafFieldNum = leafField->field();
- leafField->set_field(leafFieldNum + 1);
- auto itUpper = fieldValueMap.lower_bound(*rootField);
- // Resets the field number.
- leafField->set_field(leafFieldNum);
-
- switch (matcher.position()) {
- case Position::LAST:
- {
- itUpper--;
- if (itUpper != fieldValueMap.end()) {
- int last_index = getPositionByReferenceField(*rootField, itUpper->first);
- if (last_index < 0) {
- return;
- }
- leafField->set_position_index(last_index);
- findNonRepeatedDimensionsValues(
- fieldValueMap, matcher, rootField, leafField, rootValues);
- leafField->clear_position_index();
- }
- }
- break;
- case Position::ANY:
- {
- std::set<int> indexes;
- for (auto it = itLower; it != itUpper; ++it) {
- int index = getPositionByReferenceField(*rootField, it->first);
- if (index >= 0) {
- indexes.insert(index);
- }
- }
- if (!indexes.empty()) {
- std::vector<DimensionsValue> allValues;
- for (const int index : indexes) {
- leafField->set_position_index(index);
- std::vector<DimensionsValue> newValues = *rootValues;
- findNonRepeatedDimensionsValues(
- fieldValueMap, matcher, rootField, leafField, &newValues);
- allValues.insert(allValues.end(), newValues.begin(), newValues.end());
- leafField->clear_position_index();
- }
- rootValues->clear();
- rootValues->insert(rootValues->end(), allValues.begin(), allValues.end());
- }
- }
- break;
- default:
- break;
- }
- }
-}
-
-void findDimensionsValues(
- const FieldValueMap& fieldValueMap,
- const FieldMatcher& matcher,
- Field* rootField,
- Field* leafField,
- std::vector<DimensionsValue>* rootDimensionsValues) {
- if (!matcher.has_position()) {
- findNonRepeatedDimensionsValues(fieldValueMap, matcher, rootField, leafField,
- rootDimensionsValues);
- } else {
- findRepeatedDimensionsValues(fieldValueMap, matcher, rootField, leafField,
- rootDimensionsValues);
- }
-}
-
-} // namespace
-
-void findDimensionsValues(
- const FieldValueMap& fieldValueMap,
- const FieldMatcher& matcher,
- std::vector<DimensionsValue>* rootDimensionsValues) {
- Field rootField;
- buildSimpleAtomField(matcher.field(), &rootField);
- findDimensionsValues(fieldValueMap, matcher, &rootField, &rootField, rootDimensionsValues);
-}
-
-void buildSimpleAtomFieldMatcher(const int tagId, FieldMatcher* matcher) {
- matcher->set_field(tagId);
-}
-
-void buildSimpleAtomFieldMatcher(const int tagId, const int fieldNum, FieldMatcher* matcher) {
- matcher->set_field(tagId);
- matcher->add_child()->set_field(fieldNum);
-}
-
-constexpr int ATTRIBUTION_FIELD_NUM_IN_ATOM_PROTO = 1;
-constexpr int UID_FIELD_NUM_IN_ATTRIBUTION_NODE_PROTO = 1;
-constexpr int TAG_FIELD_NUM_IN_ATTRIBUTION_NODE_PROTO = 2;
-
-void buildAttributionUidFieldMatcher(const int tagId, const Position position,
- FieldMatcher* matcher) {
- matcher->set_field(tagId);
- auto child = matcher->add_child();
- child->set_field(ATTRIBUTION_FIELD_NUM_IN_ATOM_PROTO);
- child->set_position(position);
- child->add_child()->set_field(UID_FIELD_NUM_IN_ATTRIBUTION_NODE_PROTO);
-}
-
-void buildAttributionTagFieldMatcher(const int tagId, const Position position,
- FieldMatcher* matcher) {
- matcher->set_field(tagId);
- FieldMatcher* child = matcher->add_child();
- child->set_field(ATTRIBUTION_FIELD_NUM_IN_ATOM_PROTO);
- child->set_position(position);
- child->add_child()->set_field(TAG_FIELD_NUM_IN_ATTRIBUTION_NODE_PROTO);
-}
-
-void buildAttributionFieldMatcher(const int tagId, const Position position, FieldMatcher* matcher) {
- matcher->set_field(tagId);
- FieldMatcher* child = matcher->add_child();
- child->set_field(ATTRIBUTION_FIELD_NUM_IN_ATOM_PROTO);
- child->set_position(position);
- child->add_child()->set_field(UID_FIELD_NUM_IN_ATTRIBUTION_NODE_PROTO);
- child->add_child()->set_field(TAG_FIELD_NUM_IN_ATTRIBUTION_NODE_PROTO);
-}
-
-void DimensionsValueToString(const DimensionsValue& value, std::string *flattened) {
- if (!value.has_field()) {
- return;
- }
- *flattened += std::to_string(value.field());
- *flattened += ":";
- switch (value.value_case()) {
- case DimensionsValue::ValueCase::kValueStr:
- *flattened += value.value_str();
- break;
- case DimensionsValue::ValueCase::kValueInt:
- *flattened += std::to_string(value.value_int());
- break;
- case DimensionsValue::ValueCase::kValueLong:
- *flattened += std::to_string(value.value_long());
- break;
- case DimensionsValue::ValueCase::kValueBool:
- *flattened += std::to_string(value.value_bool());
- break;
- case DimensionsValue::ValueCase::kValueFloat:
- *flattened += std::to_string(value.value_float());
- break;
- case DimensionsValue::ValueCase::kValueTuple:
- {
- *flattened += "{";
- for (int i = 0; i < value.value_tuple().dimensions_value_size(); ++i) {
- DimensionsValueToString(value.value_tuple().dimensions_value(i), flattened);
- *flattened += "|";
- }
- *flattened += "}";
- }
- break;
- case DimensionsValue::ValueCase::VALUE_NOT_SET:
- break;
- }
-}
-
-std::string DimensionsValueToString(const DimensionsValue& value) {
- std::string flatten;
- DimensionsValueToString(value, &flatten);
- return flatten;
-}
-
-bool IsSubDimension(const DimensionsValue& dimension, const DimensionsValue& sub) {
- if (dimension.field() != sub.field()) {
- return false;
- }
- if (dimension.value_case() != sub.value_case()) {
- return false;
- }
- switch (dimension.value_case()) {
- case DimensionsValue::ValueCase::kValueStr:
- return dimension.value_str() == sub.value_str();
- case DimensionsValue::ValueCase::kValueInt:
- return dimension.value_int() == sub.value_int();
- case DimensionsValue::ValueCase::kValueLong:
- return dimension.value_long() == sub.value_long();
- case DimensionsValue::ValueCase::kValueBool:
- return dimension.value_bool() == sub.value_bool();
- case DimensionsValue::ValueCase::kValueFloat:
- return dimension.value_float() == sub.value_float();
- case DimensionsValue::ValueCase::kValueTuple: {
- if (dimension.value_tuple().dimensions_value_size() <
- sub.value_tuple().dimensions_value_size()) {
- return false;
- }
- bool allSub = true;
- for (int i = 0; allSub && i < sub.value_tuple().dimensions_value_size(); ++i) {
- bool isSub = false;
- for (int j = 0; !isSub &&
- j < dimension.value_tuple().dimensions_value_size(); ++j) {
- isSub |= IsSubDimension(dimension.value_tuple().dimensions_value(j),
- sub.value_tuple().dimensions_value(i));
- }
- allSub &= isSub;
- }
- return allSub;
- }
- break;
- case DimensionsValue::ValueCase::VALUE_NOT_SET:
- return false;
- default:
- return false;
- }
-}
-
-long getLongFromDimenValue(const DimensionsValue& dimensionValue) {
- switch (dimensionValue.value_case()) {
- case DimensionsValue::ValueCase::kValueInt:
- return dimensionValue.value_int();
- case DimensionsValue::ValueCase::kValueLong:
- return dimensionValue.value_long();
- case DimensionsValue::ValueCase::kValueBool:
- return dimensionValue.value_bool() ? 1 : 0;
- case DimensionsValue::ValueCase::kValueFloat:
- return (int64_t)dimensionValue.value_float();
- case DimensionsValue::ValueCase::kValueTuple:
- case DimensionsValue::ValueCase::kValueStr:
- case DimensionsValue::ValueCase::VALUE_NOT_SET:
- return 0;
- }
-}
-
-bool getSubDimension(const DimensionsValue& dimension, const FieldMatcher& matcher,
- DimensionsValue* subDimension) {
- if (!matcher.has_field()) {
- return false;
- }
- if (matcher.field() != dimension.field()) {
- return false;
- }
- if (matcher.child_size() <= 0) {
- if (dimension.value_case() == DimensionsValue::ValueCase::kValueTuple ||
- dimension.value_case() == DimensionsValue::ValueCase::VALUE_NOT_SET) {
- return false;
- }
- *subDimension = dimension;
- return true;
- } else {
- if (dimension.value_case() != DimensionsValue::ValueCase::kValueTuple) {
- return false;
- }
- bool found_value = true;
- auto value_tuple = dimension.value_tuple();
- subDimension->set_field(dimension.field());
- for (int i = 0; found_value && i < matcher.child_size(); ++i) {
- int j = 0;
- for (; j < value_tuple.dimensions_value_size(); ++j) {
- if (value_tuple.dimensions_value(j).field() == matcher.child(i).field()) {
- break;
- }
- }
- if (j < value_tuple.dimensions_value_size()) {
- found_value &= getSubDimension(value_tuple.dimensions_value(j), matcher.child(i),
- subDimension->mutable_value_tuple()->add_dimensions_value());
- } else {
- found_value = false;
- }
- }
- return found_value;
- }
-}
-
-} // namespace statsd
-} // namespace os
-} // namespace android
diff --git a/cmds/statsd/src/dimension.h b/cmds/statsd/src/dimension.h
deleted file mode 100644
index 138c6e9..0000000
--- a/cmds/statsd/src/dimension.h
+++ /dev/null
@@ -1,71 +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.
- */
-
-#pragma once
-
-#include <log/logprint.h>
-#include <set>
-#include <vector>
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-#include "field_util.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-// Returns the leaf node from the DimensionsValue proto. It assume that the input has only one
-// leaf node at most.
-const DimensionsValue* getSingleLeafValue(const DimensionsValue* value);
-DimensionsValue getSingleLeafValue(const DimensionsValue& value);
-
-// Appends the leaf node to the parent tree.
-void appendLeafNodeToTree(const Field& field, const DimensionsValue& value, DimensionsValue* tree);
-
-// Constructs the DimensionsValue protos from the FieldMatcher. Each DimensionsValue proto
-// represents a tree. When the input proto has repeated fields and the input "dimensions" wants
-// "ANY" locations, it will return multiple trees.
-void findDimensionsValues(
- const FieldValueMap& fieldValueMap,
- const FieldMatcher& matcher,
- std::vector<DimensionsValue>* rootDimensionsValues);
-
-// Utils to build FieldMatcher proto for simple one-depth atoms.
-void buildSimpleAtomFieldMatcher(const int tagId, const int atomFieldNum, FieldMatcher* matcher);
-void buildSimpleAtomFieldMatcher(const int tagId, FieldMatcher* matcher);
-
-// Utils to build FieldMatcher proto for attribution nodes.
-void buildAttributionUidFieldMatcher(const int tagId, const Position position,
- FieldMatcher* matcher);
-void buildAttributionTagFieldMatcher(const int tagId, const Position position,
- FieldMatcher* matcher);
-void buildAttributionFieldMatcher(const int tagId, const Position position,
- FieldMatcher* matcher);
-
-// Utils to print pretty string for DimensionsValue proto.
-std::string DimensionsValueToString(const DimensionsValue& value);
-void DimensionsValueToString(const DimensionsValue& value, std::string *flattened);
-
-bool IsSubDimension(const DimensionsValue& dimension, const DimensionsValue& sub);
-
-// Helper function to get long value from the DimensionsValue proto.
-long getLongFromDimenValue(const DimensionsValue& dimensionValue);
-
-bool getSubDimension(const DimensionsValue& dimension, const FieldMatcher& matcher,
- DimensionsValue* subDimension);
-} // namespace statsd
-} // namespace os
-} // namespace android
diff --git a/cmds/statsd/src/external/CpuTimePerUidFreqPuller.cpp b/cmds/statsd/src/external/CpuTimePerUidFreqPuller.cpp
index d0d2f93..d1d9d37 100644
--- a/cmds/statsd/src/external/CpuTimePerUidFreqPuller.cpp
+++ b/cmds/statsd/src/external/CpuTimePerUidFreqPuller.cpp
@@ -25,6 +25,7 @@
#include "guardrail/StatsdStats.h"
#include "logd/LogEvent.h"
#include "statslog.h"
+#include "stats_log_util.h"
using std::make_shared;
using std::shared_ptr;
@@ -62,7 +63,9 @@
return false;
}
- uint64_t timestamp = time(nullptr) * NS_PER_SEC;
+ int64_t wallClockTimestampNs = getWallClockNs();
+ int64_t elapsedTimestampNs = getElapsedRealtimeNs();
+
char buf[kLineBufferSize];
// first line prints the format and frequencies
fin.getline(buf, kLineBufferSize);
@@ -77,7 +80,8 @@
int idx = 0;
do {
timeMs = std::stoull(pch);
- auto ptr = make_shared<LogEvent>(android::util::CPU_TIME_PER_UID_FREQ, timestamp);
+ auto ptr = make_shared<LogEvent>(android::util::CPU_TIME_PER_UID_FREQ,
+ wallClockTimestampNs, elapsedTimestampNs);
ptr->write(uid);
ptr->write(idx);
ptr->write(timeMs);
diff --git a/cmds/statsd/src/external/CpuTimePerUidPuller.cpp b/cmds/statsd/src/external/CpuTimePerUidPuller.cpp
index d9aeb46..568b8f0 100644
--- a/cmds/statsd/src/external/CpuTimePerUidPuller.cpp
+++ b/cmds/statsd/src/external/CpuTimePerUidPuller.cpp
@@ -24,6 +24,7 @@
#include "guardrail/StatsdStats.h"
#include "logd/LogEvent.h"
#include "statslog.h"
+#include "stats_log_util.h"
using std::make_shared;
using std::shared_ptr;
@@ -57,7 +58,8 @@
return false;
}
- uint64_t timestamp = time(nullptr) * NS_PER_SEC;
+ int64_t wallClockTimestampNs = getWallClockNs();
+ int64_t elapsedTimestampNs = getElapsedRealtimeNs();
char buf[kLineBufferSize];
char* pch;
while (!fin.eof()) {
@@ -70,7 +72,8 @@
pch = strtok(buf, " ");
uint64_t sysTimeMs = std::stoull(pch);
- auto ptr = make_shared<LogEvent>(android::util::CPU_TIME_PER_UID, timestamp);
+ auto ptr = make_shared<LogEvent>(android::util::CPU_TIME_PER_UID,
+ wallClockTimestampNs, elapsedTimestampNs);
ptr->write(uid);
ptr->write(userTimeMs);
ptr->write(sysTimeMs);
diff --git a/cmds/statsd/src/external/KernelUidCpuActiveTimeReader.cpp b/cmds/statsd/src/external/KernelUidCpuActiveTimeReader.cpp
index 0e126e7..0b545cc 100644
--- a/cmds/statsd/src/external/KernelUidCpuActiveTimeReader.cpp
+++ b/cmds/statsd/src/external/KernelUidCpuActiveTimeReader.cpp
@@ -23,6 +23,7 @@
#include "guardrail/StatsdStats.h"
#include "logd/LogEvent.h"
#include "statslog.h"
+#include "stats_log_util.h"
using std::make_shared;
using std::shared_ptr;
@@ -57,7 +58,9 @@
return false;
}
- uint64_t timestamp = time(nullptr) * NS_PER_SEC;
+ int64_t wallClockTimestampNs = getWallClockNs();
+ int64_t elapsedTimestampNs = getElapsedRealtimeNs();
+
char buf[kLineBufferSize];
char* pch;
while (!fin.eof()) {
@@ -70,7 +73,7 @@
int idx = 0;
do {
timeMs = std::stoull(pch);
- auto ptr = make_shared<LogEvent>(mTagId, timestamp);
+ auto ptr = make_shared<LogEvent>(mTagId, wallClockTimestampNs, elapsedTimestampNs);
ptr->write(uid);
ptr->write(idx);
ptr->write(timeMs);
diff --git a/cmds/statsd/src/external/KernelUidCpuClusterTimeReader.cpp b/cmds/statsd/src/external/KernelUidCpuClusterTimeReader.cpp
index 7684ed4..cc80204 100644
--- a/cmds/statsd/src/external/KernelUidCpuClusterTimeReader.cpp
+++ b/cmds/statsd/src/external/KernelUidCpuClusterTimeReader.cpp
@@ -22,6 +22,7 @@
#include "guardrail/StatsdStats.h"
#include "logd/LogEvent.h"
#include "statslog.h"
+#include "stats_log_util.h"
using std::make_shared;
using std::shared_ptr;
@@ -56,7 +57,8 @@
return false;
}
- uint64_t timestamp = time(nullptr) * NS_PER_SEC;
+ int64_t wallClockTimestampNs = getWallClockNs();
+ int64_t elapsedTimestampNs = getElapsedRealtimeNs();
char buf[kLineBufferSize];
char* pch;
while (!fin.eof()) {
@@ -69,7 +71,7 @@
int idx = 0;
do {
timeMs = std::stoull(pch);
- auto ptr = make_shared<LogEvent>(mTagId, timestamp);
+ auto ptr = make_shared<LogEvent>(mTagId, wallClockTimestampNs, elapsedTimestampNs);
ptr->write(uid);
ptr->write(idx);
ptr->write(timeMs);
diff --git a/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp b/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp
index 72fb5ff..261cb43 100644
--- a/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp
+++ b/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp
@@ -25,6 +25,7 @@
#include "ResourceHealthManagerPuller.h"
#include "logd/LogEvent.h"
#include "statslog.h"
+#include "stats_log_util.h"
using android::hardware::hidl_vec;
using android::hardware::health::V2_0::get_health_service;
@@ -61,7 +62,8 @@
return false;
}
- uint64_t timestamp = time(nullptr) * NS_PER_SEC;
+ int64_t wallClockTimestampNs = getWallClockNs();
+ int64_t elapsedTimestampNs = getElapsedRealtimeNs();
data->clear();
bool result_success = true;
@@ -72,12 +74,14 @@
return;
}
if (mTagId == android::util::REMAINING_BATTERY_CAPACITY) {
- auto ptr = make_shared<LogEvent>(android::util::REMAINING_BATTERY_CAPACITY, timestamp);
+ auto ptr = make_shared<LogEvent>(android::util::REMAINING_BATTERY_CAPACITY,
+ wallClockTimestampNs, elapsedTimestampNs);
ptr->write(v.legacy.batteryChargeCounter);
ptr->init();
data->push_back(ptr);
} else if (mTagId == android::util::FULL_BATTERY_CAPACITY) {
- auto ptr = make_shared<LogEvent>(android::util::FULL_BATTERY_CAPACITY, timestamp);
+ auto ptr = make_shared<LogEvent>(android::util::FULL_BATTERY_CAPACITY,
+ wallClockTimestampNs, elapsedTimestampNs);
ptr->write(v.legacy.batteryFullCharge);
ptr->init();
data->push_back(ptr);
diff --git a/cmds/statsd/src/external/StatsCompanionServicePuller.cpp b/cmds/statsd/src/external/StatsCompanionServicePuller.cpp
index 8210c8d..bd859fd 100644
--- a/cmds/statsd/src/external/StatsCompanionServicePuller.cpp
+++ b/cmds/statsd/src/external/StatsCompanionServicePuller.cpp
@@ -22,6 +22,7 @@
#include <private/android_filesystem_config.h>
#include "StatsCompanionServicePuller.h"
#include "StatsService.h"
+#include "stats_log_util.h"
#include "guardrail/StatsdStats.h"
using namespace android;
@@ -53,13 +54,13 @@
return false;
}
data->clear();
- int timestamp = time(nullptr);
+ int32_t timestampSec = getWallClockSec();
for (const StatsLogEventWrapper& it : returned_value) {
log_msg tmp;
tmp.entry_v1.len = it.bytes.size();
// Manually set the header size to 28 bytes to match the pushed log events.
tmp.entry.hdr_size = kLogMsgHeaderSize;
- tmp.entry_v1.sec = timestamp;
+ tmp.entry_v1.sec = timestampSec;
// And set the received bytes starting after the 28 bytes reserved for header.
std::copy(it.bytes.begin(), it.bytes.end(), tmp.buf + kLogMsgHeaderSize);
data->push_back(make_shared<LogEvent>(tmp));
diff --git a/cmds/statsd/src/external/StatsPuller.cpp b/cmds/statsd/src/external/StatsPuller.cpp
index fc0ad7c..9513cc5 100644
--- a/cmds/statsd/src/external/StatsPuller.cpp
+++ b/cmds/statsd/src/external/StatsPuller.cpp
@@ -20,6 +20,7 @@
#include "StatsPuller.h"
#include "guardrail/StatsdStats.h"
#include "puller_util.h"
+#include "stats_log_util.h"
namespace android {
namespace os {
@@ -44,7 +45,7 @@
bool StatsPuller::Pull(std::vector<std::shared_ptr<LogEvent>>* data) {
lock_guard<std::mutex> lock(mLock);
StatsdStats::getInstance().notePull(mTagId);
- long curTime = time(nullptr);
+ long curTime = getElapsedRealtimeSec();
if (curTime - mLastPullTimeSec < mCoolDownSec) {
(*data) = mCachedData;
StatsdStats::getInstance().notePullFromCache(mTagId);
diff --git a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
index 4c676a7..08c59cf 100644
--- a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
+++ b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
@@ -33,6 +33,7 @@
#include "SubsystemSleepStatePuller.h"
#include "logd/LogEvent.h"
#include "statslog.h"
+#include "stats_log_util.h"
#include <iostream>
@@ -165,8 +166,9 @@
if (roundedIntervalMs < mCurrentPullingInterval) {
VLOG("Updating pulling interval %ld", intervalMs);
mCurrentPullingInterval = roundedIntervalMs;
- long currentTimeMs = time(nullptr) * 1000;
- long nextAlarmTimeMs = currentTimeMs + mCurrentPullingInterval - (currentTimeMs - mTimeBaseSec * 1000) % mCurrentPullingInterval;
+ long currentTimeMs = getElapsedRealtimeMillis();
+ long nextAlarmTimeMs = currentTimeMs + mCurrentPullingInterval -
+ (currentTimeMs - mTimeBaseSec * 1000) % mCurrentPullingInterval;
if (mStatsCompanionService != nullptr) {
mStatsCompanionService->setPullingAlarms(nextAlarmTimeMs, mCurrentPullingInterval);
} else {
@@ -195,7 +197,7 @@
void StatsPullerManagerImpl::OnAlarmFired() {
AutoMutex _l(mReceiversLock);
- uint64_t currentTimeMs = time(nullptr) /60 * 60 * 1000;
+ uint64_t currentTimeMs = getElapsedRealtimeMillis();
vector<pair<int, vector<ReceiverInfo*>>> needToPull =
vector<pair<int, vector<ReceiverInfo*>>>();
diff --git a/cmds/statsd/src/external/SubsystemSleepStatePuller.cpp b/cmds/statsd/src/external/SubsystemSleepStatePuller.cpp
index 65a1df0e..4501b64 100644
--- a/cmds/statsd/src/external/SubsystemSleepStatePuller.cpp
+++ b/cmds/statsd/src/external/SubsystemSleepStatePuller.cpp
@@ -36,6 +36,7 @@
#include "SubsystemSleepStatePuller.h"
#include "logd/LogEvent.h"
#include "statslog.h"
+#include "stats_log_util.h"
using android::hardware::hidl_vec;
using android::hardware::power::V1_0::IPower;
@@ -84,20 +85,22 @@
return false;
}
- uint64_t timestamp = time(nullptr) * NS_PER_SEC;
+ int64_t wallClockTimestampNs = getWallClockNs();
+ int64_t elapsedTimestampNs = getElapsedRealtimeNs();
data->clear();
Return<void> ret;
ret = gPowerHalV1_0->getPlatformLowPowerStats(
- [&data, timestamp](hidl_vec<PowerStatePlatformSleepState> states, Status status) {
+ [&data, wallClockTimestampNs, elapsedTimestampNs](hidl_vec<PowerStatePlatformSleepState> states, Status status) {
if (status != Status::SUCCESS) return;
for (size_t i = 0; i < states.size(); i++) {
const PowerStatePlatformSleepState& state = states[i];
- auto statePtr = make_shared<LogEvent>(android::util::SUBSYSTEM_SLEEP_STATE,
- timestamp);
+ auto statePtr = make_shared<LogEvent>(
+ android::util::SUBSYSTEM_SLEEP_STATE,
+ wallClockTimestampNs, elapsedTimestampNs);
statePtr->write(state.name);
statePtr->write("");
statePtr->write(state.totalTransitions);
@@ -109,8 +112,9 @@
(long long)state.totalTransitions,
state.supportedOnlyInSuspend ? 1 : 0);
for (auto voter : state.voters) {
- auto voterPtr = make_shared<LogEvent>(android::util::SUBSYSTEM_SLEEP_STATE,
- timestamp);
+ auto voterPtr = make_shared<LogEvent>(
+ android::util::SUBSYSTEM_SLEEP_STATE,
+ wallClockTimestampNs, elapsedTimestampNs);
voterPtr->write(state.name);
voterPtr->write(voter.name);
voterPtr->write(voter.totalNumberOfTimesVotedSinceBoot);
@@ -135,7 +139,7 @@
android::hardware::power::V1_1::IPower::castFrom(gPowerHalV1_0);
if (gPowerHal_1_1 != nullptr) {
ret = gPowerHal_1_1->getSubsystemLowPowerStats(
- [&data, timestamp](hidl_vec<PowerStateSubsystem> subsystems, Status status) {
+ [&data, wallClockTimestampNs, elapsedTimestampNs](hidl_vec<PowerStateSubsystem> subsystems, Status status) {
if (status != Status::SUCCESS) return;
if (subsystems.size() > 0) {
@@ -145,7 +149,8 @@
const PowerStateSubsystemSleepState& state =
subsystem.states[j];
auto subsystemStatePtr = make_shared<LogEvent>(
- android::util::SUBSYSTEM_SLEEP_STATE, timestamp);
+ android::util::SUBSYSTEM_SLEEP_STATE,
+ wallClockTimestampNs, elapsedTimestampNs);
subsystemStatePtr->write(subsystem.name);
subsystemStatePtr->write(state.name);
subsystemStatePtr->write(state.totalTransitions);
diff --git a/cmds/statsd/src/external/puller_util.cpp b/cmds/statsd/src/external/puller_util.cpp
index 7cfc1d48..0b0c5c4 100644
--- a/cmds/statsd/src/external/puller_util.cpp
+++ b/cmds/statsd/src/external/puller_util.cpp
@@ -18,7 +18,6 @@
#include "Log.h"
#include "StatsPullerManagerImpl.h"
-#include "field_util.h"
#include "puller_util.h"
#include "statslog.h"
@@ -30,125 +29,136 @@
using std::shared_ptr;
using std::vector;
-DimensionsValue* getFieldValue(shared_ptr<LogEvent> event, int tagId, int fieldNum) {
- Field field;
- buildSimpleAtomField(tagId, fieldNum, &field);
- return event->findFieldValueOrNull(field);
-}
-
+namespace {
bool shouldMerge(shared_ptr<LogEvent>& lhs, shared_ptr<LogEvent>& rhs,
- const vector<int>& nonAdditiveFields, int tagId) {
- for (int f : nonAdditiveFields) {
- DimensionsValue* lValue = getFieldValue(lhs, tagId, f);
- DimensionsValue* rValue = getFieldValue(rhs, tagId, f);
- if (!compareDimensionsValue(*lValue, *rValue)) {
- return false;
+ const vector<int>& nonAdditiveFields) {
+ const auto& l_values = lhs->getValues();
+ const auto& r_values = rhs->getValues();
+
+ for (size_t i : nonAdditiveFields) {
+ // We store everything starting from index 0, so we need to use i-1
+ if (!(l_values.size() > i - 1 && r_values.size() > i - 1 &&
+ l_values[i - 1].mValue == r_values[i - 1].mValue)) {
+ return false;
+ }
}
- }
- return true;
+ return true;
}
// merge rhs to lhs
-void mergeEvent(shared_ptr<LogEvent>& lhs, shared_ptr<LogEvent>& rhs,
- const vector<int>& additiveFields, int tagId) {
- for (int f : additiveFields) {
- DimensionsValue* lValue = getFieldValue(lhs, tagId, f);
- DimensionsValue* rValue = getFieldValue(rhs, tagId, f);
- if (lValue->has_value_int()) {
- lValue->set_value_int(lValue->value_int() + rValue->value_int());
- } else if (lValue->has_value_long()) {
- lValue->set_value_long(lValue->value_long() + rValue->value_long());
+// when calling this function, all sanity check should be done already.
+// e.g., index boundary, nonAdditiveFields matching etc.
+bool mergeEvent(shared_ptr<LogEvent>& lhs, shared_ptr<LogEvent>& rhs,
+ const vector<int>& additiveFields) {
+ vector<FieldValue>* host_values = lhs->getMutableValues();
+ const auto& child_values = rhs->getValues();
+ for (int i : additiveFields) {
+ Value& host = (*host_values)[i - 1].mValue;
+ const Value& child = (child_values[i - 1]).mValue;
+ if (child.getType() != host.getType()) {
+ return false;
+ }
+ switch (child.getType()) {
+ case INT:
+ host.setInt(host.int_value + child.int_value);
+ break;
+ case LONG:
+ host.setLong(host.long_value + child.long_value);
+ break;
+ default:
+ ALOGE("Tried to merge 2 fields with unsupported type");
+ return false;
+ }
}
- }
+ return true;
}
-// process all data and merge isolated with host if necessary
-void mergeIsolatedUidsToHostUid(vector<shared_ptr<LogEvent>>& data,
- const sp<UidMap>& uidMap, int tagId) {
- if (StatsPullerManagerImpl::kAllPullAtomInfo.find(tagId) ==
- StatsPullerManagerImpl::kAllPullAtomInfo.end()) {
- VLOG("Unknown pull atom id %d", tagId);
- return;
- }
- if (android::util::kAtomsWithUidField.find(tagId) ==
- android::util::kAtomsWithUidField.end()) {
- VLOG("No uid to merge for atom %d", tagId);
- return;
- }
- const vector<int>& additiveFields =
- StatsPullerManagerImpl::kAllPullAtomInfo.find(tagId)
- ->second.additiveFields;
- const vector<int>& nonAdditiveFields =
- StatsPullerManagerImpl::kAllPullAtomInfo.find(tagId)
- ->second.nonAdditiveFields;
-
- // map of host uid to isolated uid data index in the original vector.
- // because of non additive fields, there could be multiple of them that can't
- // be merged into one
- map<int, vector<int>> hostToIsolated;
- // map of host uid to their position in the original vector
- map<int, vector<int>> hostPosition;
- vector<int> isolatedUidPos;
- // all uids in the original vector
- vector<int> allUids;
- for (size_t i = 0; i < data.size(); i++) {
- // uid field is always first primitive filed, if present
- DimensionsValue* uidField = getFieldValue(data[i], tagId, 1);
- if (!uidField) {
- VLOG("Bad data for %d, %s", tagId, data[i]->ToString().c_str());
- return;
- }
- int uid = uidField->value_int();
- allUids.push_back(uid);
- const int hostUid = uidMap->getHostUidOrSelf(uid);
- if (hostUid != uid) {
- uidField->set_value_int(hostUid);
- hostToIsolated[hostUid].push_back(i);
- isolatedUidPos.push_back(i);
- }
- }
- vector<shared_ptr<LogEvent>> mergedData;
- for (size_t i = 0; i < allUids.size(); i++) {
- if (hostToIsolated.find(allUids[i]) != hostToIsolated.end()) {
- hostPosition[allUids[i]].push_back(i);
- } else if (std::find(isolatedUidPos.begin(), isolatedUidPos.end(), i) != isolatedUidPos.end()) {
- continue;
- } else {
- mergedData.push_back(data[i]);
- }
- }
- for (auto iter = hostToIsolated.begin(); iter != hostToIsolated.end();
- iter++) {
- int uid = iter->first;
- vector<int>& isolated = hostToIsolated[uid];
- vector<int> toBeMerged;
- toBeMerged.insert(toBeMerged.begin(), isolated.begin(), isolated.end());
- if (hostPosition.find(uid) != hostPosition.end()) {
- vector<int>& host = hostPosition[uid];
- toBeMerged.insert(toBeMerged.end(), host.begin(), host.end());
- }
- vector<bool> used(toBeMerged.size());
- for (size_t i = 0; i < toBeMerged.size(); i++) {
- if (used[i] == true) {
- continue;
- }
- for (size_t j = i + 1; j < toBeMerged.size(); j++) {
- shared_ptr<LogEvent>& lhs = data[toBeMerged[i]];
- shared_ptr<LogEvent>& rhs = data[toBeMerged[j]];
- if (shouldMerge(lhs, rhs, nonAdditiveFields, tagId)) {
- mergeEvent(lhs, rhs, additiveFields, tagId);
- used[j] = true;
+bool tryMerge(vector<shared_ptr<LogEvent>>& data, int child_pos, const vector<int>& host_pos,
+ const vector<int>& nonAdditiveFields, const vector<int>& additiveFields) {
+ for (const auto& pos : host_pos) {
+ if (shouldMerge(data[pos], data[child_pos], nonAdditiveFields) &&
+ mergeEvent(data[pos], data[child_pos], additiveFields)) {
+ return true;
}
- }
}
- for (size_t i = 0; i < toBeMerged.size(); i++) {
- if (used[i] == false) {
- mergedData.push_back(data[i]);
+ return false;
+}
+
+} // namespace
+
+/**
+ * Process all data and merge isolated with host if necessary.
+ * For example:
+ * NetworkBytesAtom {
+ * int uid = 1;
+ * State process_state = 2;
+ * int byte_send = 3;
+ * int byte_recv = 4;
+ * }
+ * additive fields are {3, 4}, non-additive field is {2}
+ * If we pulled the following events (uid1_child is an isolated uid which maps to uid1):
+ * [uid1, fg, 100, 200]
+ * [uid1_child, fg, 100, 200]
+ * [uid1, bg, 100, 200]
+ *
+ * We want to merge them and results should be:
+ * [uid1, fg, 200, 400]
+ * [uid1, bg, 100, 200]
+ */
+void mergeIsolatedUidsToHostUid(vector<shared_ptr<LogEvent>>& data, const sp<UidMap>& uidMap,
+ int tagId) {
+ if (StatsPullerManagerImpl::kAllPullAtomInfo.find(tagId) ==
+ StatsPullerManagerImpl::kAllPullAtomInfo.end()) {
+ VLOG("Unknown pull atom id %d", tagId);
+ return;
}
+ if (android::util::kAtomsWithUidField.find(tagId) == android::util::kAtomsWithUidField.end()) {
+ VLOG("No uid to merge for atom %d", tagId);
+ return;
}
- }
- data.clear();
- data = mergedData;
+ const vector<int>& additiveFields =
+ StatsPullerManagerImpl::kAllPullAtomInfo.find(tagId)->second.additiveFields;
+ const vector<int>& nonAdditiveFields =
+ StatsPullerManagerImpl::kAllPullAtomInfo.find(tagId)->second.nonAdditiveFields;
+
+ // map of host uid to their position in the original vector
+ map<int, vector<int>> hostPosition;
+ vector<bool> toRemove = vector<bool>(data.size(), false);
+
+ for (size_t i = 0; i < data.size(); i++) {
+ vector<FieldValue>* valueList = data[i]->getMutableValues();
+
+ int err = 0;
+ int uid = data[i]->GetInt(1, &err);
+ if (err != 0) {
+ VLOG("Bad uid field for %s", data[i]->ToString().c_str());
+ return;
+ }
+
+ const int hostUid = uidMap->getHostUidOrSelf(uid);
+
+ if (hostUid != uid) {
+ (*valueList)[0].mValue.setInt(hostUid);
+ }
+ if (hostPosition.find(hostUid) == hostPosition.end()) {
+ hostPosition[hostUid].push_back(i);
+ } else {
+ if (tryMerge(data, i, hostPosition[hostUid], nonAdditiveFields, additiveFields)) {
+ toRemove[i] = true;
+ } else {
+ hostPosition[hostUid].push_back(i);
+ }
+ }
+ }
+
+ vector<shared_ptr<LogEvent>> mergedData;
+ for (size_t i = 0; i < toRemove.size(); i++) {
+ if (!toRemove[i]) {
+ mergedData.push_back(data[i]);
+ }
+ }
+ data.clear();
+ data = mergedData;
}
} // namespace statsd
diff --git a/cmds/statsd/src/external/puller_util.h b/cmds/statsd/src/external/puller_util.h
index 70d5321..fd4a4a2 100644
--- a/cmds/statsd/src/external/puller_util.h
+++ b/cmds/statsd/src/external/puller_util.h
@@ -17,7 +17,6 @@
#pragma once
#include <vector>
-#include "HashableDimensionKey.h"
#include "StatsPuller.h"
#include "logd/LogEvent.h"
#include "packages/UidMap.h"
diff --git a/cmds/statsd/src/field_util.cpp b/cmds/statsd/src/field_util.cpp
deleted file mode 100644
index acf64fe..0000000
--- a/cmds/statsd/src/field_util.cpp
+++ /dev/null
@@ -1,318 +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.
- */
-
-#include "Log.h"
-#include "field_util.h"
-
-#include <set>
-#include <vector>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-// This function is to compare two Field trees where each node has at most one child.
-bool CompareField(const Field& a, const Field& b) {
- if (a.field() < b.field()) {
- return true;
- }
- if (a.field() > b.field()) {
- return false;
- }
- if (a.position_index() < b.position_index()) {
- return true;
- }
- if (a.position_index() > b.position_index()) {
- return false;
- }
- if (a.child_size() < b.child_size()) {
- return true;
- }
- if (a.child_size() > b.child_size()) {
- return false;
- }
- if (a.child_size() == 0 && b.child_size() == 0) {
- return false;
- }
- return CompareField(a.child(0), b.child(0));
-}
-
-const Field* getSingleLeaf(const Field* field) {
- if (field->child_size() <= 0) {
- return field;
- } else {
- return getSingleLeaf(&field->child(0));
- }
-}
-
-Field* getSingleLeaf(Field* field) {
- if (field->child_size() <= 0) {
- return field;
- } else {
- return getSingleLeaf(field->mutable_child(0));
- }
-}
-
-void FieldToString(const Field& field, std::string *flattened) {
- *flattened += std::to_string(field.field());
- if (field.has_position_index()) {
- *flattened += "[";
- *flattened += std::to_string(field.position_index());
- *flattened += "]";
- }
- if (field.child_size() <= 0) {
- return;
- }
- *flattened += ".";
- *flattened += "{";
- for (int i = 0 ; i < field.child_size(); ++i) {
- *flattened += FieldToString(field.child(i));
- }
- *flattened += "},";
-}
-
-std::string FieldToString(const Field& field) {
- std::string flatten;
- FieldToString(field, &flatten);
- return flatten;
-}
-
-bool setFieldInLeafValueProto(const Field &field, DimensionsValue* leafValue) {
- if (field.child_size() <= 0) {
- leafValue->set_field(field.field());
- return true;
- } else if (field.child_size() == 1) {
- return setFieldInLeafValueProto(field.child(0), leafValue);
- } else {
- ALOGE("Not able to set the 'field' in leaf value for multiple children.");
- return false;
- }
-}
-
-void buildSimpleAtomField(const int tagId, const int atomFieldNum, Field *field) {
- field->set_field(tagId);
- field->add_child()->set_field(atomFieldNum);
-}
-
-void buildSimpleAtomField(const int tagId, Field *field) {
- field->set_field(tagId);
-}
-
-void appendLeaf(Field *parent, int node_field_num) {
- if (!parent->has_field()) {
- parent->set_field(node_field_num);
- } else if (parent->child_size() <= 0) {
- parent->add_child()->set_field(node_field_num);
- } else {
- appendLeaf(parent->mutable_child(0), node_field_num);
- }
-}
-
-void appendLeaf(Field *parent, int node_field_num, int position) {
- if (!parent->has_field()) {
- parent->set_field(node_field_num);
- parent->set_position_index(position);
- } else if (parent->child_size() <= 0) {
- auto child = parent->add_child();
- child->set_field(node_field_num);
- child->set_position_index(position);
- } else {
- appendLeaf(parent->mutable_child(0), node_field_num, position);
- }
-}
-
-void increasePosition(Field *field) {
- if (!field->has_position_index()) {
- field->set_position_index(0);
- } else {
- field->set_position_index(field->position_index() + 1);
- }
-}
-
-int getPositionByReferenceField(const Field& ref, const Field& field_with_index) {
- if (ref.child_size() <= 0) {
- return field_with_index.position_index();
- }
- if (ref.child_size() != 1 ||
- field_with_index.child_size() != 1) {
- return -1;
- }
- return getPositionByReferenceField(ref.child(0), field_with_index.child(0));
-}
-
-namespace {
-
-void findFields(
- const FieldValueMap& fieldValueMap,
- const FieldMatcher& matcher,
- Field* rootField,
- Field* leafField,
- std::set<Field, FieldCmp>* rootFields);
-
-void findNonRepeatedFields(
- const FieldValueMap& fieldValueMap,
- const FieldMatcher& matcher,
- Field* rootField,
- Field* leafField,
- std::set<Field, FieldCmp>* rootFields) {
- if (matcher.child_size() > 0) {
- Field* newLeafField = leafField->add_child();
- for (const auto& childMatcher : matcher.child()) {
- newLeafField->set_field(childMatcher.field());
- findFields(fieldValueMap, childMatcher, rootField, newLeafField, rootFields);
- }
- leafField->clear_child();
- } else {
- auto ret = fieldValueMap.equal_range(*rootField);
- int found = 0;
- for (auto it = ret.first; it != ret.second; ++it) {
- found++;
- }
- // Not found.
- if (found <= 0) {
- return;
- }
- if (found > 1) {
- ALOGE("Found multiple values for optional field.");
- return;
- }
- rootFields->insert(ret.first->first);
- }
-}
-
-void findRepeatedFields(const FieldValueMap& fieldValueMap, const FieldMatcher& matcher,
- Field* rootField, Field* leafField,
- std::set<Field, FieldCmp>* rootFields) {
- if (matcher.position() == Position::FIRST) {
- leafField->set_position_index(0);
- findNonRepeatedFields(fieldValueMap, matcher, rootField, leafField, rootFields);
- leafField->clear_position_index();
- } else {
- auto itLower = fieldValueMap.lower_bound(*rootField);
- if (itLower == fieldValueMap.end()) {
- return;
- }
-
- const int leafFieldNum = leafField->field();
- leafField->set_field(leafFieldNum + 1);
- auto itUpper = fieldValueMap.lower_bound(*rootField);
- // Resets the field number.
- leafField->set_field(leafFieldNum);
-
- switch (matcher.position()) {
- case Position::LAST:
- {
- itUpper--;
- if (itUpper != fieldValueMap.end()) {
- int last_index = getPositionByReferenceField(*rootField, itUpper->first);
- if (last_index < 0) {
- return;
- }
- leafField->set_position_index(last_index);
- findNonRepeatedFields(
- fieldValueMap, matcher, rootField, leafField, rootFields);
- leafField->clear_position_index();
- }
- }
- break;
- case Position::ANY:
- {
- std::set<int> indexes;
- for (auto it = itLower; it != itUpper; ++it) {
- int index = getPositionByReferenceField(*rootField, it->first);
- if (index >= 0) {
- indexes.insert(index);
- }
- }
- if (!indexes.empty()) {
- for (const int index : indexes) {
- leafField->set_position_index(index);
- findNonRepeatedFields(
- fieldValueMap, matcher, rootField, leafField, rootFields);
- leafField->clear_position_index();
- }
- }
- }
- break;
- default:
- break;
- }
- }
-}
-
-void findFields(
- const FieldValueMap& fieldValueMap,
- const FieldMatcher& matcher,
- Field* rootField,
- Field* leafField,
- std::set<Field, FieldCmp>* rootFields) {
- if (!matcher.has_position()) {
- findNonRepeatedFields(fieldValueMap, matcher, rootField, leafField, rootFields);
- } else {
- findRepeatedFields(fieldValueMap, matcher, rootField, leafField, rootFields);
- }
-}
-
-} // namespace
-
-void findFields(
- const FieldValueMap& fieldValueMap,
- const FieldMatcher& matcher,
- std::set<Field, FieldCmp>* rootFields) {
- if (!matcher.has_field() || fieldValueMap.empty()) {
- return;
- }
- Field rootField;
- buildSimpleAtomField(matcher.field(), &rootField);
- return findFields(fieldValueMap, matcher, &rootField, &rootField, rootFields);
-}
-
-void filterFields(const FieldMatcher& matcher, FieldValueMap* fieldValueMap) {
- if (!matcher.has_field()) {
- return;
- }
- std::set<Field, FieldCmp> rootFields;
- findFields(*fieldValueMap, matcher, &rootFields);
- auto it = fieldValueMap->begin();
- while (it != fieldValueMap->end()) {
- if (rootFields.find(it->first) == rootFields.end()) {
- it = fieldValueMap->erase(it);
- } else {
- it++;
- }
- }
-}
-
-bool hasLeafNode(const FieldMatcher& matcher) {
- if (!matcher.has_field()) {
- return false;
- }
- for (int i = 0; i < matcher.child_size(); ++i) {
- if (hasLeafNode(matcher.child(i))) {
- return true;
- }
- }
- return true;
-}
-
-bool IsAttributionUidField(const Field& field) {
- return field.child_size() == 1 && field.child(0).field() == 1
- && field.child(0).child_size() == 1 && field.child(0).child(0).field() == 1;
-}
-
-} // namespace statsd
-} // namespace os
-} // namespace android
diff --git a/cmds/statsd/src/field_util.h b/cmds/statsd/src/field_util.h
deleted file mode 100644
index b04465d..0000000
--- a/cmds/statsd/src/field_util.h
+++ /dev/null
@@ -1,86 +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.
- */
-
-#pragma once
-
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-#include "frameworks/base/cmds/statsd/src/statsd_internal.pb.h"
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
-
-#include <map>
-#include <set>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-// Function to sort the Field protos.
-bool CompareField(const Field& a, const Field& b);
-struct FieldCmp {
- bool operator()(const Field& a, const Field& b) const {
- return CompareField(a, b);
- }
-};
-
-// Flattened dimensions value map. To save space, usually the key contains the tree structure info
-// and value field is only leaf node.
-typedef std::map<Field, DimensionsValue, FieldCmp> FieldValueMap;
-
-// Util function to print the Field proto.
-std::string FieldToString(const Field& field);
-
-// Util function to find the leaf node from the input Field proto and set it in the corresponding
-// value proto.
-bool setFieldInLeafValueProto(const Field &field, DimensionsValue* leafValue);
-
-// Returns the leaf node from the Field proto. It assume that the input has only one
-// leaf node at most.
-const Field* getSingleLeaf(const Field* field);
-Field* getSingleLeaf(Field* field);
-
-// Append a node to the current leaf. It assumes that the input "parent" has one leaf node at most.
-void appendLeaf(Field *parent, int node_field_num);
-void appendLeaf(Field *parent, int node_field_num, int position);
-
-// Increase the position index for the node. If the "position_index" is not set, set it as 0.
-void increasePosition(Field *field);
-
-// Returns true if the matcher has specified at least one leaf node.
-bool hasLeafNode(const FieldMatcher& matcher);
-
-// The two input Field proto are describing the same tree structure. Both contain one leaf node at
-// most. This is find the position index info for the leaf node at "reference" stored in the
-// "field_with_index" tree.
-int getPositionByReferenceField(const Field& reference, const Field& field_with_index);
-
-// Utils to build the Field proto for simple atom fields.
-void buildSimpleAtomField(const int tagId, const int atomFieldNum, Field* field);
-void buildSimpleAtomField(const int tagId, Field* field);
-
-// Find out all the fields specified by the matcher.
-void findFields(
- const FieldValueMap& fieldValueMap, const FieldMatcher& matcher,
- std::set<Field, FieldCmp>* rootFields);
-
-// Filter out the fields not in the field matcher.
-void filterFields(const FieldMatcher& matcher, FieldValueMap* fieldValueMap);
-
-// Returns if the field is attribution node uid field.
-bool IsAttributionUidField(const Field& field);
-
-} // namespace statsd
-} // namespace os
-} // namespace android
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index 06c5b00..66cb1d0 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -45,18 +45,9 @@
const int FIELD_ID_ATOM_STATS = 7;
const int FIELD_ID_UIDMAP_STATS = 8;
const int FIELD_ID_ANOMALY_ALARM_STATS = 9;
-const int FIELD_ID_PULLED_ATOM_STATS = 10;
+// const int FIELD_ID_PULLED_ATOM_STATS = 10; // The proto is written in stats_log_util.cpp
const int FIELD_ID_LOGGER_ERROR_STATS = 11;
-const int FIELD_ID_MATCHER_STATS_NAME = 1;
-const int FIELD_ID_MATCHER_STATS_COUNT = 2;
-
-const int FIELD_ID_CONDITION_STATS_NAME = 1;
-const int FIELD_ID_CONDITION_STATS_COUNT = 2;
-
-const int FIELD_ID_METRIC_STATS_NAME = 1;
-const int FIELD_ID_METRIC_STATS_COUNT = 2;
-
const int FIELD_ID_ATOM_STATS_TAG = 1;
const int FIELD_ID_ATOM_STATS_COUNT = 2;
@@ -80,7 +71,7 @@
// TODO: add stats for pulled atoms.
StatsdStats::StatsdStats() {
mPushedAtomStats.resize(android::util::kMaxPushedAtomId + 1);
- mStartTimeSec = time(nullptr);
+ mStartTimeSec = getWallClockSec();
}
StatsdStats& StatsdStats::getInstance() {
@@ -99,7 +90,7 @@
void StatsdStats::noteConfigReceived(const ConfigKey& key, int metricsCount, int conditionsCount,
int matchersCount, int alertsCount, bool isValid) {
lock_guard<std::mutex> lock(mLock);
- int32_t nowTimeSec = time(nullptr);
+ int32_t nowTimeSec = getWallClockSec();
// If there is an existing config for the same key, icebox the old config.
noteConfigRemovedInternalLocked(key);
@@ -125,7 +116,7 @@
void StatsdStats::noteConfigRemovedInternalLocked(const ConfigKey& key) {
auto it = mConfigStats.find(key);
if (it != mConfigStats.end()) {
- int32_t nowTimeSec = time(nullptr);
+ int32_t nowTimeSec = getWallClockSec();
it->second.set_deletion_time_sec(nowTimeSec);
// Add condition stats, metrics stats, matcher stats, alert stats
addSubStatsToConfigLocked(key, it->second);
@@ -145,7 +136,7 @@
}
void StatsdStats::noteBroadcastSent(const ConfigKey& key) {
- noteBroadcastSent(key, time(nullptr));
+ noteBroadcastSent(key, getWallClockSec());
}
void StatsdStats::noteBroadcastSent(const ConfigKey& key, int32_t timeSec) {
@@ -164,7 +155,7 @@
}
void StatsdStats::noteDataDropped(const ConfigKey& key) {
- noteDataDropped(key, time(nullptr));
+ noteDataDropped(key, getWallClockSec());
}
void StatsdStats::noteDataDropped(const ConfigKey& key, int32_t timeSec) {
@@ -183,7 +174,7 @@
}
void StatsdStats::noteMetricsReportSent(const ConfigKey& key) {
- noteMetricsReportSent(key, time(nullptr));
+ noteMetricsReportSent(key, getWallClockSec());
}
void StatsdStats::noteMetricsReportSent(const ConfigKey& key, int32_t timeSec) {
@@ -275,10 +266,6 @@
void StatsdStats::noteAtomLogged(int atomId, int32_t timeSec) {
lock_guard<std::mutex> lock(mLock);
- if (timeSec < mStartTimeSec) {
- return;
- }
-
if (atomId > android::util::kMaxPushedAtomId) {
ALOGW("not interested in atom %d", atomId);
return;
@@ -293,7 +280,7 @@
if (mLoggerErrors.size() == kMaxLoggerErrors) {
mLoggerErrors.pop_front();
}
- mLoggerErrors.push_back(std::make_pair(time(nullptr), error));
+ mLoggerErrors.push_back(std::make_pair(getWallClockSec(), error));
}
void StatsdStats::reset() {
@@ -303,7 +290,7 @@
void StatsdStats::resetInternalLocked() {
// Reset the historical data, but keep the active ConfigStats
- mStartTimeSec = time(nullptr);
+ mStartTimeSec = getWallClockSec();
mIceBox.clear();
mConditionStats.clear();
mMetricsStats.clear();
@@ -495,7 +482,7 @@
ProtoOutputStream proto;
proto.write(FIELD_TYPE_INT32 | FIELD_ID_BEGIN_TIME, mStartTimeSec);
- proto.write(FIELD_TYPE_INT32 | FIELD_ID_END_TIME, (int32_t)time(nullptr));
+ proto.write(FIELD_TYPE_INT32 | FIELD_ID_END_TIME, (int32_t)getWallClockSec());
for (const auto& configStats : mIceBox) {
const int numBytes = configStats.ByteSize();
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index f254327..7baa5e5 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -42,6 +42,7 @@
const static int kDimensionKeySizeHardLimit = 500;
const static int kMaxConfigCount = 10;
+ const static int kMaxAlertCountPerConfig = 100;
const static int kMaxConditionCountPerConfig = 200;
const static int kMaxMetricCountPerConfig = 300;
const static int kMaxMatcherCountPerConfig = 500;
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index e1ab5d5..f07fc66 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -17,13 +17,8 @@
#define DEBUG false // STOPSHIP if true
#include "logd/LogEvent.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-
-#include <set>
#include <sstream>
-#include "field_util.h"
-#include "dimension.h"
#include "stats_log_util.h"
namespace android {
@@ -38,7 +33,7 @@
LogEvent::LogEvent(log_msg& msg) {
mContext =
create_android_log_parser(msg.msg() + sizeof(uint32_t), msg.len() - sizeof(uint32_t));
- mTimestampNs = msg.entry_v1.sec * NS_PER_SEC + msg.entry_v1.nsec;
+ mLogdTimestampNs = msg.entry_v1.sec * NS_PER_SEC + msg.entry_v1.nsec;
mLogUid = msg.entry_v4.uid;
init(mContext);
if (mContext) {
@@ -47,12 +42,24 @@
}
}
-LogEvent::LogEvent(int32_t tagId, uint64_t timestampNs) {
- mTimestampNs = timestampNs;
+LogEvent::LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedTimestampNs) {
+ mLogdTimestampNs = wallClockTimestampNs;
mTagId = tagId;
mLogUid = 0;
mContext = create_android_logger(1937006964); // the event tag shared by all stats logs
if (mContext) {
+ android_log_write_int64(mContext, elapsedTimestampNs);
+ android_log_write_int32(mContext, tagId);
+ }
+}
+
+LogEvent::LogEvent(int32_t tagId, int64_t timestampNs) {
+ mLogdTimestampNs = timestampNs;
+ mTagId = tagId;
+ mLogUid = 0;
+ mContext = create_android_logger(1937006964); // the event tag shared by all stats logs
+ if (mContext) {
+ android_log_write_int64(mContext, timestampNs);
android_log_write_int32(mContext, tagId);
}
}
@@ -152,9 +159,6 @@
if (android_log_write_string8(mContext, node.tag().c_str()) < 0) {
return false;
}
- if (android_log_write_int32(mContext, node.uid()) < 0) {
- return false;
- }
if (android_log_write_list_end(mContext) < 0) {
return false;
}
@@ -163,103 +167,104 @@
return false;
}
-namespace {
-
-void increaseField(Field *field, bool is_child) {
- if (is_child) {
- if (field->child_size() <= 0) {
- field->add_child();
- }
- } else {
- field->clear_child();
- }
- Field* curr = is_child ? field->mutable_child(0) : field;
- if (!curr->has_field()) {
- curr->set_field(1);
- } else {
- curr->set_field(curr->field() + 1);
- }
-}
-
-} // namespace
-
/**
* The elements of each log event are stored as a vector of android_log_list_elements.
* The goal is to do as little preprocessing as possible, because we read a tiny fraction
* of the elements that are written to the log.
+ *
+ * The idea here is to read through the log items once, we get as much information we need for
+ * matching as possible. Because this log will be matched against lots of matchers.
*/
void LogEvent::init(android_log_context context) {
- if (!context) {
- return;
- }
android_log_list_element elem;
- // TODO: The log is actually structured inside one list. This is convenient
- // because we'll be able to use it to put the attribution (WorkSource) block first
- // without doing our own tagging scheme. Until that change is in, just drop the
- // list-related log elements and the order we get there is our index-keyed data
- // structure.
int i = 0;
-
- int seenListStart = 0;
-
- Field fieldTree;
- Field* atomField = fieldTree.add_child();
+ int depth = -1;
+ int pos[] = {1, 1, 1};
do {
elem = android_log_read_next(context);
switch ((int)elem.type) {
case EVENT_TYPE_INT:
- // elem at [0] is EVENT_TYPE_LIST, [1] is the tag id.
- if (i == 1) {
+ // elem at [0] is EVENT_TYPE_LIST, [1] is the timestamp, [2] is tag id.
+ if (i == 2) {
mTagId = elem.data.int32;
- fieldTree.set_field(mTagId);
} else {
- increaseField(atomField, seenListStart > 0/* is_child */);
- mFieldValueMap[fieldTree].set_value_int(elem.data.int32);
- }
- break;
- case EVENT_TYPE_FLOAT:
- {
- increaseField(atomField, seenListStart > 0/* is_child */);
- mFieldValueMap[fieldTree].set_value_float(elem.data.float32);
- }
- break;
- case EVENT_TYPE_STRING:
- {
- increaseField(atomField, seenListStart > 0/* is_child */);
- mFieldValueMap[fieldTree].set_value_str(
- string(elem.data.string, elem.len).c_str());
- }
- break;
- case EVENT_TYPE_LONG:
- {
- increaseField(atomField, seenListStart > 0 /* is_child */);
- mFieldValueMap[fieldTree].set_value_long(elem.data.int64);
- }
- break;
- case EVENT_TYPE_LIST:
- if (i >= 1) {
- if (seenListStart > 0) {
- increasePosition(atomField);
- } else {
- increaseField(atomField, false /* is_child */);
+ if (depth < 0 || depth > 2) {
+ return;
}
- seenListStart++;
- if (seenListStart >= 3) {
+
+ mValues.push_back(
+ FieldValue(Field(mTagId, pos, depth), Value((int32_t)elem.data.int32)));
+
+ pos[depth]++;
+ }
+ break;
+ case EVENT_TYPE_FLOAT: {
+ if (depth < 0 || depth > 2) {
+ ALOGE("Depth > 2. Not supported!");
+ return;
+ }
+
+ mValues.push_back(FieldValue(Field(mTagId, pos, depth), Value(elem.data.float32)));
+
+ pos[depth]++;
+
+ } break;
+ case EVENT_TYPE_STRING: {
+ if (depth < 0 || depth > 2) {
+ ALOGE("Depth > 2. Not supported!");
+ return;
+ }
+
+ mValues.push_back(FieldValue(Field(mTagId, pos, depth),
+ Value(string(elem.data.string, elem.len))));
+
+ pos[depth]++;
+
+ } break;
+ case EVENT_TYPE_LONG: {
+ if (i == 1) {
+ mElapsedTimestampNs = elem.data.int64;
+ } else {
+ if (depth < 0 || depth > 2) {
ALOGE("Depth > 2. Not supported!");
return;
}
+ mValues.push_back(
+ FieldValue(Field(mTagId, pos, depth), Value((int64_t)elem.data.int64)));
+
+ pos[depth]++;
}
+ } break;
+ case EVENT_TYPE_LIST:
+ depth++;
+ if (depth > 2) {
+ ALOGE("Depth > 2. Not supported!");
+ return;
+ }
+ pos[depth] = 1;
+
break;
- case EVENT_TYPE_LIST_STOP:
- seenListStart--;
- if (seenListStart == 0) {
- atomField->clear_position_index();
- } else {
- if (atomField->child_size() > 0) {
- atomField->mutable_child(0)->clear_field();
+ case EVENT_TYPE_LIST_STOP: {
+ int prevDepth = depth;
+ depth--;
+ if (depth >= 0 && depth < 2) {
+ // Now go back to decorate the previous items that are last at prevDepth.
+ // So that we can later easily match them with Position=Last matchers.
+ pos[prevDepth]--;
+ int path = getEncodedField(pos, prevDepth, false);
+ for (auto it = mValues.rbegin(); it != mValues.rend(); ++it) {
+ if (it->mField.getDepth() >= prevDepth &&
+ it->mField.getPath(prevDepth) == path) {
+ it->mField.decorateLastPos(prevDepth);
+ } else {
+ // Safe to break, because the items are in DFS order.
+ break;
+ }
}
+ pos[depth]++;
}
break;
+ }
case EVENT_TYPE_UNKNOWN:
break;
default:
@@ -270,162 +275,117 @@
}
int64_t LogEvent::GetLong(size_t key, status_t* err) const {
- DimensionsValue value;
- if (!GetSimpleAtomDimensionsValueProto(key, &value)) {
- *err = BAD_INDEX;
- return 0;
- }
- const DimensionsValue* leafValue = getSingleLeafValue(&value);
- switch (leafValue->value_case()) {
- case DimensionsValue::ValueCase::kValueInt:
- return (int64_t)leafValue->value_int();
- case DimensionsValue::ValueCase::kValueLong:
- return leafValue->value_long();
- case DimensionsValue::ValueCase::kValueBool:
- return leafValue->value_bool() ? 1 : 0;
- case DimensionsValue::ValueCase::kValueFloat:
- return (int64_t)leafValue->value_float();
- case DimensionsValue::ValueCase::kValueTuple:
- case DimensionsValue::ValueCase::kValueStr:
- case DimensionsValue::ValueCase::VALUE_NOT_SET: {
- *err = BAD_TYPE;
- return 0;
+ // TODO: encapsulate the magical operations all in Field struct as a static function.
+ int field = getSimpleField(key);
+ for (const auto& value : mValues) {
+ if (value.mField.getField() == field) {
+ if (value.mValue.getType() == LONG) {
+ return value.mValue.long_value;
+ } else if (value.mValue.getType() == INT) {
+ return value.mValue.int_value;
+ } else {
+ *err = BAD_TYPE;
+ return 0;
+ }
+ }
+ if ((size_t)value.mField.getPosAtDepth(0) > key) {
+ break;
}
}
+
+ *err = BAD_INDEX;
+ return 0;
}
int LogEvent::GetInt(size_t key, status_t* err) const {
- DimensionsValue value;
- if (!GetSimpleAtomDimensionsValueProto(key, &value)) {
+ int field = getSimpleField(key);
+ for (const auto& value : mValues) {
+ if (value.mField.getField() == field) {
+ if (value.mValue.getType() == INT) {
+ return value.mValue.int_value;
+ } else {
+ *err = BAD_TYPE;
+ return 0;
+ }
+ }
+ if ((size_t)value.mField.getPosAtDepth(0) > key) {
+ break;
+ }
+ }
+
*err = BAD_INDEX;
return 0;
- }
- const DimensionsValue* leafValue = getSingleLeafValue(&value);
- switch (leafValue->value_case()) {
- case DimensionsValue::ValueCase::kValueInt:
- return leafValue->value_int();
- case DimensionsValue::ValueCase::kValueLong:
- case DimensionsValue::ValueCase::kValueBool:
- case DimensionsValue::ValueCase::kValueFloat:
- case DimensionsValue::ValueCase::kValueTuple:
- case DimensionsValue::ValueCase::kValueStr:
- case DimensionsValue::ValueCase::VALUE_NOT_SET: {
- *err = BAD_TYPE;
- return 0;
- }
- }
}
const char* LogEvent::GetString(size_t key, status_t* err) const {
- DimensionsValue value;
- if (!GetSimpleAtomDimensionsValueProto(key, &value)) {
- *err = BAD_INDEX;
- return 0;
- }
- const DimensionsValue* leafValue = getSingleLeafValue(&value);
- switch (leafValue->value_case()) {
- case DimensionsValue::ValueCase::kValueStr:
- return leafValue->value_str().c_str();
- case DimensionsValue::ValueCase::kValueInt:
- case DimensionsValue::ValueCase::kValueLong:
- case DimensionsValue::ValueCase::kValueBool:
- case DimensionsValue::ValueCase::kValueFloat:
- case DimensionsValue::ValueCase::kValueTuple:
- case DimensionsValue::ValueCase::VALUE_NOT_SET: {
- *err = BAD_TYPE;
- return 0;
+ int field = getSimpleField(key);
+ for (const auto& value : mValues) {
+ if (value.mField.getField() == field) {
+ if (value.mValue.getType() == STRING) {
+ return value.mValue.str_value.c_str();
+ } else {
+ *err = BAD_TYPE;
+ return 0;
+ }
+ }
+ if ((size_t)value.mField.getPosAtDepth(0) > key) {
+ break;
}
}
+
+ *err = BAD_INDEX;
+ return NULL;
}
bool LogEvent::GetBool(size_t key, status_t* err) const {
- DimensionsValue value;
- if (!GetSimpleAtomDimensionsValueProto(key, &value)) {
- *err = BAD_INDEX;
- return 0;
- }
- const DimensionsValue* leafValue = getSingleLeafValue(&value);
- switch (leafValue->value_case()) {
- case DimensionsValue::ValueCase::kValueInt:
- return leafValue->value_int() != 0;
- case DimensionsValue::ValueCase::kValueLong:
- return leafValue->value_long() != 0;
- case DimensionsValue::ValueCase::kValueBool:
- return leafValue->value_bool();
- case DimensionsValue::ValueCase::kValueFloat:
- return leafValue->value_float() != 0;
- case DimensionsValue::ValueCase::kValueTuple:
- case DimensionsValue::ValueCase::kValueStr:
- case DimensionsValue::ValueCase::VALUE_NOT_SET: {
- *err = BAD_TYPE;
- return 0;
+ int field = getSimpleField(key);
+ for (const auto& value : mValues) {
+ if (value.mField.getField() == field) {
+ if (value.mValue.getType() == INT) {
+ return value.mValue.int_value != 0;
+ } else if (value.mValue.getType() == LONG) {
+ return value.mValue.long_value != 0;
+ } else {
+ *err = BAD_TYPE;
+ return false;
+ }
+ }
+ if ((size_t)value.mField.getPosAtDepth(0) > key) {
+ break;
}
}
+
+ *err = BAD_INDEX;
+ return false;
}
float LogEvent::GetFloat(size_t key, status_t* err) const {
- DimensionsValue value;
- if (!GetSimpleAtomDimensionsValueProto(key, &value)) {
- *err = BAD_INDEX;
- return 0;
- }
- const DimensionsValue* leafValue = getSingleLeafValue(&value);
- switch (leafValue->value_case()) {
- case DimensionsValue::ValueCase::kValueInt:
- return (float)leafValue->value_int();
- case DimensionsValue::ValueCase::kValueLong:
- return (float)leafValue->value_long();
- case DimensionsValue::ValueCase::kValueBool:
- return leafValue->value_bool() ? 1.0f : 0.0f;
- case DimensionsValue::ValueCase::kValueFloat:
- return leafValue->value_float();
- case DimensionsValue::ValueCase::kValueTuple:
- case DimensionsValue::ValueCase::kValueStr:
- case DimensionsValue::ValueCase::VALUE_NOT_SET: {
- *err = BAD_TYPE;
- return 0;
+ int field = getSimpleField(key);
+ for (const auto& value : mValues) {
+ if (value.mField.getField() == field) {
+ if (value.mValue.getType() == FLOAT) {
+ return value.mValue.float_value;
+ } else {
+ *err = BAD_TYPE;
+ return 0.0;
+ }
+ }
+ if ((size_t)value.mField.getPosAtDepth(0) > key) {
+ break;
}
}
-}
-void LogEvent::GetAtomDimensionsValueProtos(const FieldMatcher& matcher,
- std::vector<DimensionsValue> *dimensionsValues) const {
- findDimensionsValues(mFieldValueMap, matcher, dimensionsValues);
-}
-
-bool LogEvent::GetAtomDimensionsValueProto(const FieldMatcher& matcher,
- DimensionsValue* dimensionsValue) const {
- std::vector<DimensionsValue> rootDimensionsValues;
- findDimensionsValues(mFieldValueMap, matcher, &rootDimensionsValues);
- if (rootDimensionsValues.size() != 1) {
- return false;
- }
- *dimensionsValue = rootDimensionsValues.front();
- return true;
-}
-
-bool LogEvent::GetSimpleAtomDimensionsValueProto(size_t atomField,
- DimensionsValue* dimensionsValue) const {
- FieldMatcher matcher;
- buildSimpleAtomFieldMatcher(mTagId, atomField, &matcher);
- return GetAtomDimensionsValueProto(matcher, dimensionsValue);
-}
-
-DimensionsValue* LogEvent::findFieldValueOrNull(const Field& field) {
- auto it = mFieldValueMap.find(field);
- if (it == mFieldValueMap.end()) {
- return nullptr;
- }
- return &it->second;
+ *err = BAD_INDEX;
+ return 0.0;
}
string LogEvent::ToString() const {
ostringstream result;
- result << "{ " << mTimestampNs << " (" << mTagId << ")";
- for (const auto& itr : mFieldValueMap) {
- result << FieldToString(itr.first);
+ result << "{ " << mLogdTimestampNs << " " << mElapsedTimestampNs << " (" << mTagId << ")";
+ for (const auto& value : mValues) {
+ result << StringPrintf("%#x", value.mField.getField());
result << "->";
- result << DimensionsValueToString(itr.second);
+ result << value.mValue.toString();
result << " ";
}
result << " }";
@@ -433,7 +393,7 @@
}
void LogEvent::ToProto(ProtoOutputStream& protoOutput) const {
- writeFieldValueTreeToStream(getFieldValueMap(), &protoOutput);
+ writeFieldValueTreeToStream(mTagId, getValues(), &protoOutput);
}
} // namespace statsd
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index d521e09..b3084d5 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -16,7 +16,7 @@
#pragma once
-#include "field_util.h"
+#include "FieldValue.h"
#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
#include <android/util/ProtoOutputStream.h>
@@ -24,11 +24,8 @@
#include <log/log_read.h>
#include <private/android_logger.h>
#include <utils/Errors.h>
-#include <utils/JenkinsHash.h>
-#include <memory>
#include <string>
-#include <map>
#include <vector>
namespace android {
@@ -37,7 +34,6 @@
using std::string;
using std::vector;
-
/**
* Wrapper for the log_msg structure.
*/
@@ -51,14 +47,18 @@
/**
* Constructs a LogEvent with synthetic data for testing. Must call init() before reading.
*/
- explicit LogEvent(int32_t tagId, uint64_t timestampNs);
+ explicit LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedTimestampNs);
+
+ // For testing. The timestamp is used as both elapsed real time and logd timestamp.
+ explicit LogEvent(int32_t tagId, int64_t timestampNs);
~LogEvent();
/**
* Get the timestamp associated with this event.
*/
- inline uint64_t GetTimestampNs() const { return mTimestampNs; }
+ inline int64_t GetLogdTimestampNs() const { return mLogdTimestampNs; }
+ inline int64_t GetElapsedTimestampNs() const { return mElapsedTimestampNs; }
/**
* Get the tag for this event.
@@ -81,19 +81,6 @@
bool GetBool(size_t key, status_t* err) const;
float GetFloat(size_t key, status_t* err) const;
- /*
- * Get DimensionsValue proto objects from FieldMatcher.
- */
- void GetAtomDimensionsValueProtos(
- const FieldMatcher& matcher, std::vector<DimensionsValue> *dimensionsValues) const;
- bool GetAtomDimensionsValueProto(
- const FieldMatcher& matcher, DimensionsValue* dimensionsValue) const;
-
- /*
- * Get a DimensionsValue proto objects from Field.
- */
- bool GetSimpleAtomDimensionsValueProto(size_t field, DimensionsValue* dimensionsValue) const;
-
/**
* Write test data to the LogEvent. This can only be used when the LogEvent is constructed
* using LogEvent(tagId, timestampNs). You need to call init() before you can read from it.
@@ -124,20 +111,30 @@
void init();
/**
- * Set timestamp if the original timestamp is missing.
+ * Set elapsed timestamp if the original timestamp is missing.
*/
- void setTimestampNs(uint64_t timestampNs) {mTimestampNs = timestampNs;}
-
- inline int size() const {
- return mFieldValueMap.size();
+ void setElapsedTimestampNs(int64_t timestampNs) {
+ mElapsedTimestampNs = timestampNs;
}
/**
- * Returns the mutable DimensionsValue proto for the specific the field.
+ * Set the timestamp if the original logd timestamp is missing.
*/
- DimensionsValue* findFieldValueOrNull(const Field& field);
+ void setLogdWallClockTimestampNs(int64_t timestampNs) {
+ mLogdTimestampNs = timestampNs;
+ }
- inline const FieldValueMap& getFieldValueMap() const { return mFieldValueMap; }
+ inline int size() const {
+ return mValues.size();
+ }
+
+ const std::vector<FieldValue>& getValues() const {
+ return mValues;
+ }
+
+ std::vector<FieldValue>* getMutableValues() {
+ return &mValues;
+ }
private:
/**
@@ -151,14 +148,20 @@
*/
void init(android_log_context context);
- FieldValueMap mFieldValueMap;
+ // The items are naturally sorted in DFS order as we read them. this allows us to do fast
+ // matching.
+ std::vector<FieldValue> mValues;
// This field is used when statsD wants to create log event object and write fields to it. After
// calling init() function, this object would be destroyed to save memory usage.
// When the log event is created from log msg, this field is never initiated.
android_log_context mContext = NULL;
- uint64_t mTimestampNs;
+ // The timestamp set by the logd.
+ int64_t mLogdTimestampNs;
+
+ // The elapsed timestamp set by statsd log writer.
+ int64_t mElapsedTimestampNs;
int mTagId;
diff --git a/cmds/statsd/src/matchers/matcher_util.cpp b/cmds/statsd/src/matchers/matcher_util.cpp
index fae9172..944764b 100644
--- a/cmds/statsd/src/matchers/matcher_util.cpp
+++ b/cmds/statsd/src/matchers/matcher_util.cpp
@@ -13,23 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
+#define DEBUG false // STOPSHIP if true
#include "Log.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
#include "matchers/LogMatchingTracker.h"
#include "matchers/matcher_util.h"
-#include "dimension.h"
#include "stats_util.h"
-#include "field_util.h"
-
-#include <log/event_tag_map.h>
-#include <log/log_event_list.h>
-#include <log/logprint.h>
-#include <utils/Errors.h>
-
-#include <sstream>
-#include <unordered_map>
using std::ostringstream;
using std::set;
@@ -93,198 +83,224 @@
return matched;
}
-namespace {
-
-bool matchFieldSimple(const UidMap& uidMap, const FieldValueMap& fieldMap,
- const FieldValueMatcher&matcher, Field* rootField, Field* leafField);
-
-bool matchesNonRepeatedField(const UidMap& uidMap, const FieldValueMap& fieldMap,
- const FieldValueMatcher&matcher, Field* rootField, Field* leafField) {
- if (matcher.value_matcher_case() ==
- FieldValueMatcher::ValueMatcherCase::VALUE_MATCHER_NOT_SET) {
- return !fieldMap.empty() && fieldMap.begin()->first.field() == matcher.field();
- } else if (matcher.value_matcher_case() == FieldValueMatcher::ValueMatcherCase::kMatchesTuple) {
- bool allMatched = true;
- Field* newLeafField = leafField->add_child();
- for (int i = 0; allMatched && i < matcher.matches_tuple().field_value_matcher_size(); ++i) {
- const auto& childMatcher = matcher.matches_tuple().field_value_matcher(i);
- newLeafField->set_field(childMatcher.field());
- allMatched &= matchFieldSimple(uidMap, fieldMap, childMatcher, rootField, newLeafField);
- }
- leafField->clear_child();
- return allMatched;
- } else {
- auto ret = fieldMap.equal_range(*rootField);
- int found = 0;
- for (auto it = ret.first; it != ret.second; ++it) {
- found++;
- }
- // Not found.
- if (found <= 0) {
- return false;
- }
- if (found > 1) {
- ALOGE("Found multiple values for optional field.");
- return false;
- }
- bool matched = false;
- switch (matcher.value_matcher_case()) {
- case FieldValueMatcher::ValueMatcherCase::kEqBool: {
- // Logd does not support bool, it is int instead.
- matched = ((ret.first->second.value_int() > 0) == matcher.eq_bool());
- break;
- }
- case FieldValueMatcher::ValueMatcherCase::kEqString: {
- if (IsAttributionUidField(*rootField)) {
- const int uid = ret.first->second.value_int();
- std::set<string> packageNames =
- uidMap.getAppNamesFromUid(uid, true /* normalize*/);
- matched = packageNames.find(matcher.eq_string()) != packageNames.end();
- } else {
- matched = (ret.first->second.value_str() == matcher.eq_string());
- }
- break;
- }
- case FieldValueMatcher::ValueMatcherCase::kEqInt: {
- int64_t val = ret.first->second.has_value_int() ?
- ret.first->second.value_int() : ret.first->second.value_long();
- matched = (val == matcher.eq_int());
- break;
- }
- case FieldValueMatcher::ValueMatcherCase::kLtInt: {
- int64_t val = ret.first->second.has_value_int() ?
- ret.first->second.value_int() : ret.first->second.value_long();
- matched = (val < matcher.lt_int());
- break;
- }
- case FieldValueMatcher::ValueMatcherCase::kGtInt: {
- int64_t val = ret.first->second.has_value_int() ?
- ret.first->second.value_int() : ret.first->second.value_long();
- matched = (val > matcher.gt_int());
- break;
- }
- case FieldValueMatcher::ValueMatcherCase::kLtFloat: {
- matched = (ret.first->second.value_float() < matcher.lt_float());
- break;
- }
- case FieldValueMatcher::ValueMatcherCase::kGtFloat: {
- matched = (ret.first->second.value_float() > matcher.gt_float());
- break;
- }
- case FieldValueMatcher::ValueMatcherCase::kLteInt: {
- int64_t val = ret.first->second.has_value_int() ?
- ret.first->second.value_int() : ret.first->second.value_long();
- matched = (val <= matcher.lte_int());
- break;
- }
- case FieldValueMatcher::ValueMatcherCase::kGteInt: {
- int64_t val = ret.first->second.has_value_int() ?
- ret.first->second.value_int() : ret.first->second.value_long();
- matched = (val >= matcher.gte_int());
- break;
- }
- default:
- break;
- }
- return matched;
+bool tryMatchString(const UidMap& uidMap, const Field& field, const Value& value,
+ const string& str_match) {
+ if (isAttributionUidField(field, value)) {
+ int uid = value.int_value;
+ std::set<string> packageNames = uidMap.getAppNamesFromUid(uid, true /* normalize*/);
+ return packageNames.find(str_match) != packageNames.end();
+ } else if (value.getType() == STRING) {
+ return value.str_value == str_match;
}
+ return false;
}
-bool matchesRepeatedField(const UidMap& uidMap, const FieldValueMap& fieldMap,
- const FieldValueMatcher&matcher,
- Field* rootField, Field* leafField) {
- if (matcher.position() == Position::FIRST) {
- leafField->set_position_index(0);
- bool res = matchesNonRepeatedField(uidMap, fieldMap, matcher, rootField, leafField);
- leafField->clear_position_index();
- return res;
- } else {
- auto itLower = fieldMap.lower_bound(*rootField);
- if (itLower == fieldMap.end()) {
+bool matchesSimple(const UidMap& uidMap, const FieldValueMatcher& matcher,
+ const vector<FieldValue>& values, int start, int end, int depth) {
+ if (depth > 2) {
+ ALOGE("Depth > 3 not supported");
+ return false;
+ }
+
+ if (start >= end) {
+ return false;
+ }
+
+ // Filter by entry field first
+ int newStart = -1;
+ int newEnd = end;
+ // because the fields are naturally sorted in the DFS order. we can safely
+ // break when pos is larger than the one we are searching for.
+ for (int i = start; i < end; i++) {
+ int pos = values[i].mField.getPosAtDepth(depth);
+ if (pos == matcher.field()) {
+ if (newStart == -1) {
+ newStart = i;
+ }
+ newEnd = i + 1;
+ } else if (pos > matcher.field()) {
+ break;
+ }
+ }
+
+ // Now we have zoomed in to a new range
+ start = newStart;
+ end = newEnd;
+
+ if (start == -1) {
+ // No such field found.
+ return false;
+ }
+
+ vector<pair<int, int>> ranges; // the ranges are for matching ANY position
+ if (matcher.has_position()) {
+ // Repeated fields position is stored as a node in the path.
+ depth++;
+ if (depth > 2) {
return false;
}
-
- const int leafFieldNum = leafField->field();
- leafField->set_field(leafFieldNum + 1);
- auto itUpper = fieldMap.lower_bound(*rootField);
- // Resets the field number.
- leafField->set_field(leafFieldNum);
-
switch (matcher.position()) {
- case Position::LAST:
- {
- itUpper--;
- if (itUpper == fieldMap.end()) {
- return false;
- } else {
- int last_index = getPositionByReferenceField(*rootField, itUpper->first);
- if (last_index < 0) {
- return false;
- }
- leafField->set_position_index(last_index);
- bool res = matchesNonRepeatedField(uidMap, fieldMap, matcher, rootField, leafField);
- leafField->clear_position_index();
- return res;
- }
- }
- break;
- case Position::ANY:
- {
- bool matched = false;
- for (auto it = itLower; it != itUpper; ++it) {
- int index = getPositionByReferenceField(*rootField, it->first);
- if (index >= 0) {
- leafField->set_position_index(index);
- matched |= matchesNonRepeatedField(uidMap, fieldMap, matcher, rootField, leafField);
- leafField->clear_position_index();
- if (matched) {
- break;
- }
- }
+ case Position::FIRST: {
+ for (int i = start; i < end; i++) {
+ int pos = values[i].mField.getPosAtDepth(depth);
+ if (pos != 1) {
+ // Again, the log elements are stored in sorted order. so
+ // once the position is > 1, we break;
+ end = i;
+ break;
}
- return matched;
- }
- default:
- return false;
- }
- }
-
-}
-
-bool matchFieldSimple(const UidMap& uidMap, const FieldValueMap& fieldMap,
- const FieldValueMatcher&matcher, Field* rootField, Field* leafField) {
- if (!matcher.has_position()) {
- return matchesNonRepeatedField(uidMap, fieldMap, matcher, rootField, leafField);
+ }
+ ranges.push_back(std::make_pair(start, end));
+ break;
+ }
+ case Position::LAST: {
+ // move the starting index to the first LAST field at the depth.
+ for (int i = start; i < end; i++) {
+ if (values[i].mField.isLastPos(depth)) {
+ start = i;
+ break;
+ }
+ }
+ ranges.push_back(std::make_pair(start, end));
+ break;
+ }
+ case Position::ANY: {
+ // ANY means all the children matchers match in any of the sub trees, it's a match
+ newStart = start;
+ newEnd = end;
+ // Here start is guaranteed to be a valid index.
+ int currentPos = values[start].mField.getPosAtDepth(depth);
+ // Now find all sub trees ranges.
+ for (int i = start; i < end; i++) {
+ int newPos = values[i].mField.getPosAtDepth(depth);
+ if (newPos != currentPos) {
+ ranges.push_back(std::make_pair(newStart, i));
+ newStart = i;
+ currentPos = newPos;
+ }
+ }
+ ranges.push_back(std::make_pair(newStart, end));
+ break;
+ }
+ case Position::POSITION_UNKNOWN:
+ break;
+ }
} else {
- return matchesRepeatedField(uidMap, fieldMap, matcher, rootField, leafField);
+ // No position
+ ranges.push_back(std::make_pair(start, end));
+ }
+ // start and end are still pointing to the matched range.
+ switch (matcher.value_matcher_case()) {
+ case FieldValueMatcher::kMatchesTuple: {
+ ++depth;
+ // If any range matches all matchers, good.
+ for (const auto& range : ranges) {
+ bool matched = true;
+ for (const auto& subMatcher : matcher.matches_tuple().field_value_matcher()) {
+ if (!matchesSimple(uidMap, subMatcher, values, range.first, range.second,
+ depth)) {
+ matched = false;
+ break;
+ }
+ }
+ if (matched) return true;
+ }
+ return false;
+ }
+ case FieldValueMatcher::ValueMatcherCase::kEqBool: {
+ for (int i = start; i < end; i++) {
+ if ((values[i].mValue.getType() == INT &&
+ (values[i].mValue.int_value != 0) == matcher.eq_bool()) ||
+ (values[i].mValue.getType() == LONG &&
+ (values[i].mValue.long_value != 0) == matcher.eq_bool())) {
+ return true;
+ }
+ }
+ return false;
+ }
+ case FieldValueMatcher::ValueMatcherCase::kEqString: {
+ for (int i = start; i < end; i++) {
+ if (tryMatchString(uidMap, values[i].mField, values[i].mValue,
+ matcher.eq_string())) {
+ return true;
+ }
+ }
+ }
+ return false;
+ case FieldValueMatcher::ValueMatcherCase::kEqInt:
+ for (int i = start; i < end; i++) {
+ if (values[i].mValue.getType() == INT &&
+ (matcher.eq_int() == values[i].mValue.int_value)) {
+ return true;
+ }
+ }
+ return false;
+ case FieldValueMatcher::ValueMatcherCase::kLtInt:
+ for (int i = start; i < end; i++) {
+ if (values[i].mValue.getType() == INT &&
+ (values[i].mValue.int_value < matcher.lt_int())) {
+ return true;
+ }
+ }
+ return false;
+ case FieldValueMatcher::ValueMatcherCase::kGtInt:
+ for (int i = start; i < end; i++) {
+ if (values[i].mValue.getType() == INT &&
+ (values[i].mValue.int_value > matcher.gt_int())) {
+ return true;
+ }
+ }
+ return false;
+ case FieldValueMatcher::ValueMatcherCase::kLtFloat:
+ for (int i = start; i < end; i++) {
+ if (values[i].mValue.getType() == FLOAT &&
+ (values[i].mValue.float_value < matcher.lt_float())) {
+ return true;
+ }
+ }
+ return false;
+ case FieldValueMatcher::ValueMatcherCase::kGtFloat:
+ for (int i = start; i < end; i++) {
+ if (values[i].mValue.getType() == FLOAT &&
+ (values[i].mValue.float_value > matcher.gt_float())) {
+ return true;
+ }
+ }
+ return false;
+ case FieldValueMatcher::ValueMatcherCase::kLteInt:
+ for (int i = start; i < end; i++) {
+ if (values[i].mValue.getType() == INT &&
+ (values[i].mValue.int_value <= matcher.lte_int())) {
+ return true;
+ }
+ }
+ return false;
+ case FieldValueMatcher::ValueMatcherCase::kGteInt:
+ for (int i = start; i < end; i++) {
+ if (values[i].mValue.getType() == INT &&
+ (values[i].mValue.int_value >= matcher.gte_int())) {
+ return true;
+ }
+ }
+ return false;
+ default:
+ return false;
}
}
-} // namespace
-
bool matchesSimple(const UidMap& uidMap, const SimpleAtomMatcher& simpleMatcher,
const LogEvent& event) {
if (simpleMatcher.field_value_matcher_size() <= 0) {
return event.GetTagId() == simpleMatcher.atom_id();
}
- Field root_field;
- root_field.set_field(simpleMatcher.atom_id());
- FieldValueMatcher root_field_matcher;
- root_field_matcher.set_field(simpleMatcher.atom_id());
- for (int i = 0; i < simpleMatcher.field_value_matcher_size(); i++) {
- *root_field_matcher.mutable_matches_tuple()->add_field_value_matcher() =
- simpleMatcher.field_value_matcher(i);
+ for (const auto& matcher : simpleMatcher.field_value_matcher()) {
+ if (!matchesSimple(uidMap, matcher, event.getValues(), 0, event.getValues().size(), 0)) {
+ return false;
+ }
}
- return matchFieldSimple(
- uidMap, event.getFieldValueMap(), root_field_matcher, &root_field, &root_field);
+ return true;
}
-void getDimensionKeys(const LogEvent& event, const FieldMatcher& matcher,
- std::vector<DimensionsValue> *dimensionKeys) {
- if (matcher.has_field()) {
- findDimensionsValues(event.getFieldValueMap(), matcher, dimensionKeys);
- }
-}
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/matchers/matcher_util.h b/cmds/statsd/src/matchers/matcher_util.h
index a45a9fb..872cd8e 100644
--- a/cmds/statsd/src/matchers/matcher_util.h
+++ b/cmds/statsd/src/matchers/matcher_util.h
@@ -45,9 +45,6 @@
bool matchesSimple(const UidMap& uidMap,
const SimpleAtomMatcher& simpleMatcher, const LogEvent& wrapper);
-void getDimensionKeys(const LogEvent& event, const FieldMatcher& matcher,
- std::vector<DimensionsValue> *dimensionKeys);
-
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index 5a042b6..af2e362 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -21,7 +21,6 @@
#include "guardrail/StatsdStats.h"
#include "stats_util.h"
#include "stats_log_util.h"
-#include "dimension.h"
#include <limits.h>
#include <stdlib.h>
@@ -53,8 +52,8 @@
const int FIELD_ID_DIMENSION_IN_CONDITION = 2;
const int FIELD_ID_BUCKET_INFO = 3;
// for CountBucketInfo
-const int FIELD_ID_START_BUCKET_NANOS = 1;
-const int FIELD_ID_END_BUCKET_NANOS = 2;
+const int FIELD_ID_START_BUCKET_ELAPSED_NANOS = 1;
+const int FIELD_ID_END_BUCKET_ELAPSED_NANOS = 2;
const int FIELD_ID_COUNT = 3;
CountMetricProducer::CountMetricProducer(const ConfigKey& key, const CountMetric& metric,
@@ -64,21 +63,32 @@
: MetricProducer(metric.id(), key, startTimeNs, conditionIndex, wizard) {
// TODO: evaluate initial conditions. and set mConditionMet.
if (metric.has_bucket()) {
- mBucketSizeNs = TimeUnitToBucketSizeInMillis(metric.bucket()) * 1000000;
+ mBucketSizeNs =
+ TimeUnitToBucketSizeInMillisGuardrailed(key.GetUid(), metric.bucket()) * 1000000;
} else {
mBucketSizeNs = LLONG_MAX;
}
- // TODO: use UidMap if uid->pkg_name is required
- mDimensionsInWhat = metric.dimensions_in_what();
- mDimensionsInCondition = metric.dimensions_in_condition();
+ if (metric.has_dimensions_in_what()) {
+ translateFieldMatcher(metric.dimensions_in_what(), &mDimensionsInWhat);
+ }
+
+ if (metric.has_dimensions_in_condition()) {
+ translateFieldMatcher(metric.dimensions_in_condition(), &mDimensionsInCondition);
+ }
if (metric.links().size() > 0) {
- mConditionLinks.insert(mConditionLinks.begin(), metric.links().begin(),
- metric.links().end());
+ for (const auto& link : metric.links()) {
+ Metric2Condition mc;
+ mc.conditionId = link.condition();
+ translateFieldMatcher(link.fields_in_what(), &mc.metricFields);
+ translateFieldMatcher(link.fields_in_condition(), &mc.conditionFields);
+ mMetric2ConditionLinks.push_back(mc);
+ }
+ mConditionSliced = true;
}
- mConditionSliced = (metric.links().size() > 0)||
- (mDimensionsInCondition.has_field() && mDimensionsInCondition.child_size() > 0);
+
+ mConditionSliced = (metric.links().size() > 0) || (mDimensionsInCondition.size() > 0);
VLOG("metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(),
(long long)mBucketSizeNs, (long long)mStartTimeNs);
@@ -92,38 +102,15 @@
VLOG("Metric %lld onSlicedConditionMayChange", (long long)mMetricId);
}
-void CountMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs, StatsLogReport* report) {
- flushIfNeededLocked(dumpTimeNs);
- report->set_metric_id(mMetricId);
-
- auto count_metrics = report->mutable_count_metrics();
- for (const auto& counter : mPastBuckets) {
- CountMetricData* metricData = count_metrics->add_data();
- *metricData->mutable_dimensions_in_what() =
- counter.first.getDimensionKeyInWhat().getDimensionsValue();
- *metricData->mutable_dimensions_in_condition() =
- counter.first.getDimensionKeyInCondition().getDimensionsValue();
- for (const auto& bucket : counter.second) {
- CountBucketInfo* bucketInfo = metricData->add_bucket_info();
- bucketInfo->set_start_bucket_nanos(bucket.mBucketStartNs);
- bucketInfo->set_end_bucket_nanos(bucket.mBucketEndNs);
- bucketInfo->set_count(bucket.mCount);
- }
- }
-}
-
void CountMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs,
ProtoOutputStream* protoOutput) {
flushIfNeededLocked(dumpTimeNs);
if (mPastBuckets.empty()) {
return;
}
-
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
long long protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_COUNT_METRICS);
- VLOG("metric %lld dump report now...",(long long)mMetricId);
-
for (const auto& counter : mPastBuckets) {
const MetricDimensionKey& dimensionKey = counter.first;
VLOG(" dimension key %s", dimensionKey.c_str());
@@ -134,25 +121,24 @@
// First fill dimension.
long long dimensionInWhatToken = protoOutput->start(
FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_WHAT);
- writeDimensionsValueProtoToStream(
- dimensionKey.getDimensionKeyInWhat().getDimensionsValue(), protoOutput);
+ writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), protoOutput);
protoOutput->end(dimensionInWhatToken);
if (dimensionKey.hasDimensionKeyInCondition()) {
long long dimensionInConditionToken = protoOutput->start(
FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_CONDITION);
- writeDimensionsValueProtoToStream(
- dimensionKey.getDimensionKeyInCondition().getDimensionsValue(), protoOutput);
+ writeDimensionToProto(dimensionKey.getDimensionKeyInCondition(), protoOutput);
protoOutput->end(dimensionInConditionToken);
}
// Then fill bucket_info (CountBucketInfo).
+
for (const auto& bucket : counter.second) {
long long bucketInfoToken = protoOutput->start(
FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_BUCKET_INFO);
- protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_NANOS,
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_ELAPSED_NANOS,
(long long)bucket.mBucketStartNs);
- protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_NANOS,
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_ELAPSED_NANOS,
(long long)bucket.mBucketEndNs);
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_COUNT, (long long)bucket.mCount);
protoOutput->end(bucketInfoToken);
@@ -199,8 +185,7 @@
const size_t matcherIndex, const MetricDimensionKey& eventKey,
const ConditionKey& conditionKey, bool condition,
const LogEvent& event) {
- uint64_t eventTimeNs = event.GetTimestampNs();
-
+ uint64_t eventTimeNs = event.GetElapsedTimestampNs();
flushIfNeededLocked(eventTimeNs);
if (condition == false) {
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
index b06c77b..0c4291d 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -57,7 +57,6 @@
private:
void onDumpReportLocked(const uint64_t dumpTimeNs,
android::util::ProtoOutputStream* protoOutput) override;
- void onDumpReportLocked(const uint64_t dumpTimeNs, StatsLogReport* report) override;
// Internal interface to handle condition change.
void onConditionChangedLocked(const bool conditionMet, const uint64_t eventTime) override;
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index 65cbc4a..3b7936d 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -21,7 +21,6 @@
#include "guardrail/StatsdStats.h"
#include "stats_util.h"
#include "stats_log_util.h"
-#include "dimension.h"
#include <limits.h>
#include <stdlib.h>
@@ -52,8 +51,8 @@
const int FIELD_ID_DIMENSION_IN_CONDITION = 2;
const int FIELD_ID_BUCKET_INFO = 3;
// for DurationBucketInfo
-const int FIELD_ID_START_BUCKET_NANOS = 1;
-const int FIELD_ID_END_BUCKET_NANOS = 2;
+const int FIELD_ID_START_BUCKET_ELAPSED_NANOS = 1;
+const int FIELD_ID_END_BUCKET_ELAPSED_NANOS = 2;
const int FIELD_ID_DURATION = 3;
DurationMetricProducer::DurationMetricProducer(const ConfigKey& key, const DurationMetric& metric,
@@ -68,27 +67,39 @@
mStartIndex(startIndex),
mStopIndex(stopIndex),
mStopAllIndex(stopAllIndex),
- mNested(nesting),
- mInternalDimensions(internalDimensions) {
+ mNested(nesting) {
// TODO: The following boiler plate code appears in all MetricProducers, but we can't abstract
// them in the base class, because the proto generated CountMetric, and DurationMetric are
// not related. Maybe we should add a template in the future??
if (metric.has_bucket()) {
- mBucketSizeNs = TimeUnitToBucketSizeInMillis(metric.bucket()) * 1000000;
+ mBucketSizeNs =
+ TimeUnitToBucketSizeInMillisGuardrailed(key.GetUid(), metric.bucket()) * 1000000;
} else {
mBucketSizeNs = LLONG_MAX;
}
- // TODO: use UidMap if uid->pkg_name is required
- mDimensionsInWhat = metric.dimensions_in_what();
- mDimensionsInCondition = metric.dimensions_in_condition();
+ if (metric.has_dimensions_in_what()) {
+ translateFieldMatcher(metric.dimensions_in_what(), &mDimensionsInWhat);
+ }
+
+ if (internalDimensions.has_field()) {
+ translateFieldMatcher(internalDimensions, &mInternalDimensions);
+ }
+
+ if (metric.has_dimensions_in_condition()) {
+ translateFieldMatcher(metric.dimensions_in_condition(), &mDimensionsInCondition);
+ }
if (metric.links().size() > 0) {
- mConditionLinks.insert(mConditionLinks.begin(), metric.links().begin(),
- metric.links().end());
+ for (const auto& link : metric.links()) {
+ Metric2Condition mc;
+ mc.conditionId = link.condition();
+ translateFieldMatcher(link.fields_in_what(), &mc.metricFields);
+ translateFieldMatcher(link.fields_in_condition(), &mc.conditionFields);
+ mMetric2ConditionLinks.push_back(mc);
+ }
}
- mConditionSliced = (metric.links().size() > 0)||
- (mDimensionsInCondition.has_field() && mDimensionsInCondition.child_size() > 0);
+ mConditionSliced = (metric.links().size() > 0) || (mDimensionsInCondition.size() > 0);
VLOG("metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(),
(long long)mBucketSizeNs, (long long)mStartTimeNs);
@@ -140,10 +151,9 @@
std::unordered_set<HashableDimensionKey> conditionDimensionsKeySet;
- ConditionState conditionState = mWizard->getMetConditionDimension(
- mConditionTrackerIndex, mDimensionsInCondition, &conditionDimensionsKeySet);
+ mWizard->getMetConditionDimension(mConditionTrackerIndex, mDimensionsInCondition,
+ &conditionDimensionsKeySet);
- bool condition = (conditionState == ConditionState::kTrue);
for (auto& pair : mCurrentSlicedDurationTrackerMap) {
conditionDimensionsKeySet.erase(pair.first.getDimensionKeyInCondition());
}
@@ -174,37 +184,18 @@
}
}
-void DurationMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs, StatsLogReport* report) {
- flushIfNeededLocked(dumpTimeNs);
- report->set_metric_id(mMetricId);
-
- auto duration_metrics = report->mutable_duration_metrics();
- for (const auto& pair : mPastBuckets) {
- DurationMetricData* metricData = duration_metrics->add_data();
- *metricData->mutable_dimensions_in_what() =
- pair.first.getDimensionKeyInWhat().getDimensionsValue();
- *metricData->mutable_dimensions_in_condition() =
- pair.first.getDimensionKeyInCondition().getDimensionsValue();
- for (const auto& bucket : pair.second) {
- auto bucketInfo = metricData->add_bucket_info();
- bucketInfo->set_start_bucket_nanos(bucket.mBucketStartNs);
- bucketInfo->set_end_bucket_nanos(bucket.mBucketEndNs);
- bucketInfo->set_duration_nanos(bucket.mDuration);
- }
- }
-}
-
void DurationMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs,
ProtoOutputStream* protoOutput) {
flushIfNeededLocked(dumpTimeNs);
if (mPastBuckets.empty()) {
+ VLOG(" Duration metric, empty return");
return;
}
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
long long protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_DURATION_METRICS);
- VLOG("metric %lld dump report now...", (long long)mMetricId);
+ VLOG("Duration metric %lld dump report now...", (long long)mMetricId);
for (const auto& pair : mPastBuckets) {
const MetricDimensionKey& dimensionKey = pair.first;
@@ -216,15 +207,13 @@
// First fill dimension.
long long dimensionToken = protoOutput->start(
FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_WHAT);
- writeDimensionsValueProtoToStream(
- dimensionKey.getDimensionKeyInWhat().getDimensionsValue(), protoOutput);
+ writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), protoOutput);
protoOutput->end(dimensionToken);
if (dimensionKey.hasDimensionKeyInCondition()) {
long long dimensionInConditionToken = protoOutput->start(
FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_CONDITION);
- writeDimensionsValueProtoToStream(
- dimensionKey.getDimensionKeyInCondition().getDimensionsValue(), protoOutput);
+ writeDimensionToProto(dimensionKey.getDimensionKeyInCondition(), protoOutput);
protoOutput->end(dimensionInConditionToken);
}
@@ -232,9 +221,9 @@
for (const auto& bucket : pair.second) {
long long bucketInfoToken = protoOutput->start(
FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_BUCKET_INFO);
- protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_NANOS,
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_ELAPSED_NANOS,
(long long)bucket.mBucketStartNs);
- protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_NANOS,
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_ELAPSED_NANOS,
(long long)bucket.mBucketEndNs);
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_DURATION, (long long)bucket.mDuration);
protoOutput->end(bucketInfoToken);
@@ -321,11 +310,11 @@
const size_t matcherIndex, const MetricDimensionKey& eventKey,
const ConditionKey& conditionKeys, bool condition,
const LogEvent& event) {
- flushIfNeededLocked(event.GetTimestampNs());
+ flushIfNeededLocked(event.GetElapsedTimestampNs());
if (matcherIndex == mStopAllIndex) {
for (auto& pair : mCurrentSlicedDurationTrackerMap) {
- pair.second->noteStopAll(event.GetTimestampNs());
+ pair.second->noteStopAll(event.GetElapsedTimestampNs());
}
return;
}
@@ -339,23 +328,21 @@
auto it = mCurrentSlicedDurationTrackerMap.find(eventKey);
- std::vector<DimensionsValue> values;
- getDimensionKeys(event, mInternalDimensions, &values);
+ std::vector<HashableDimensionKey> values;
+ filterValues(mInternalDimensions, event.getValues(), &values);
if (values.empty()) {
if (matcherIndex == mStartIndex) {
it->second->noteStart(DEFAULT_DIMENSION_KEY, condition,
- event.GetTimestampNs(), conditionKeys);
+ event.GetElapsedTimestampNs(), conditionKeys);
} else if (matcherIndex == mStopIndex) {
- it->second->noteStop(DEFAULT_DIMENSION_KEY, event.GetTimestampNs(), false);
+ it->second->noteStop(DEFAULT_DIMENSION_KEY, event.GetElapsedTimestampNs(), false);
}
} else {
- for (const DimensionsValue& value : values) {
+ for (const auto& value : values) {
if (matcherIndex == mStartIndex) {
- it->second->noteStart(
- HashableDimensionKey(value), condition, event.GetTimestampNs(), conditionKeys);
+ it->second->noteStart(value, condition, event.GetElapsedTimestampNs(), conditionKeys);
} else if (matcherIndex == mStopIndex) {
- it->second->noteStop(
- HashableDimensionKey(value), event.GetTimestampNs(), false);
+ it->second->noteStop(value, event.GetElapsedTimestampNs(), false);
}
}
}
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index a496016..5f29281 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -57,7 +57,6 @@
private:
void onDumpReportLocked(const uint64_t dumpTimeNs,
android::util::ProtoOutputStream* protoOutput) override;
- void onDumpReportLocked(const uint64_t dumpTimeNs, StatsLogReport* report) override;
// Internal interface to handle condition change.
void onConditionChangedLocked(const bool conditionMet, const uint64_t eventTime) override;
@@ -90,7 +89,7 @@
const bool mNested;
// The dimension from the atom predicate. e.g., uid, wakelock name.
- const FieldMatcher mInternalDimensions;
+ vector<Matcher> mInternalDimensions;
// Save the past buckets and we can clear when the StatsLogReport is dumped.
// TODO: Add a lock to mPastBuckets.
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
index 936a2ef1..2585aa3 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -19,6 +19,7 @@
#include "EventMetricProducer.h"
#include "stats_util.h"
+#include "stats_log_util.h"
#include <limits.h>
#include <stdlib.h>
@@ -46,8 +47,9 @@
// for EventMetricDataWrapper
const int FIELD_ID_DATA = 1;
// for EventMetricData
-const int FIELD_ID_TIMESTAMP_NANOS = 1;
+const int FIELD_ID_ELAPSED_TIMESTAMP_NANOS = 1;
const int FIELD_ID_ATOMS = 2;
+const int FIELD_ID_WALL_CLOCK_TIMESTAMP_NANOS = 3;
EventMetricProducer::EventMetricProducer(const ConfigKey& key, const EventMetric& metric,
const int conditionIndex,
@@ -55,8 +57,13 @@
const uint64_t startTimeNs)
: MetricProducer(metric.id(), key, startTimeNs, conditionIndex, wizard) {
if (metric.links().size() > 0) {
- mConditionLinks.insert(mConditionLinks.begin(), metric.links().begin(),
- metric.links().end());
+ for (const auto& link : metric.links()) {
+ Metric2Condition mc;
+ mc.conditionId = link.condition();
+ translateFieldMatcher(link.fields_in_what(), &mc.metricFields);
+ translateFieldMatcher(link.fields_in_condition(), &mc.conditionFields);
+ mMetric2ConditionLinks.push_back(mc);
+ }
mConditionSliced = true;
}
mProto = std::make_unique<ProtoOutputStream>();
@@ -88,10 +95,6 @@
return buffer;
}
-void EventMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs, StatsLogReport* report) {
-
-}
-
void EventMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs,
ProtoOutputStream* protoOutput) {
if (mProto->size() <= 0) {
@@ -126,9 +129,12 @@
long long wrapperToken =
mProto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DATA);
- mProto->write(FIELD_TYPE_INT64 | FIELD_ID_TIMESTAMP_NANOS, (long long)event.GetTimestampNs());
+ mProto->write(FIELD_TYPE_INT64 | FIELD_ID_ELAPSED_TIMESTAMP_NANOS,
+ (long long)event.GetElapsedTimestampNs());
long long eventToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_ATOMS);
event.ToProto(*mProto);
+ mProto->write(FIELD_TYPE_INT64 | FIELD_ID_WALL_CLOCK_TIMESTAMP_NANOS,
+ (long long)getWallClockNs());
mProto->end(eventToken);
mProto->end(wrapperToken);
}
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.h b/cmds/statsd/src/metrics/EventMetricProducer.h
index 394ed23..3f2c5a5 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.h
+++ b/cmds/statsd/src/metrics/EventMetricProducer.h
@@ -48,7 +48,6 @@
void onDumpReportLocked(const uint64_t dumpTimeNs,
android::util::ProtoOutputStream* protoOutput) override;
- void onDumpReportLocked(const uint64_t dumpTimeNs, StatsLogReport* report) override;
// Internal interface to handle condition change.
void onConditionChangedLocked(const bool conditionMet, const uint64_t eventTime) override;
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index 62ee6ef..0daa506 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -19,7 +19,6 @@
#include "GaugeMetricProducer.h"
#include "guardrail/StatsdStats.h"
-#include "dimension.h"
#include "stats_log_util.h"
#include <cutils/log.h>
@@ -53,10 +52,10 @@
const int FIELD_ID_DIMENSION_IN_CONDITION = 2;
const int FIELD_ID_BUCKET_INFO = 3;
// for GaugeBucketInfo
-const int FIELD_ID_START_BUCKET_NANOS = 1;
-const int FIELD_ID_END_BUCKET_NANOS = 2;
+const int FIELD_ID_START_BUCKET_ELAPSED_NANOS = 1;
+const int FIELD_ID_END_BUCKET_ELAPSED_NANOS = 2;
const int FIELD_ID_ATOM = 3;
-const int FIELD_ID_TIMESTAMP = 4;
+const int FIELD_ID_ELAPSED_ATOM_TIMESTAMP = 4;
GaugeMetricProducer::GaugeMetricProducer(const ConfigKey& key, const GaugeMetric& metric,
const int conditionIndex,
@@ -70,25 +69,36 @@
mCurrentSlicedBucketForAnomaly = std::make_shared<DimToValMap>();
int64_t bucketSizeMills = 0;
if (metric.has_bucket()) {
- bucketSizeMills = TimeUnitToBucketSizeInMillis(metric.bucket());
+ bucketSizeMills = TimeUnitToBucketSizeInMillisGuardrailed(key.GetUid(), metric.bucket());
} else {
bucketSizeMills = TimeUnitToBucketSizeInMillis(ONE_HOUR);
}
mBucketSizeNs = bucketSizeMills * 1000000;
mSamplingType = metric.sampling_type();
- mFieldFilter = metric.gauge_fields_filter();
+ if (!metric.gauge_fields_filter().include_all()) {
+ translateFieldMatcher(metric.gauge_fields_filter().fields(), &mFieldMatchers);
+ }
// TODO: use UidMap if uid->pkg_name is required
- mDimensionsInWhat = metric.dimensions_in_what();
- mDimensionsInCondition = metric.dimensions_in_condition();
+ if (metric.has_dimensions_in_what()) {
+ translateFieldMatcher(metric.dimensions_in_what(), &mDimensionsInWhat);
+ }
+
+ if (metric.has_dimensions_in_condition()) {
+ translateFieldMatcher(metric.dimensions_in_condition(), &mDimensionsInCondition);
+ }
if (metric.links().size() > 0) {
- mConditionLinks.insert(mConditionLinks.begin(), metric.links().begin(),
- metric.links().end());
+ for (const auto& link : metric.links()) {
+ Metric2Condition mc;
+ mc.conditionId = link.condition();
+ translateFieldMatcher(link.fields_in_what(), &mc.metricFields);
+ translateFieldMatcher(link.fields_in_condition(), &mc.conditionFields);
+ mMetric2ConditionLinks.push_back(mc);
+ }
}
- mConditionSliced = (metric.links().size() > 0)||
- (mDimensionsInCondition.has_field() && mDimensionsInCondition.child_size() > 0);
+ mConditionSliced = (metric.links().size() > 0) || (mDimensionsInCondition.size() > 0);
// Kicks off the puller immediately.
if (mPullTagId != -1 && mSamplingType == GaugeMetric::RANDOM_ONE_SAMPLE) {
@@ -115,13 +125,6 @@
}
}
-void GaugeMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs, StatsLogReport* report) {
- flushIfNeededLocked(dumpTimeNs);
- ProtoOutputStream pbOutput;
- onDumpReportLocked(dumpTimeNs, &pbOutput);
- parseProtoOutputStream(pbOutput, report);
-}
-
void GaugeMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs,
ProtoOutputStream* protoOutput) {
VLOG("gauge metric %lld report now...", (long long)mMetricId);
@@ -144,15 +147,13 @@
// First fill dimension.
long long dimensionToken = protoOutput->start(
FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_WHAT);
- writeDimensionsValueProtoToStream(
- dimensionKey.getDimensionKeyInWhat().getDimensionsValue(), protoOutput);
+ writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), protoOutput);
protoOutput->end(dimensionToken);
if (dimensionKey.hasDimensionKeyInCondition()) {
long long dimensionInConditionToken = protoOutput->start(
FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_CONDITION);
- writeDimensionsValueProtoToStream(
- dimensionKey.getDimensionKeyInCondition().getDimensionsValue(), protoOutput);
+ writeDimensionToProto(dimensionKey.getDimensionKeyInCondition(), protoOutput);
protoOutput->end(dimensionInConditionToken);
}
@@ -160,22 +161,23 @@
for (const auto& bucket : pair.second) {
long long bucketInfoToken = protoOutput->start(
FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_BUCKET_INFO);
- protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_NANOS,
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_ELAPSED_NANOS,
(long long)bucket.mBucketStartNs);
- protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_NANOS,
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_ELAPSED_NANOS,
(long long)bucket.mBucketEndNs);
if (!bucket.mGaugeAtoms.empty()) {
long long atomsToken =
protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_ATOM);
for (const auto& atom : bucket.mGaugeAtoms) {
- writeFieldValueTreeToStream(*atom.mFields, protoOutput);
+ writeFieldValueTreeToStream(mTagId, *(atom.mFields), protoOutput);
}
protoOutput->end(atomsToken);
for (const auto& atom : bucket.mGaugeAtoms) {
- protoOutput->write(FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED | FIELD_ID_TIMESTAMP,
- (long long)atom.mTimestamps);
+ protoOutput->write(
+ FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED | FIELD_ID_ELAPSED_ATOM_TIMESTAMP,
+ (long long)atom.mTimestamps);
}
}
protoOutput->end(bucketInfoToken);
@@ -246,13 +248,14 @@
VLOG("Metric %lld onSlicedConditionMayChange", (long long)mMetricId);
}
-std::shared_ptr<FieldValueMap> GaugeMetricProducer::getGaugeFields(const LogEvent& event) {
- std::shared_ptr<FieldValueMap> gaugeFields =
- std::make_shared<FieldValueMap>(event.getFieldValueMap());
- if (!mFieldFilter.include_all()) {
- filterFields(mFieldFilter.fields(), gaugeFields.get());
+std::shared_ptr<vector<FieldValue>> GaugeMetricProducer::getGaugeFields(const LogEvent& event) {
+ if (mFieldMatchers.size() > 0) {
+ std::shared_ptr<vector<FieldValue>> gaugeFields = std::make_shared<vector<FieldValue>>();
+ filterGaugeValues(mFieldMatchers, event.getValues(), gaugeFields.get());
+ return gaugeFields;
+ } else {
+ return std::make_shared<vector<FieldValue>>(event.getValues());
}
- return gaugeFields;
}
void GaugeMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& allData) {
@@ -291,7 +294,8 @@
if (condition == false) {
return;
}
- uint64_t eventTimeNs = event.GetTimestampNs();
+ uint64_t eventTimeNs = event.GetElapsedTimestampNs();
+ mTagId = event.GetTagId();
if (eventTimeNs < mCurrentBucketStartTimeNs) {
VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
(long long)mCurrentBucketStartTimeNs);
@@ -308,20 +312,18 @@
if (hitGuardRailLocked(eventKey)) {
return;
}
- GaugeAtom gaugeAtom;
- gaugeAtom.mFields = getGaugeFields(event);
- gaugeAtom.mTimestamps = eventTimeNs;
+ GaugeAtom gaugeAtom(getGaugeFields(event), eventTimeNs);
(*mCurrentSlicedBucket)[eventKey].push_back(gaugeAtom);
// Anomaly detection on gauge metric only works when there is one numeric
// field specified.
if (mAnomalyTrackers.size() > 0) {
if (gaugeAtom.mFields->size() == 1) {
- const DimensionsValue& dimensionsValue = gaugeAtom.mFields->begin()->second;
+ const Value& value = gaugeAtom.mFields->begin()->mValue;
long gaugeVal = 0;
- if (dimensionsValue.has_value_int()) {
- gaugeVal = (long)dimensionsValue.value_int();
- } else if (dimensionsValue.has_value_long()) {
- gaugeVal = dimensionsValue.value_long();
+ if (value.getType() == INT) {
+ gaugeVal = (long)value.int_value;
+ } else if (value.getType() == LONG) {
+ gaugeVal = value.long_value;
}
for (auto& tracker : mAnomalyTrackers) {
tracker->detectAndDeclareAnomaly(eventTimeNs, mCurrentBucketNum, eventKey,
@@ -332,17 +334,16 @@
}
void GaugeMetricProducer::updateCurrentSlicedBucketForAnomaly() {
- status_t err = NO_ERROR;
for (const auto& slice : *mCurrentSlicedBucket) {
- if (slice.second.empty() || slice.second.front().mFields->empty()) {
+ if (slice.second.empty()) {
continue;
}
- const DimensionsValue& dimensionsValue = slice.second.front().mFields->begin()->second;
+ const Value& value = slice.second.front().mFields->front().mValue;
long gaugeVal = 0;
- if (dimensionsValue.has_value_int()) {
- gaugeVal = (long)dimensionsValue.value_int();
- } else if (dimensionsValue.has_value_long()) {
- gaugeVal = dimensionsValue.value_long();
+ if (value.getType() == INT) {
+ gaugeVal = (long)value.int_value;
+ } else if (value.getType() == LONG) {
+ gaugeVal = value.long_value;
}
(*mCurrentSlicedBucketForAnomaly)[slice.first] = gaugeVal;
}
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h
index d5d34be..c3ae6ce 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.h
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h
@@ -33,7 +33,10 @@
namespace statsd {
struct GaugeAtom {
- std::shared_ptr<FieldValueMap> mFields;
+ GaugeAtom(std::shared_ptr<vector<FieldValue>> fields, int64_t timeNs)
+ : mFields(fields), mTimestamps(timeNs) {
+ }
+ std::shared_ptr<vector<FieldValue>> mFields;
int64_t mTimestamps;
};
@@ -87,7 +90,6 @@
private:
void onDumpReportLocked(const uint64_t dumpTimeNs,
android::util::ProtoOutputStream* protoOutput) override;
- void onDumpReportLocked(const uint64_t dumpTimeNs, StatsLogReport* report) override;
// for testing
GaugeMetricProducer(const ConfigKey& key, const GaugeMetric& gaugeMetric,
@@ -113,6 +115,8 @@
void pullLocked();
+ int mTagId;
+
std::shared_ptr<StatsPullerManager> mStatsPullerManager;
// tagId for pulled data. -1 if this is not pulled
const int mPullTagId;
@@ -133,12 +137,12 @@
void updateCurrentSlicedBucketForAnomaly();
// Whitelist of fields to report. Empty means all are reported.
- FieldFilter mFieldFilter;
+ std::vector<Matcher> mFieldMatchers;
GaugeMetric::SamplingType mSamplingType;
// apply a whitelist on the original input
- std::shared_ptr<FieldValueMap> getGaugeFields(const LogEvent& event);
+ std::shared_ptr<vector<FieldValue>> getGaugeFields(const LogEvent& event);
// Util function to check whether the specified dimension hits the guardrail.
bool hitGuardRailLocked(const MetricDimensionKey& newKey);
diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp
index 85e655b..f3307dc 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -13,9 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include "MetricProducer.h"
-#include "dimension.h"
+#define DEBUG true // STOPSHIP if true
+#include "Log.h"
+#include "MetricProducer.h"
namespace android {
namespace os {
@@ -24,7 +25,7 @@
using std::map;
void MetricProducer::onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event) {
- uint64_t eventTimeNs = event.GetTimestampNs();
+ uint64_t eventTimeNs = event.GetElapsedTimestampNs();
// this is old event, maybe statsd restarted?
if (eventTimeNs < mStartTimeNs) {
return;
@@ -35,9 +36,10 @@
std::unordered_set<HashableDimensionKey> dimensionKeysInCondition;
if (mConditionSliced) {
- for (const auto& link : mConditionLinks) {
- getDimensionKeysForCondition(event, link, &conditionKey[link.condition()]);
+ for (const auto& link : mMetric2ConditionLinks) {
+ getDimensionForCondition(event, link, &conditionKey[link.conditionId]);
}
+
auto conditionState =
mWizard->query(mConditionTrackerIndex, conditionKey, mDimensionsInCondition,
&dimensionKeysInCondition);
@@ -46,20 +48,19 @@
condition = mCondition;
}
- vector<DimensionsValue> dimensionInWhatValues;
- if (mDimensionsInWhat.has_field() && mDimensionsInWhat.child_size() > 0) {
- getDimensionKeys(event, mDimensionsInWhat, &dimensionInWhatValues);
+ vector<HashableDimensionKey> dimensionInWhatValues;
+ if (mDimensionsInWhat.size() > 0) {
+ filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhatValues);
}
if (dimensionInWhatValues.empty() && dimensionKeysInCondition.empty()) {
onMatchedLogEventInternalLocked(
matcherIndex, DEFAULT_METRIC_DIMENSION_KEY, conditionKey, condition, event);
} else if (dimensionKeysInCondition.empty()) {
- for (const DimensionsValue& whatValue : dimensionInWhatValues) {
- onMatchedLogEventInternalLocked(
- matcherIndex,
- MetricDimensionKey(HashableDimensionKey(whatValue), DEFAULT_DIMENSION_KEY),
- conditionKey, condition, event);
+ for (const HashableDimensionKey& whatValue : dimensionInWhatValues) {
+ onMatchedLogEventInternalLocked(matcherIndex,
+ MetricDimensionKey(whatValue, DEFAULT_DIMENSION_KEY),
+ conditionKey, condition, event);
}
} else if (dimensionInWhatValues.empty()) {
for (const auto& conditionDimensionKey : dimensionKeysInCondition) {
@@ -69,12 +70,11 @@
conditionKey, condition, event);
}
} else {
- for (const DimensionsValue& whatValue : dimensionInWhatValues) {
+ for (const auto& whatValue : dimensionInWhatValues) {
for (const auto& conditionDimensionKey : dimensionKeysInCondition) {
onMatchedLogEventInternalLocked(
- matcherIndex,
- MetricDimensionKey(HashableDimensionKey(whatValue), conditionDimensionKey),
- conditionKey, condition, event);
+ matcherIndex, MetricDimensionKey(whatValue, conditionDimensionKey),
+ conditionKey, condition, event);
}
}
}
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 542dd8a..8663e5e 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -19,6 +19,7 @@
#include <shared_mutex>
+#include "HashableDimensionKey.h"
#include "anomaly/AnomalyTracker.h"
#include "condition/ConditionWizard.h"
#include "config/ConfigKey.h"
@@ -109,11 +110,6 @@
std::lock_guard<std::mutex> lock(mMutex);
return onDumpReportLocked(dumpTimeNs, protoOutput);
}
- // This method does not clear the past buckets.
- void onDumpReport(const uint64_t dumpTimeNs, StatsLogReport* report) {
- std::lock_guard<std::mutex> lock(mMutex);
- return onDumpReportLocked(dumpTimeNs, report);
- }
void dumpStates(FILE* out, bool verbose) const {
std::lock_guard<std::mutex> lock(mMutex);
@@ -127,6 +123,7 @@
return byteSizeLocked();
}
+ /* If alert is valid, adds an AnomalyTracker and returns it. If invalid, returns nullptr. */
virtual sp<AnomalyTracker> addAnomalyTracker(const Alert &alert) {
std::lock_guard<std::mutex> lock(mMutex);
sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, mConfigKey);
@@ -141,6 +138,11 @@
return mBucketSizeNs;
}
+ // Only needed for unit-testing to override guardrail.
+ void setBucketSize(int64_t bucketSize) {
+ mBucketSizeNs = bucketSize;
+ }
+
inline const int64_t& getMetricId() {
return mMetricId;
}
@@ -150,7 +152,6 @@
virtual void onSlicedConditionMayChangeLocked(const uint64_t eventTime) = 0;
virtual void onDumpReportLocked(const uint64_t dumpTimeNs,
android::util::ProtoOutputStream* protoOutput) = 0;
- virtual void onDumpReportLocked(const uint64_t dumpTimeNs, StatsLogReport* report) = 0;
virtual size_t byteSizeLocked() const = 0;
virtual void dumpStatesLocked(FILE* out, bool verbose) const = 0;
@@ -203,10 +204,10 @@
int mConditionTrackerIndex;
- FieldMatcher mDimensionsInWhat; // The dimensions_in_what defined in statsd_config
- FieldMatcher mDimensionsInCondition; // The dimensions_in_condition defined in statsd_config
+ vector<Matcher> mDimensionsInWhat; // The dimensions_in_what defined in statsd_config
+ vector<Matcher> mDimensionsInCondition; // The dimensions_in_condition defined in statsd_config
- std::vector<MetricConditionLink> mConditionLinks;
+ std::vector<Metric2Condition> mMetric2ConditionLinks;
std::vector<sp<AnomalyTracker>> mAnomalyTrackers;
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 6c21b05..e75b710 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#define DEBUG false // STOPSHIP if true
+#define DEBUG true // STOPSHIP if true
#include "Log.h"
#include "MetricsManager.h"
#include "statslog.h"
@@ -26,6 +26,7 @@
#include "matchers/SimpleLogMatchingTracker.h"
#include "metrics_manager_util.h"
#include "stats_util.h"
+#include "stats_log_util.h"
#include <log/logprint.h>
#include <private/android_filesystem_config.h>
@@ -49,9 +50,10 @@
MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config,
const long timeBaseSec, sp<UidMap> uidMap)
- : mConfigKey(key), mUidMap(uidMap), mLastReportTimeNs(0) {
+ : mConfigKey(key), mUidMap(uidMap), mLastReportTimeNs(timeBaseSec * NS_PER_SEC) {
mConfigValid =
- initStatsdConfig(key, config, *uidMap, timeBaseSec, mTagIds, mAllAtomMatchers, mAllConditionTrackers,
+ initStatsdConfig(key, config, *uidMap, timeBaseSec, mTagIds, mAllAtomMatchers,
+ mAllConditionTrackers,
mAllMetricProducers, mAllAnomalyTrackers, mConditionToMetricMap,
mTrackerToMetricMap, mTrackerToConditionMap, mNoReportMetricIds);
@@ -90,8 +92,10 @@
ALOGE("This config is too big! Reject!");
mConfigValid = false;
}
-
- // TODO: add alert size.
+ if (mAllAnomalyTrackers.size() > StatsdStats::kMaxAlertCountPerConfig) {
+ ALOGE("This config has too many alerts! Reject!");
+ mConfigValid = false;
+ }
// no matter whether this config is valid, log it in the stats.
StatsdStats::getInstance().noteConfigReceived(key, mAllMetricProducers.size(),
mAllConditionTrackers.size(),
@@ -151,14 +155,6 @@
initLogSourceWhiteList();
}
-void MetricsManager::onDumpReport(const uint64_t& dumpTimeStampNs, ConfigMetricsReport* report) {
- for (const auto& producer : mAllMetricProducers) {
- if (mNoReportMetricIds.find(producer->getMetricId()) == mNoReportMetricIds.end()) {
- producer->onDumpReport(dumpTimeStampNs, report->add_metrics());
- }
- }
-}
-
void MetricsManager::dumpStates(FILE* out, bool verbose) {
fprintf(out, "ConfigKey %s, allowed source:", mConfigKey.ToString().c_str());
{
@@ -173,9 +169,8 @@
}
}
-void MetricsManager::onDumpReport(ProtoOutputStream* protoOutput) {
+void MetricsManager::onDumpReport(const uint64_t dumpTimeStampNs, ProtoOutputStream* protoOutput) {
VLOG("=========================Metric Reports Start==========================");
- uint64_t dumpTimeStampNs = time(nullptr) * NS_PER_SEC;
// one StatsLogReport per MetricProduer
for (const auto& producer : mAllMetricProducers) {
if (mNoReportMetricIds.find(producer->getMetricId()) == mNoReportMetricIds.end()) {
@@ -185,7 +180,7 @@
protoOutput->end(token);
}
}
- mLastReportTimeNs = ::android::elapsedRealtimeNano();
+ mLastReportTimeNs = dumpTimeStampNs;
VLOG("=========================Metric Reports End==========================");
}
@@ -195,8 +190,9 @@
return;
}
- if (event.GetTagId() == android::util::APP_HOOK) { // Check that app hook fields are valid.
- // TODO: Find a way to make these checks easier to maintain if the app hooks get changed.
+ if (event.GetTagId() == android::util::APP_BREADCRUMB_REPORTED) {
+ // Check that app breadcrumb reported fields are valid.
+ // TODO: Find a way to make these checks easier to maintain.
status_t err = NO_ERROR;
// Uid is 3rd from last field and must match the caller's uid,
@@ -239,7 +235,7 @@
}
int tagId = event.GetTagId();
- uint64_t eventTime = event.GetTimestampNs();
+ uint64_t eventTime = event.GetElapsedTimestampNs();
if (mTagIds.find(tagId) == mTagIds.end()) {
// not interesting...
return;
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 2b30f44..d4f844f 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -70,8 +70,8 @@
};
// Config source owner can call onDumpReport() to get all the metrics collected.
- virtual void onDumpReport(android::util::ProtoOutputStream* protoOutput);
- virtual void onDumpReport(const uint64_t& dumpTimeStampNs, ConfigMetricsReport* report);
+ virtual void onDumpReport(const uint64_t dumpTimeNs,
+ android::util::ProtoOutputStream* protoOutput);
// Computes the total byte size of all metrics managed by a single config source.
// Does not change the state.
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 7b1944c..35fcdc4 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -17,7 +17,6 @@
#define DEBUG false // STOPSHIP if true
#include "Log.h"
-#include "dimension.h"
#include "ValueMetricProducer.h"
#include "guardrail/StatsdStats.h"
#include "stats_log_util.h"
@@ -73,21 +72,34 @@
// TODO: valuemetric for pushed events may need unlimited bucket length
int64_t bucketSizeMills = 0;
if (metric.has_bucket()) {
- bucketSizeMills = TimeUnitToBucketSizeInMillis(metric.bucket());
+ bucketSizeMills = TimeUnitToBucketSizeInMillisGuardrailed(key.GetUid(), metric.bucket());
} else {
bucketSizeMills = TimeUnitToBucketSizeInMillis(ONE_HOUR);
}
mBucketSizeNs = bucketSizeMills * 1000000;
- mDimensionsInWhat = metric.dimensions_in_what();
- mDimensionsInCondition = metric.dimensions_in_condition();
+ if (metric.has_dimensions_in_what()) {
+ translateFieldMatcher(metric.dimensions_in_what(), &mDimensionsInWhat);
+ }
+
+ if (metric.has_dimensions_in_condition()) {
+ translateFieldMatcher(metric.dimensions_in_condition(), &mDimensionsInCondition);
+ }
if (metric.links().size() > 0) {
- mConditionLinks.insert(mConditionLinks.begin(), metric.links().begin(),
- metric.links().end());
+ for (const auto& link : metric.links()) {
+ Metric2Condition mc;
+ mc.conditionId = link.condition();
+ translateFieldMatcher(link.fields_in_what(), &mc.metricFields);
+ translateFieldMatcher(link.fields_in_condition(), &mc.conditionFields);
+ mMetric2ConditionLinks.push_back(mc);
+ }
}
- mConditionSliced = (metric.links().size() > 0)||
- (mDimensionsInCondition.has_field() && mDimensionsInCondition.child_size() > 0);
+
+ if (mValueField.child_size()) {
+ mField = mValueField.child(0).field();
+ }
+ mConditionSliced = (metric.links().size() > 0) || (mDimensionsInCondition.size() > 0);
if (!metric.has_condition() && mPullTagId != -1) {
VLOG("Setting up periodic pulling for %d", mPullTagId);
@@ -117,25 +129,6 @@
VLOG("Metric %lld onSlicedConditionMayChange", (long long)mMetricId);
}
-void ValueMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs, StatsLogReport* report) {
- flushIfNeededLocked(dumpTimeNs);
- report->set_metric_id(mMetricId);
- auto value_metrics = report->mutable_value_metrics();
- for (const auto& pair : mPastBuckets) {
- ValueMetricData* metricData = value_metrics->add_data();
- *metricData->mutable_dimensions_in_what() =
- pair.first.getDimensionKeyInWhat().getDimensionsValue();
- *metricData->mutable_dimensions_in_condition() =
- pair.first.getDimensionKeyInCondition().getDimensionsValue();
- for (const auto& bucket : pair.second) {
- ValueBucketInfo* bucketInfo = metricData->add_bucket_info();
- bucketInfo->set_start_bucket_nanos(bucket.mBucketStartNs);
- bucketInfo->set_end_bucket_nanos(bucket.mBucketEndNs);
- bucketInfo->set_value(bucket.mValue);
- }
- }
-}
-
void ValueMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs,
ProtoOutputStream* protoOutput) {
VLOG("metric %lld dump report now...", (long long)mMetricId);
@@ -155,14 +148,12 @@
// First fill dimension.
long long dimensionToken = protoOutput->start(
FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_WHAT);
- writeDimensionsValueProtoToStream(
- dimensionKey.getDimensionKeyInWhat().getDimensionsValue(), protoOutput);
+ writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), protoOutput);
protoOutput->end(dimensionToken);
if (dimensionKey.hasDimensionKeyInCondition()) {
long long dimensionInConditionToken = protoOutput->start(
FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_CONDITION);
- writeDimensionsValueProtoToStream(
- dimensionKey.getDimensionKeyInCondition().getDimensionsValue(), protoOutput);
+ writeDimensionToProto(dimensionKey.getDimensionKeyInCondition(), protoOutput);
protoOutput->end(dimensionInConditionToken);
}
@@ -228,19 +219,19 @@
}
// For scheduled pulled data, the effective event time is snap to the nearest
// bucket boundary to make bucket finalize.
- uint64_t realEventTime = allData.at(0)->GetTimestampNs();
+ uint64_t realEventTime = allData.at(0)->GetElapsedTimestampNs();
uint64_t eventTime = mStartTimeNs +
- ((realEventTime - mStartTimeNs)/mBucketSizeNs) * mBucketSizeNs;
+ ((realEventTime - mStartTimeNs) / mBucketSizeNs) * mBucketSizeNs;
mCondition = false;
for (const auto& data : allData) {
- data->setTimestampNs(eventTime-1);
+ data->setElapsedTimestampNs(eventTime - 1);
onMatchedLogEventLocked(0, *data);
}
mCondition = true;
for (const auto& data : allData) {
- data->setTimestampNs(eventTime);
+ data->setElapsedTimestampNs(eventTime);
onMatchedLogEventLocked(0, *data);
}
}
@@ -270,7 +261,7 @@
const size_t matcherIndex, const MetricDimensionKey& eventKey,
const ConditionKey& conditionKey, bool condition,
const LogEvent& event) {
- uint64_t eventTimeNs = event.GetTimestampNs();
+ uint64_t eventTimeNs = event.GetElapsedTimestampNs();
if (eventTimeNs < mCurrentBucketStartTimeNs) {
VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
(long long)mCurrentBucketStartTimeNs);
@@ -284,11 +275,11 @@
}
Interval& interval = mCurrentSlicedBucket[eventKey];
- std::shared_ptr<FieldValueMap> valueFieldMap = getValueFields(event);
- if (valueFieldMap->empty() || valueFieldMap->size() > 1) {
+ int error = 0;
+ const long value = event.GetLong(mField, &error);
+ if (error < 0) {
return;
}
- const long value = getLongFromDimenValue(valueFieldMap->begin()->second);
if (mPullTagId != -1) { // for pulled events
if (mCondition == true) {
@@ -324,13 +315,6 @@
}
}
-std::shared_ptr<FieldValueMap> ValueMetricProducer::getValueFields(const LogEvent& event) {
- std::shared_ptr<FieldValueMap> valueFields =
- std::make_shared<FieldValueMap>(event.getFieldValueMap());
- filterFields(mValueField, valueFields.get());
- return valueFields;
-}
-
void ValueMetricProducer::flushIfNeededLocked(const uint64_t& eventTimeNs) {
uint64_t currentBucketEndTimeNs = getCurrentBucketEndTimeNs();
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index bf5b7df..b518f2f 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -62,7 +62,7 @@
// Pretend the pulled data occurs right before the app upgrade event.
mCondition = false;
for (const auto& data : allData) {
- data->setTimestampNs(eventTimeNs - 1);
+ data->setElapsedTimestampNs(eventTimeNs - 1);
onMatchedLogEventLocked(0, *data);
}
@@ -71,7 +71,7 @@
mCondition = true;
for (const auto& data : allData) {
- data->setTimestampNs(eventTimeNs);
+ data->setElapsedTimestampNs(eventTimeNs);
onMatchedLogEventLocked(0, *data);
}
} else { // For pushed value metric, we simply flush and reset the current bucket start.
@@ -89,7 +89,6 @@
private:
void onDumpReportLocked(const uint64_t dumpTimeNs,
android::util::ProtoOutputStream* protoOutput) override;
- void onDumpReportLocked(const uint64_t dumpTimeNs, StatsLogReport* report) override;
// Internal interface to handle condition change.
void onConditionChangedLocked(const bool conditionMet, const uint64_t eventTime) override;
@@ -120,6 +119,8 @@
// tagId for pulled data. -1 if this is not pulled
const int mPullTagId;
+ int mField;
+
// internal state of a bucket.
typedef struct {
// Pulled data always come in pair of <start, end>. This holds the value
@@ -142,8 +143,6 @@
// TODO: Add a lock to mPastBuckets.
std::unordered_map<MetricDimensionKey, std::vector<ValueBucket>> mPastBuckets;
- std::shared_ptr<FieldValueMap> getValueFields(const LogEvent& event);
-
// Util function to check whether the specified dimension hits the guardrail.
bool hitGuardRailLocked(const MetricDimensionKey& newKey);
diff --git a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
index 356a81c..8f236fa 100644
--- a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
@@ -62,7 +62,7 @@
public:
DurationTracker(const ConfigKey& key, const int64_t& id, const MetricDimensionKey& eventKey,
sp<ConditionWizard> wizard, int conditionIndex,
- const FieldMatcher& dimensionInCondition, bool nesting,
+ const std::vector<Matcher>& dimensionInCondition, bool nesting,
uint64_t currentBucketStartNs, uint64_t currentBucketNum, uint64_t startTimeNs,
uint64_t bucketSizeNs, bool conditionSliced,
const std::vector<sp<DurationAnomalyTracker>>& anomalyTrackers)
@@ -182,7 +182,7 @@
const int64_t mBucketSizeNs;
- const FieldMatcher mDimensionInCondition;
+ const std::vector<Matcher>& mDimensionInCondition;
const bool mNested;
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
index c3bafc6..95df5ae6 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
@@ -27,7 +27,7 @@
MaxDurationTracker::MaxDurationTracker(const ConfigKey& key, const int64_t& id,
const MetricDimensionKey& eventKey,
sp<ConditionWizard> wizard, int conditionIndex,
- const FieldMatcher& dimensionInCondition, bool nesting,
+ const vector<Matcher>& dimensionInCondition, bool nesting,
uint64_t currentBucketStartNs, uint64_t currentBucketNum,
uint64_t startTimeNs, uint64_t bucketSizeNs,
bool conditionSliced,
@@ -55,9 +55,7 @@
// 1. Report the tuple count if the tuple count > soft limit
if (mInfos.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
size_t newTupleCount = mInfos.size() + 1;
- StatsdStats::getInstance().noteMetricDimensionSize(
- mConfigKey, hashMetricDimensionKey(mTrackerId, mEventKey),
- newTupleCount);
+ StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mTrackerId, newTupleCount);
// 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
ALOGE("MaxDurTracker %lld dropping data for dimension key %s",
@@ -179,7 +177,6 @@
false; // has either a kStarted or kPaused event across bucket boundaries
// meaning we need to carry them over to the new bucket.
for (auto it = mInfos.begin(); it != mInfos.end(); ++it) {
- int64_t finalDuration = it->second.lastDuration;
if (it->second.state == DurationState::kStopped) {
// No need to keep buckets for events that were stopped before.
mInfos.erase(it);
@@ -229,10 +226,11 @@
ConditionState conditionState = mWizard->query(
mConditionTrackerIndex, pair.second.conditionKeys, mDimensionInCondition,
&conditionDimensionKeySet);
- bool conditionMet = (conditionState == ConditionState::kTrue) &&
- (!mDimensionInCondition.has_field() ||
- conditionDimensionKeySet.find(mEventKey.getDimensionKeyInCondition()) !=
- conditionDimensionKeySet.end());
+ bool conditionMet =
+ (conditionState == ConditionState::kTrue) &&
+ (mDimensionInCondition.size() == 0 ||
+ conditionDimensionKeySet.find(mEventKey.getDimensionKeyInCondition()) !=
+ conditionDimensionKeySet.end());
VLOG("key: %s, condition: %d", pair.first.c_str(), conditionMet);
noteConditionChanged(pair.first, conditionMet, timestamp);
}
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
index fba4119..95863b6 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
@@ -30,7 +30,7 @@
public:
MaxDurationTracker(const ConfigKey& key, const int64_t& id, const MetricDimensionKey& eventKey,
sp<ConditionWizard> wizard, int conditionIndex,
- const FieldMatcher& dimensionInCondition, bool nesting,
+ const std::vector<Matcher>& dimensionInCondition, bool nesting,
uint64_t currentBucketStartNs, uint64_t currentBucketNum,
uint64_t startTimeNs, uint64_t bucketSizeNs, bool conditionSliced,
const std::vector<sp<DurationAnomalyTracker>>& anomalyTrackers);
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
index 85f7b7c..f583f91 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
@@ -26,7 +26,7 @@
OringDurationTracker::OringDurationTracker(
const ConfigKey& key, const int64_t& id, const MetricDimensionKey& eventKey,
- sp<ConditionWizard> wizard, int conditionIndex, const FieldMatcher& dimensionInCondition,
+ sp<ConditionWizard> wizard, int conditionIndex, const vector<Matcher>& dimensionInCondition,
bool nesting, uint64_t currentBucketStartNs, uint64_t currentBucketNum,
uint64_t startTimeNs, uint64_t bucketSizeNs, bool conditionSliced,
const vector<sp<DurationAnomalyTracker>>& anomalyTrackers)
@@ -53,9 +53,7 @@
}
if (mConditionKeyMap.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
size_t newTupleCount = mConditionKeyMap.size() + 1;
- StatsdStats::getInstance().noteMetricDimensionSize(
- mConfigKey, hashMetricDimensionKey(mTrackerId, mEventKey),
- newTupleCount);
+ StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mTrackerId, newTupleCount);
// 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
ALOGE("OringDurTracker %lld dropping data for dimension key %s",
@@ -229,9 +227,9 @@
mWizard->query(mConditionTrackerIndex, mConditionKeyMap[key],
mDimensionInCondition, &conditionDimensionKeySet);
if (conditionState != ConditionState::kTrue ||
- (mDimensionInCondition.has_field() &&
+ (mDimensionInCondition.size() != 0 &&
conditionDimensionKeySet.find(mEventKey.getDimensionKeyInCondition()) ==
- conditionDimensionKeySet.end())) {
+ conditionDimensionKeySet.end())) {
startedToPaused.push_back(*it);
it = mStarted.erase(it);
VLOG("Key %s started -> paused", key.c_str());
@@ -261,9 +259,9 @@
mWizard->query(mConditionTrackerIndex, mConditionKeyMap[key],
mDimensionInCondition, &conditionDimensionKeySet);
if (conditionState == ConditionState::kTrue &&
- (!mDimensionInCondition.has_field() ||
- conditionDimensionKeySet.find(mEventKey.getDimensionKeyInCondition())
- != conditionDimensionKeySet.end())) {
+ (mDimensionInCondition.size() == 0 ||
+ conditionDimensionKeySet.find(mEventKey.getDimensionKeyInCondition()) !=
+ conditionDimensionKeySet.end())) {
pausedToStarted.push_back(*it);
it = mPaused.erase(it);
VLOG("Key %s paused -> started", key.c_str());
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
index 73e50e0..07c1329 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
@@ -29,8 +29,8 @@
public:
OringDurationTracker(const ConfigKey& key, const int64_t& id,
const MetricDimensionKey& eventKey, sp<ConditionWizard> wizard,
- int conditionIndex, const FieldMatcher& dimensionInCondition, bool nesting,
- uint64_t currentBucketStartNs, uint64_t currentBucketNum,
+ int conditionIndex, const std::vector<Matcher>& dimensionInCondition,
+ bool nesting, uint64_t currentBucketStartNs, uint64_t currentBucketNum,
uint64_t startTimeNs, uint64_t bucketSizeNs, bool conditionSliced,
const std::vector<sp<DurationAnomalyTracker>>& anomalyTrackers);
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index 205c8e4..71e5c33 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -38,6 +38,22 @@
namespace os {
namespace statsd {
+namespace {
+
+bool hasLeafNode(const FieldMatcher& matcher) {
+ if (!matcher.has_field()) {
+ return false;
+ }
+ for (int i = 0; i < matcher.child_size(); ++i) {
+ if (hasLeafNode(matcher.child(i))) {
+ return true;
+ }
+ }
+ return true;
+}
+
+} // namespace
+
bool handleMetricWithLogTrackers(const int64_t what, const int metricIndex,
const bool usedForDimension,
const vector<sp<LogMatchingTracker>>& allAtomMatchers,
@@ -497,10 +513,12 @@
const int metricIndex = itr->second;
sp<MetricProducer> metric = allMetricProducers[metricIndex];
sp<AnomalyTracker> anomalyTracker = metric->addAnomalyTracker(alert);
- if (anomalyTracker != nullptr) {
- anomalyTrackerMap.insert(std::make_pair(alert.id(), allAnomalyTrackers.size()));
- allAnomalyTrackers.push_back(anomalyTracker);
+ if (anomalyTracker == nullptr) {
+ // The ALOGW for this invalid alert was already displayed in addAnomalyTracker().
+ return false;
}
+ anomalyTrackerMap.insert(std::make_pair(alert.id(), allAnomalyTrackers.size()));
+ allAnomalyTrackers.push_back(anomalyTracker);
}
for (int i = 0; i < config.subscription_size(); ++i) {
const Subscription& subscription = config.subscription(i);
diff --git a/cmds/statsd/src/packages/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp
index 0d7b722..e322ca4 100644
--- a/cmds/statsd/src/packages/UidMap.cpp
+++ b/cmds/statsd/src/packages/UidMap.cpp
@@ -13,9 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#define DEBUG false // STOPSHIP if true
+#define DEBUG true // STOPSHIP if true
#include "Log.h"
+#include "stats_log_util.h"
#include "guardrail/StatsdStats.h"
#include "packages/UidMap.h"
@@ -82,7 +83,7 @@
void UidMap::updateMap(const vector<int32_t>& uid, const vector<int64_t>& versionCode,
const vector<String16>& packageName) {
- updateMap(time(nullptr) * NS_PER_SEC, uid, versionCode, packageName);
+ updateMap(getElapsedRealtimeNs(), uid, versionCode, packageName);
}
void UidMap::updateMap(const int64_t& timestamp, const vector<int32_t>& uid,
@@ -98,7 +99,7 @@
}
auto snapshot = mOutput.add_snapshots();
- snapshot->set_timestamp_nanos(timestamp);
+ snapshot->set_elapsed_timestamp_nanos(timestamp);
for (size_t j = 0; j < uid.size(); j++) {
auto t = snapshot->add_package_info();
t->set_name(string(String8(packageName[j]).string()));
@@ -125,7 +126,7 @@
}
void UidMap::updateApp(const String16& app_16, const int32_t& uid, const int64_t& versionCode) {
- updateApp(time(nullptr) * NS_PER_SEC, app_16, uid, versionCode);
+ updateApp(getElapsedRealtimeNs(), app_16, uid, versionCode);
}
void UidMap::updateApp(const int64_t& timestamp, const String16& app_16, const int32_t& uid,
@@ -137,7 +138,7 @@
auto log = mOutput.add_changes();
log->set_deletion(false);
- log->set_timestamp_nanos(timestamp);
+ log->set_elapsed_timestamp_nanos(timestamp);
log->set_app(appName);
log->set_uid(uid);
log->set_version(versionCode);
@@ -194,7 +195,7 @@
}
void UidMap::removeApp(const String16& app_16, const int32_t& uid) {
- removeApp(time(nullptr) * NS_PER_SEC, app_16, uid);
+ removeApp(getElapsedRealtimeNs(), app_16, uid);
}
void UidMap::getListenerListCopyLocked(vector<wp<PackageInfoListener>>* output) {
@@ -218,7 +219,7 @@
auto log = mOutput.add_changes();
log->set_deletion(true);
- log->set_timestamp_nanos(timestamp);
+ log->set_elapsed_timestamp_nanos(timestamp);
log->set_app(app);
log->set_uid(uid);
mBytesUsed += log->ByteSize();
@@ -305,7 +306,7 @@
}
UidMapping UidMap::getOutput(const ConfigKey& key) {
- return getOutput(time(nullptr) * NS_PER_SEC, key);
+ return getOutput(getElapsedRealtimeNs(), key);
}
UidMapping UidMap::getOutput(const int64_t& timestamp, const ConfigKey& key) {
@@ -321,7 +322,7 @@
auto snapshots = mOutput.mutable_snapshots();
auto it_snapshots = snapshots->cbegin();
while (it_snapshots != snapshots->cend()) {
- if (it_snapshots->timestamp_nanos() < cutoff_nanos) {
+ if (it_snapshots->elapsed_timestamp_nanos() < cutoff_nanos) {
// it_snapshots points to the following element after erasing.
it_snapshots = snapshots->erase(it_snapshots);
} else {
@@ -331,7 +332,7 @@
auto deltas = mOutput.mutable_changes();
auto it_deltas = deltas->cbegin();
while (it_deltas != deltas->cend()) {
- if (it_deltas->timestamp_nanos() < cutoff_nanos) {
+ if (it_deltas->elapsed_timestamp_nanos() < cutoff_nanos) {
// it_snapshots points to the following element after erasing.
it_deltas = deltas->erase(it_deltas);
} else {
@@ -343,7 +344,7 @@
// Produce another snapshot. This results in extra data being uploaded but helps
// ensure we can re-construct the UID->app name, versionCode mapping in server.
auto snapshot = mOutput.add_snapshots();
- snapshot->set_timestamp_nanos(timestamp);
+ snapshot->set_elapsed_timestamp_nanos(timestamp);
for (auto it : mMap) {
auto t = snapshot->add_package_info();
t->set_name(it.second.packageName);
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index b56cffb..b427485 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -42,15 +42,17 @@
}
message EventMetricData {
- optional int64 timestamp_nanos = 1;
+ optional int64 elapsed_timestamp_nanos = 1;
optional Atom atom = 2;
+
+ optional int64 wall_clock_timestamp_sec = 3;
}
message CountBucketInfo {
- optional int64 start_bucket_nanos = 1;
+ optional int64 start_bucket_elapsed_nanos = 1;
- optional int64 end_bucket_nanos = 2;
+ optional int64 end_bucket_elapsed_nanos = 2;
optional int64 count = 3;
}
@@ -64,9 +66,9 @@
}
message DurationBucketInfo {
- optional int64 start_bucket_nanos = 1;
+ optional int64 start_bucket_elapsed_nanos = 1;
- optional int64 end_bucket_nanos = 2;
+ optional int64 end_bucket_elapsed_nanos = 2;
optional int64 duration_nanos = 3;
}
@@ -80,9 +82,9 @@
}
message ValueBucketInfo {
- optional int64 start_bucket_nanos = 1;
+ optional int64 start_bucket_elapsed_nanos = 1;
- optional int64 end_bucket_nanos = 2;
+ optional int64 end_bucket_elapsed_nanos = 2;
optional int64 value = 3;
}
@@ -102,7 +104,7 @@
repeated Atom atom = 3;
- repeated int64 timestamp_nanos = 4;
+ repeated int64 elapsed_timestamp_nanos = 4;
}
message GaugeMetricData {
@@ -122,7 +124,7 @@
optional int32 uid = 3;
}
- optional int64 timestamp_nanos = 1;
+ optional int64 elapsed_timestamp_nanos = 1;
repeated PackageInfo package_info = 2;
}
@@ -131,7 +133,7 @@
message Change {
optional bool deletion = 1;
- optional int64 timestamp_nanos = 2;
+ optional int64 elapsed_timestamp_nanos = 2;
optional string app = 3;
optional int32 uid = 4;
@@ -176,9 +178,9 @@
optional UidMapping uid_map = 2;
- optional int64 last_report_nanos = 3;
+ optional int64 last_report_elapsed_nanos = 3;
- optional int64 current_report_nanos = 4;
+ optional int64 current_report_elapsed_nanos = 4;
}
message ConfigMetricsReportList {
diff --git a/cmds/statsd/src/stats_log_util.cpp b/cmds/statsd/src/stats_log_util.cpp
index 6c61400..30eef4f 100644
--- a/cmds/statsd/src/stats_log_util.cpp
+++ b/cmds/statsd/src/stats_log_util.cpp
@@ -16,9 +16,13 @@
#include "stats_log_util.h"
+#include <logd/LogEvent.h>
+#include <private/android_filesystem_config.h>
+#include <utils/Log.h>
#include <set>
#include <stack>
#include <utils/Log.h>
+#include <utils/SystemClock.h>
using android::util::FIELD_COUNT_REPEATED;
using android::util::FIELD_TYPE_BOOL;
@@ -38,12 +42,11 @@
const int DIMENSIONS_VALUE_VALUE_STR = 2;
const int DIMENSIONS_VALUE_VALUE_INT = 3;
const int DIMENSIONS_VALUE_VALUE_LONG = 4;
-const int DIMENSIONS_VALUE_VALUE_BOOL = 5;
+// const int DIMENSIONS_VALUE_VALUE_BOOL = 5; // logd doesn't have bool data type.
const int DIMENSIONS_VALUE_VALUE_FLOAT = 6;
const int DIMENSIONS_VALUE_VALUE_TUPLE = 7;
-// for MessageValue Proto
-const int FIELD_ID_FIELD_VALUE_IN_MESSAGE_VALUE_PROTO = 1;
+const int DIMENSIONS_VALUE_TUPLE_VALUE = 1;
// for PulledAtomStats proto
const int FIELD_ID_PULLED_ATOM_STATS = 10;
@@ -51,186 +54,175 @@
const int FIELD_ID_TOTAL_PULL = 2;
const int FIELD_ID_TOTAL_PULL_FROM_CACHE = 3;
const int FIELD_ID_MIN_PULL_INTERVAL_SEC = 4;
-
-void writeDimensionsValueProtoToStream(const DimensionsValue& dimensionsValue,
- ProtoOutputStream* protoOutput) {
- if (!dimensionsValue.has_field()) {
- return;
- }
- protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD, dimensionsValue.field());
- switch (dimensionsValue.value_case()) {
- case DimensionsValue::ValueCase::kValueStr:
- protoOutput->write(FIELD_TYPE_STRING | DIMENSIONS_VALUE_VALUE_STR,
- dimensionsValue.value_str());
- break;
- case DimensionsValue::ValueCase::kValueInt:
- protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_VALUE_INT,
- dimensionsValue.value_int());
- break;
- case DimensionsValue::ValueCase::kValueLong:
- protoOutput->write(FIELD_TYPE_INT64 | DIMENSIONS_VALUE_VALUE_LONG,
- dimensionsValue.value_long());
- break;
- case DimensionsValue::ValueCase::kValueBool:
- protoOutput->write(FIELD_TYPE_BOOL | DIMENSIONS_VALUE_VALUE_BOOL,
- dimensionsValue.value_bool());
- break;
- case DimensionsValue::ValueCase::kValueFloat:
- protoOutput->write(FIELD_TYPE_FLOAT | DIMENSIONS_VALUE_VALUE_FLOAT,
- dimensionsValue.value_float());
- break;
- case DimensionsValue::ValueCase::kValueTuple:
- {
- long long tupleToken = protoOutput->start(
- FIELD_TYPE_MESSAGE | DIMENSIONS_VALUE_VALUE_TUPLE);
- for (int i = 0; i < dimensionsValue.value_tuple().dimensions_value_size(); ++i) {
- long long token = protoOutput->start(
- FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED
- | FIELD_ID_FIELD_VALUE_IN_MESSAGE_VALUE_PROTO);
- writeDimensionsValueProtoToStream(
- dimensionsValue.value_tuple().dimensions_value(i), protoOutput);
- protoOutput->end(token);
- }
- protoOutput->end(tupleToken);
- }
- break;
- default:
- break;
- }
-}
-
-// for Field Proto
-const int FIELD_FIELD = 1;
-const int FIELD_POSITION_INDEX = 2;
-const int FIELD_CHILD = 3;
-
-void writeFieldProtoToStream(
- const Field& field, util::ProtoOutputStream* protoOutput) {
- if (!field.has_field()) {
- return;
- }
- protoOutput->write(FIELD_TYPE_INT32 | FIELD_FIELD, field.field());
- if (field.has_position_index()) {
- protoOutput->write(FIELD_TYPE_INT32 | FIELD_POSITION_INDEX, field.position_index());
- }
- for (int i = 0; i < field.child_size(); ++i) {
- long long childToken = protoOutput->start(
- FIELD_TYPE_MESSAGE| FIELD_COUNT_REPEATED | FIELD_CHILD);
- writeFieldProtoToStream(field.child(i), protoOutput);
- protoOutput->end(childToken);
- }
-}
-
namespace {
-void addOrUpdateChildrenMap(
- const Field& root,
- const Field& node,
- std::map<Field, std::set<Field, FieldCmp>, FieldCmp> *childrenMap) {
- Field parentNode = root;
- if (node.has_position_index()) {
- appendLeaf(&parentNode, node.field(), node.position_index());
- } else {
- appendLeaf(&parentNode, node.field());
- }
- if (childrenMap->find(parentNode) == childrenMap->end()) {
- childrenMap->insert(std::make_pair(parentNode, std::set<Field, FieldCmp>{}));
- }
- auto it = childrenMap->find(parentNode);
- for (int i = 0; i < node.child_size(); ++i) {
- auto child = node.child(i);
- Field childNode = parentNode;
- if (child.has_position_index()) {
- appendLeaf(&childNode, child.field(), child.position_index());
- } else {
- appendLeaf(&childNode, child.field());
+void writeDimensionToProtoHelper(const std::vector<FieldValue>& dims, size_t* index, int depth,
+ int prefix, ProtoOutputStream* protoOutput) {
+ size_t count = dims.size();
+ while (*index < count) {
+ const auto& dim = dims[*index];
+ const int valueDepth = dim.mField.getDepth();
+ const int valuePrefix = dim.mField.getPrefix(depth);
+ const int fieldNum = dim.mField.getPosAtDepth(depth);
+ if (valueDepth > 2) {
+ ALOGE("Depth > 2 not supported");
+ return;
}
- it->second.insert(childNode);
- addOrUpdateChildrenMap(parentNode, child, childrenMap);
+
+ if (depth == valueDepth && valuePrefix == prefix) {
+ long long token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
+ DIMENSIONS_VALUE_TUPLE_VALUE);
+ protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD, fieldNum);
+ switch (dim.mValue.getType()) {
+ case INT:
+ protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_VALUE_INT,
+ dim.mValue.int_value);
+ break;
+ case LONG:
+ protoOutput->write(FIELD_TYPE_INT64 | DIMENSIONS_VALUE_VALUE_LONG,
+ (long long)dim.mValue.long_value);
+ break;
+ case FLOAT:
+ protoOutput->write(FIELD_TYPE_FLOAT | DIMENSIONS_VALUE_VALUE_FLOAT,
+ dim.mValue.float_value);
+ break;
+ case STRING:
+ protoOutput->write(FIELD_TYPE_STRING | DIMENSIONS_VALUE_VALUE_STR,
+ dim.mValue.str_value);
+ break;
+ default:
+ break;
+ }
+ if (token != 0) {
+ protoOutput->end(token);
+ }
+ (*index)++;
+ } else if (valueDepth > depth && valuePrefix == prefix) {
+ // Writing the sub tree
+ long long dimensionToken = protoOutput->start(
+ FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | DIMENSIONS_VALUE_TUPLE_VALUE);
+ protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD, fieldNum);
+ long long tupleToken =
+ protoOutput->start(FIELD_TYPE_MESSAGE | DIMENSIONS_VALUE_VALUE_TUPLE);
+ writeDimensionToProtoHelper(dims, index, valueDepth, dim.mField.getPrefix(valueDepth),
+ protoOutput);
+ protoOutput->end(tupleToken);
+ protoOutput->end(dimensionToken);
+ } else {
+ // Done with the prev sub tree
+ return;
+ }
}
}
-void addOrUpdateChildrenMap(
- const Field& field,
- std::map<Field, std::set<Field, FieldCmp>, FieldCmp> *childrenMap) {
- Field root;
- addOrUpdateChildrenMap(root, field, childrenMap);
+} // namespace
+
+void writeDimensionToProto(const HashableDimensionKey& dimension, ProtoOutputStream* protoOutput) {
+ if (dimension.getValues().size() == 0) {
+ return;
+ }
+ protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD,
+ dimension.getValues()[0].mField.getTag());
+ long long topToken = protoOutput->start(FIELD_TYPE_MESSAGE | DIMENSIONS_VALUE_VALUE_TUPLE);
+ size_t index = 0;
+ writeDimensionToProtoHelper(dimension.getValues(), &index, 0, 0, protoOutput);
+ protoOutput->end(topToken);
}
-} // namespace
+// Supported Atoms format
+// XYZ_Atom {
+// repeated SubMsg field_1 = 1;
+// SubMsg2 field_2 = 2;
+// int32/float/string/int63 field_3 = 3;
+// }
+// logd's msg format, doesn't allow us to distinguish between the 2 cases below
+// Case (1):
+// Atom {
+// SubMsg {
+// int i = 1;
+// int j = 2;
+// }
+// repeated SubMsg
+// }
+//
+// and case (2):
+// Atom {
+// SubMsg {
+// repeated int i = 1;
+// repeated int j = 2;
+// }
+// optional SubMsg = 1;
+// }
+//
+//
+void writeFieldValueTreeToStreamHelper(const std::vector<FieldValue>& dims, size_t* index,
+ int depth, int prefix, ProtoOutputStream* protoOutput) {
+ size_t count = dims.size();
+ while (*index < count) {
+ const auto& dim = dims[*index];
+ const int valueDepth = dim.mField.getDepth();
+ const int valuePrefix = dim.mField.getPrefix(depth);
+ const int fieldNum = dim.mField.getPosAtDepth(depth);
+ if (valueDepth > 2) {
+ ALOGE("Depth > 2 not supported");
+ return;
+ }
-void writeFieldValueTreeToStream(const FieldValueMap &fieldValueMap,
+ if (depth == valueDepth && valuePrefix == prefix) {
+ switch (dim.mValue.getType()) {
+ case INT:
+ protoOutput->write(FIELD_TYPE_INT32 | fieldNum, dim.mValue.int_value);
+ break;
+ case LONG:
+ protoOutput->write(FIELD_TYPE_INT64 | fieldNum,
+ (long long)dim.mValue.long_value);
+ break;
+ case FLOAT:
+ protoOutput->write(FIELD_TYPE_FLOAT | fieldNum, dim.mValue.float_value);
+ break;
+ case STRING:
+ protoOutput->write(FIELD_TYPE_STRING | fieldNum, dim.mValue.str_value);
+ break;
+ }
+ (*index)++;
+ } else if (valueDepth > depth && valuePrefix == prefix) {
+ // Writing the sub tree
+ long long msg_token = 0;
+ if (valueDepth == depth + 2) {
+ msg_token =
+ protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | fieldNum);
+ } else if (valueDepth == depth + 1) {
+ msg_token = protoOutput->start(FIELD_TYPE_MESSAGE | fieldNum);
+ }
+ // Directly jump to the leaf value because the repeated position field is implied
+ // by the position of the sub msg in the parent field.
+ writeFieldValueTreeToStreamHelper(dims, index, valueDepth,
+ dim.mField.getPrefix(valueDepth), protoOutput);
+ if (msg_token != 0) {
+ protoOutput->end(msg_token);
+ }
+ } else {
+ // Done with the prev sub tree
+ return;
+ }
+ }
+}
+
+void writeFieldValueTreeToStream(int tagId, const std::vector<FieldValue>& values,
util::ProtoOutputStream* protoOutput) {
- std::map<Field, std::set<Field, FieldCmp>, FieldCmp> childrenMap;
- // Rebuild the field tree.
- for (auto it = fieldValueMap.begin(); it != fieldValueMap.end(); ++it) {
- addOrUpdateChildrenMap(it->first, &childrenMap);
- }
- std::stack<std::pair<long long, Field>> tokenStack;
- // Iterate over the node tree to fill the Atom proto.
- for (auto it = childrenMap.begin(); it != childrenMap.end(); ++it) {
- const Field* nodeLeaf = getSingleLeaf(&it->first);
- const int fieldNum = nodeLeaf->field();
- while (!tokenStack.empty()) {
- auto currentMsgNode = tokenStack.top().second;
- auto currentMsgNodeChildrenIt = childrenMap.find(currentMsgNode);
- if (currentMsgNodeChildrenIt->second.find(it->first) ==
- currentMsgNodeChildrenIt->second.end()) {
- protoOutput->end(tokenStack.top().first);
- tokenStack.pop();
- } else {
- break;
- }
- }
- if (it->second.size() == 0) {
- auto itValue = fieldValueMap.find(it->first);
- if (itValue != fieldValueMap.end()) {
- const DimensionsValue& value = itValue->second;
- switch (value.value_case()) {
- case DimensionsValue::ValueCase::kValueStr:
- protoOutput->write(FIELD_TYPE_STRING | fieldNum,
- value.value_str());
- break;
- case DimensionsValue::ValueCase::kValueInt:
- protoOutput->write(FIELD_TYPE_INT32 | fieldNum,
- value.value_int());
- break;
- case DimensionsValue::ValueCase::kValueLong:
- protoOutput->write(FIELD_TYPE_INT64 | fieldNum,
- value.value_long());
- break;
- case DimensionsValue::ValueCase::kValueBool:
- protoOutput->write(FIELD_TYPE_BOOL | fieldNum,
- value.value_bool());
- break;
- case DimensionsValue::ValueCase::kValueFloat:
- protoOutput->write(FIELD_TYPE_FLOAT | fieldNum,
- value.value_float());
- break;
- // This would not happen as the node has no child.
- case DimensionsValue::ValueCase::kValueTuple:
- break;
- default:
- break;
- }
- } else {
- ALOGE("Leaf node value not found. This should never happen.");
- }
- } else {
- long long token;
- if (nodeLeaf->has_position_index()) {
- token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | fieldNum);
- } else {
- token = protoOutput->start(FIELD_TYPE_MESSAGE | fieldNum);
- }
- tokenStack.push(std::make_pair(token, it->first));
- }
- }
+ long long atomToken = protoOutput->start(FIELD_TYPE_MESSAGE | tagId);
- while (!tokenStack.empty()) {
- protoOutput->end(tokenStack.top().first);
- tokenStack.pop();
+ size_t index = 0;
+ writeFieldValueTreeToStreamHelper(values, &index, 0, 0, protoOutput);
+ protoOutput->end(atomToken);
+}
+
+int64_t TimeUnitToBucketSizeInMillisGuardrailed(int uid, TimeUnit unit) {
+ int64_t bucketSizeMillis = TimeUnitToBucketSizeInMillis(unit);
+ if (bucketSizeMillis > 1000 && bucketSizeMillis < 5 * 60 * 1000LL && uid != AID_SHELL) {
+ bucketSizeMillis = 5 * 60 * 1000LL;
}
+ return bucketSizeMillis;
}
int64_t TimeUnitToBucketSizeInMillis(TimeUnit unit) {
@@ -274,6 +266,30 @@
protoOutput->end(token);
}
+int64_t getElapsedRealtimeNs() {
+ return ::android::elapsedRealtimeNano();
+}
+
+int64_t getElapsedRealtimeSec() {
+ return ::android::elapsedRealtimeNano() / NS_PER_SEC;
+}
+
+int64_t getElapsedRealtimeMillis() {
+ return ::android::elapsedRealtime();
+}
+
+int64_t getWallClockNs() {
+ return time(nullptr) * NS_PER_SEC;
+}
+
+int64_t getWallClockSec() {
+ return time(nullptr);
+}
+
+int64_t getWallClockMillis() {
+ return time(nullptr) * MS_PER_SEC;
+}
+
} // namespace statsd
} // namespace os
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/src/stats_log_util.h b/cmds/statsd/src/stats_log_util.h
index cee9200..6a5123d 100644
--- a/cmds/statsd/src/stats_log_util.h
+++ b/cmds/statsd/src/stats_log_util.h
@@ -17,7 +17,8 @@
#pragma once
#include <android/util/ProtoOutputStream.h>
-#include "field_util.h"
+#include "FieldValue.h"
+#include "HashableDimensionKey.h"
#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
#include "guardrail/StatsdStats.h"
@@ -26,20 +27,36 @@
namespace os {
namespace statsd {
-// Helper function to write DimensionsValue proto to ProtoOutputStream.
-void writeDimensionsValueProtoToStream(const DimensionsValue& fieldValue,
- util::ProtoOutputStream* protoOutput);
-
-// Helper function to write Field proto to ProtoOutputStream.
-void writeFieldProtoToStream(const Field& field, util::ProtoOutputStream* protoOutput);
-
-// Helper function to construct the field value tree and write to ProtoOutputStream
-void writeFieldValueTreeToStream(const FieldValueMap& fieldValueMap,
+void writeFieldValueTreeToStream(int tagId, const std::vector<FieldValue>& values,
util::ProtoOutputStream* protoOutput);
+void writeDimensionToProto(const HashableDimensionKey& dimension,
+ util::ProtoOutputStream* protoOutput);
+
+// Convert the TimeUnit enum to the bucket size in millis with a guardrail on
+// bucket size.
+int64_t TimeUnitToBucketSizeInMillisGuardrailed(int uid, TimeUnit unit);
// Convert the TimeUnit enum to the bucket size in millis.
int64_t TimeUnitToBucketSizeInMillis(TimeUnit unit);
+// Gets the elapsed timestamp in ns.
+int64_t getElapsedRealtimeNs();
+
+// Gets the elapsed timestamp in millis.
+int64_t getElapsedRealtimeMillis();
+
+// Gets the elapsed timestamp in seconds.
+int64_t getElapsedRealtimeSec();
+
+// Gets the wall clock timestamp in ns.
+int64_t getWallClockNs();
+
+// Gets the wall clock timestamp in millis.
+int64_t getWallClockMillis();
+
+// Gets the wall clock timestamp in seconds.
+int64_t getWallClockSec();
+
// Helper function to write PulledAtomStats to ProtoOutputStream
void writePullerStatsToStream(const std::pair<int, StatsdStats::PulledAtomStats>& pair,
util::ProtoOutputStream* protoOutput);
@@ -58,4 +75,4 @@
} // namespace statsd
} // namespace os
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/src/statsd_internal.proto b/cmds/statsd/src/statsd_internal.proto
deleted file mode 100644
index 25aacee..0000000
--- a/cmds/statsd/src/statsd_internal.proto
+++ /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.
- */
-
-syntax = "proto2";
-option optimize_for = LITE_RUNTIME;
-
-package android.os.statsd;
-
-option java_package = "com.android.os";
-option java_outer_classname = "StatsdInternalProto";
-
-message Field {
- optional int32 field = 1;
- optional int32 position_index = 2 [default = -1];
- repeated Field child = 3;
-}
diff --git a/cmds/statsd/src/storage/StorageManager.cpp b/cmds/statsd/src/storage/StorageManager.cpp
index 23bd5561..6a1db72 100644
--- a/cmds/statsd/src/storage/StorageManager.cpp
+++ b/cmds/statsd/src/storage/StorageManager.cpp
@@ -20,6 +20,7 @@
#include "android-base/stringprintf.h"
#include "guardrail/StatsdStats.h"
#include "storage/StorageManager.h"
+#include "stats_log_util.h"
#include <android-base/file.h>
#include <dirent.h>
@@ -252,7 +253,7 @@
string file_name = getFilePath(path, timestamp, uid, configID);
// Check for timestamp and delete if it's too old.
- long fileAge = time(nullptr) - timestamp;
+ long fileAge = getWallClockSec() - timestamp;
if (fileAge > StatsdStats::kMaxAgeSecond) {
deleteFile(file_name.c_str());
}
diff --git a/cmds/statsd/src/subscriber/SubscriberReporter.cpp b/cmds/statsd/src/subscriber/SubscriberReporter.cpp
index 3af684f..9f68fc4 100644
--- a/cmds/statsd/src/subscriber/SubscriberReporter.cpp
+++ b/cmds/statsd/src/subscriber/SubscriberReporter.cpp
@@ -98,50 +98,66 @@
ALOGW("Failed to send subscriber broadcast: could not access StatsCompanionService.");
return;
}
- mStatsCompanionService->sendSubscriberBroadcast(intentSender,
- configKey.GetUid(),
- configKey.GetId(),
- subscription.id(),
- subscription.rule_id(),
- protoToStatsDimensionsValue(dimKey));
+ mStatsCompanionService->sendSubscriberBroadcast(
+ intentSender, configKey.GetUid(), configKey.GetId(), subscription.id(),
+ subscription.rule_id(), getStatsDimensionsValue(dimKey.getDimensionKeyInWhat()));
}
-StatsDimensionsValue SubscriberReporter::protoToStatsDimensionsValue(
- const MetricDimensionKey& dimKey) {
- return protoToStatsDimensionsValue(dimKey.getDimensionKeyInWhat().getDimensionsValue());
-}
-
-StatsDimensionsValue SubscriberReporter::protoToStatsDimensionsValue(
- const DimensionsValue& protoDimsVal) {
- int32_t field = protoDimsVal.field();
-
- switch (protoDimsVal.value_case()) {
- case DimensionsValue::ValueCase::kValueStr:
- return StatsDimensionsValue(field, String16(protoDimsVal.value_str().c_str()));
- case DimensionsValue::ValueCase::kValueInt:
- return StatsDimensionsValue(field, static_cast<int32_t>(protoDimsVal.value_int()));
- case DimensionsValue::ValueCase::kValueLong:
- return StatsDimensionsValue(field, static_cast<int64_t>(protoDimsVal.value_long()));
- case DimensionsValue::ValueCase::kValueBool:
- return StatsDimensionsValue(field, static_cast<bool>(protoDimsVal.value_bool()));
- case DimensionsValue::ValueCase::kValueFloat:
- return StatsDimensionsValue(field, static_cast<float>(protoDimsVal.value_float()));
- case DimensionsValue::ValueCase::kValueTuple:
- {
- int sz = protoDimsVal.value_tuple().dimensions_value_size();
- std::vector<StatsDimensionsValue> sdvVec(sz);
- for (int i = 0; i < sz; i++) {
- sdvVec[i] = protoToStatsDimensionsValue(
- protoDimsVal.value_tuple().dimensions_value(i));
- }
- return StatsDimensionsValue(field, sdvVec);
+void getStatsDimensionsValueHelper(const std::vector<FieldValue>& dims, size_t* index, int depth,
+ int prefix, vector<StatsDimensionsValue>* output) {
+ size_t count = dims.size();
+ while (*index < count) {
+ const auto& dim = dims[*index];
+ const int valueDepth = dim.mField.getDepth();
+ const int valuePrefix = dim.mField.getPrefix(depth);
+ if (valueDepth > 2) {
+ ALOGE("Depth > 2 not supported");
+ return;
+ }
+ if (depth == valueDepth && valuePrefix == prefix) {
+ switch (dim.mValue.getType()) {
+ case INT:
+ output->push_back(StatsDimensionsValue(dim.mField.getPosAtDepth(depth),
+ dim.mValue.int_value));
+ break;
+ case LONG:
+ output->push_back(StatsDimensionsValue(dim.mField.getPosAtDepth(depth),
+ dim.mValue.long_value));
+ break;
+ case FLOAT:
+ output->push_back(StatsDimensionsValue(dim.mField.getPosAtDepth(depth),
+ dim.mValue.float_value));
+ break;
+ case STRING:
+ output->push_back(StatsDimensionsValue(dim.mField.getPosAtDepth(depth),
+ String16(dim.mValue.str_value.c_str())));
+ break;
+ default:
+ break;
}
- default:
- ALOGW("protoToStatsDimensionsValue failed: illegal type.");
- return StatsDimensionsValue();
+ (*index)++;
+ } else if (valueDepth > depth && valuePrefix == prefix) {
+ vector<StatsDimensionsValue> childOutput;
+ getStatsDimensionsValueHelper(dims, index, depth + 1, dim.mField.getPrefix(depth + 1),
+ &childOutput);
+ output->push_back(StatsDimensionsValue(dim.mField.getPosAtDepth(depth), childOutput));
+ } else {
+ return;
+ }
}
}
+StatsDimensionsValue SubscriberReporter::getStatsDimensionsValue(const HashableDimensionKey& dim) {
+ if (dim.getValues().size() == 0) {
+ return StatsDimensionsValue();
+ }
+
+ vector<StatsDimensionsValue> fields;
+ size_t index = 0;
+ getStatsDimensionsValueHelper(dim.getValues(), &index, 0, 0, &fields);
+ return StatsDimensionsValue(dim.getValues()[0].mField.getTag(), fields);
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/subscriber/SubscriberReporter.h b/cmds/statsd/src/subscriber/SubscriberReporter.h
index 13fc7fd..c7d1a5b 100644
--- a/cmds/statsd/src/subscriber/SubscriberReporter.h
+++ b/cmds/statsd/src/subscriber/SubscriberReporter.h
@@ -82,6 +82,8 @@
const Subscription& subscription,
const MetricDimensionKey& dimKey) const;
+ static StatsDimensionsValue getStatsDimensionsValue(const HashableDimensionKey& dim);
+
private:
SubscriberReporter() {};
@@ -102,14 +104,6 @@
const ConfigKey& configKey,
const Subscription& subscription,
const MetricDimensionKey& dimKey) const;
-
- /** Converts a stats_log.proto DimensionsValue to a StatsDimensionsValue. */
- static StatsDimensionsValue protoToStatsDimensionsValue(
- const DimensionsValue& protoDimsVal);
-
- /** Converts a HashableDimensionKey to a StatsDimensionsValue. */
- static StatsDimensionsValue protoToStatsDimensionsValue(
- const MetricDimensionKey& dimKey);
};
} // namespace statsd
diff --git a/cmds/statsd/tests/FieldValue_test.cpp b/cmds/statsd/tests/FieldValue_test.cpp
new file mode 100644
index 0000000..f1ad0c8
--- /dev/null
+++ b/cmds/statsd/tests/FieldValue_test.cpp
@@ -0,0 +1,350 @@
+/*
+ * 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.
+ */
+#include <gtest/gtest.h>
+#include "src/logd/LogEvent.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "matchers/matcher_util.h"
+#include "stats_log_util.h"
+#include "stats_util.h"
+#include "subscriber/SubscriberReporter.h"
+
+#ifdef __ANDROID__
+
+namespace android {
+namespace os {
+namespace statsd {
+
+TEST(AtomMatcherTest, TestFieldTranslation) {
+ FieldMatcher matcher1;
+ matcher1.set_field(10);
+ FieldMatcher* child = matcher1.add_child();
+ child->set_field(1);
+ child->set_position(Position::ANY);
+
+ child = child->add_child();
+ child->set_field(1);
+
+ vector<Matcher> output;
+ translateFieldMatcher(matcher1, &output);
+
+ EXPECT_EQ((size_t)1, output.size());
+
+ const auto& matcher12 = output[0];
+ EXPECT_EQ((int32_t)10, matcher12.mMatcher.getTag());
+ EXPECT_EQ((int32_t)0x2010001, matcher12.mMatcher.getField());
+ EXPECT_EQ((int32_t)0xff7f007f, matcher12.mMask);
+}
+
+TEST(AtomMatcherTest, TestFilter) {
+ FieldMatcher matcher1;
+ matcher1.set_field(10);
+ FieldMatcher* child = matcher1.add_child();
+ child->set_field(1);
+ child->set_position(Position::ANY);
+
+ child = child->add_child();
+ child->set_field(1);
+
+ child = matcher1.add_child();
+ child->set_field(2);
+
+ vector<Matcher> matchers;
+ translateFieldMatcher(matcher1, &matchers);
+
+ AttributionNode attribution_node1;
+ attribution_node1.set_uid(1111);
+ attribution_node1.set_tag("location1");
+
+ AttributionNode attribution_node2;
+ attribution_node2.set_uid(2222);
+ attribution_node2.set_tag("location2");
+
+ AttributionNode attribution_node3;
+ attribution_node3.set_uid(3333);
+ attribution_node3.set_tag("location3");
+ std::vector<AttributionNode> attribution_nodes = {attribution_node1, attribution_node2,
+ attribution_node3};
+
+ // Set up the event
+ LogEvent event(10, 12345);
+ event.write(attribution_nodes);
+ event.write("some value");
+ // Convert to a LogEvent
+ event.init();
+ vector<HashableDimensionKey> output;
+
+ filterValues(matchers, event.getValues(), &output);
+
+ EXPECT_EQ((size_t)(3), output.size());
+
+ const auto& key1 = output[0];
+ EXPECT_EQ((size_t)2, key1.getValues().size());
+ EXPECT_EQ((int32_t)0x02010001, key1.getValues()[0].mField.getField());
+ EXPECT_EQ((int32_t)1111, key1.getValues()[0].mValue.int_value);
+ EXPECT_EQ((int32_t)0x00020000, key1.getValues()[1].mField.getField());
+ EXPECT_EQ("some value", key1.getValues()[1].mValue.str_value);
+
+ const auto& key2 = output[1];
+ EXPECT_EQ((size_t)2, key2.getValues().size());
+ EXPECT_EQ((int32_t)0x02010001, key2.getValues()[0].mField.getField());
+ EXPECT_EQ((int32_t)2222, key2.getValues()[0].mValue.int_value);
+ EXPECT_EQ((int32_t)0x00020000, key2.getValues()[1].mField.getField());
+ EXPECT_EQ("some value", key2.getValues()[1].mValue.str_value);
+
+ const auto& key3 = output[2];
+ EXPECT_EQ((size_t)2, key3.getValues().size());
+ EXPECT_EQ((int32_t)0x02010001, key3.getValues()[0].mField.getField());
+ EXPECT_EQ((int32_t)3333, key3.getValues()[0].mValue.int_value);
+ EXPECT_EQ((int32_t)0x00020000, key3.getValues()[1].mField.getField());
+ EXPECT_EQ("some value", key3.getValues()[1].mValue.str_value);
+}
+
+TEST(AtomMatcherTest, TestSubDimension) {
+ HashableDimensionKey dim;
+
+ int pos1[] = {1, 1, 1};
+ int pos2[] = {1, 1, 2};
+ int pos3[] = {1, 1, 3};
+ int pos4[] = {2, 0, 0};
+ Field field1(10, pos1, 2);
+ Field field2(10, pos2, 2);
+
+ Field field3(10, pos3, 2);
+ Field field4(10, pos4, 0);
+
+ Value value1((int32_t)10025);
+ Value value2("tag");
+
+ Value value11((int32_t)10026);
+ Value value22("tag2");
+
+ dim.addValue(FieldValue(field1, value1));
+ dim.addValue(FieldValue(field2, value2));
+
+ HashableDimensionKey subDim1;
+ subDim1.addValue(FieldValue(field1, value1));
+
+ HashableDimensionKey subDim2;
+ subDim1.addValue(FieldValue(field2, value2));
+
+ EXPECT_TRUE(dim.contains(dim));
+ EXPECT_TRUE(dim.contains(subDim1));
+ EXPECT_TRUE(dim.contains(subDim2));
+
+ HashableDimensionKey subDim3;
+ subDim3.addValue(FieldValue(field1, value11));
+ EXPECT_FALSE(dim.contains(subDim3));
+
+ HashableDimensionKey subDim4;
+ // Empty dimension is always a sub dimension of other dimensions
+ EXPECT_TRUE(dim.contains(subDim4));
+}
+
+TEST(AtomMatcherTest, TestMetric2ConditionLink) {
+ AttributionNode attribution_node1;
+ attribution_node1.set_uid(1111);
+ attribution_node1.set_tag("location1");
+
+ AttributionNode attribution_node2;
+ attribution_node2.set_uid(2222);
+ attribution_node2.set_tag("location2");
+
+ AttributionNode attribution_node3;
+ attribution_node3.set_uid(3333);
+ attribution_node3.set_tag("location3");
+ std::vector<AttributionNode> attribution_nodes = {attribution_node1, attribution_node2,
+ attribution_node3};
+
+ // Set up the event
+ LogEvent event(10, 12345);
+ event.write(attribution_nodes);
+ event.write("some value");
+ // Convert to a LogEvent
+ event.init();
+
+ FieldMatcher whatMatcher;
+ whatMatcher.set_field(10);
+ FieldMatcher* child11 = whatMatcher.add_child();
+ child11->set_field(1);
+ child11->set_position(Position::ANY);
+ child11 = child11->add_child();
+ child11->set_field(1);
+
+ FieldMatcher conditionMatcher;
+ conditionMatcher.set_field(27);
+ FieldMatcher* child2 = conditionMatcher.add_child();
+ child2->set_field(2);
+ child2->set_position(Position::LAST);
+
+ child2 = child2->add_child();
+ child2->set_field(2);
+
+ Metric2Condition link;
+
+ translateFieldMatcher(whatMatcher, &link.metricFields);
+ translateFieldMatcher(conditionMatcher, &link.conditionFields);
+
+ EXPECT_EQ((size_t)1, link.metricFields.size());
+ EXPECT_EQ((int32_t)0x02010001, link.metricFields[0].mMatcher.getField());
+ EXPECT_EQ((int32_t)0xff7f007f, link.metricFields[0].mMask);
+ EXPECT_EQ((int32_t)10, link.metricFields[0].mMatcher.getTag());
+
+ EXPECT_EQ((size_t)1, link.conditionFields.size());
+ EXPECT_EQ((int32_t)0x02028002, link.conditionFields[0].mMatcher.getField());
+ EXPECT_EQ((int32_t)0xff7f807f, link.conditionFields[0].mMask);
+ EXPECT_EQ((int32_t)27, link.conditionFields[0].mMatcher.getTag());
+}
+
+TEST(AtomMatcherTest, TestSubscriberDimensionWrite) {
+ HashableDimensionKey dim;
+
+ int pos1[] = {1, 1, 1};
+ int pos2[] = {1, 1, 2};
+ int pos3[] = {1, 1, 3};
+ int pos4[] = {2, 0, 0};
+
+ Field field1(10, pos1, 2);
+ Field field2(10, pos2, 2);
+ Field field3(10, pos3, 2);
+ Field field4(10, pos4, 0);
+
+ Value value1((int32_t)10025);
+ Value value2("tag");
+ Value value3((int32_t)987654);
+ Value value4((int32_t)99999);
+
+ dim.addValue(FieldValue(field1, value1));
+ dim.addValue(FieldValue(field2, value2));
+ dim.addValue(FieldValue(field3, value3));
+ dim.addValue(FieldValue(field4, value4));
+
+ SubscriberReporter::getStatsDimensionsValue(dim);
+ // TODO: can't test anything here because SubscriberReport class doesn't have any read api.
+}
+
+TEST(AtomMatcherTest, TestWriteDimensionToProto) {
+ HashableDimensionKey dim;
+ int pos1[] = {1, 1, 1};
+ int pos2[] = {1, 1, 2};
+ int pos3[] = {1, 1, 3};
+ int pos4[] = {2, 0, 0};
+ Field field1(10, pos1, 2);
+ Field field2(10, pos2, 2);
+ Field field3(10, pos3, 2);
+ Field field4(10, pos4, 0);
+
+ Value value1((int32_t)10025);
+ Value value2("tag");
+ Value value3((int32_t)987654);
+ Value value4((int32_t)99999);
+
+ dim.addValue(FieldValue(field1, value1));
+ dim.addValue(FieldValue(field2, value2));
+ dim.addValue(FieldValue(field3, value3));
+ dim.addValue(FieldValue(field4, value4));
+
+ android::util::ProtoOutputStream protoOut;
+ writeDimensionToProto(dim, &protoOut);
+
+ vector<uint8_t> outData;
+ outData.resize(protoOut.size());
+ size_t pos = 0;
+ auto iter = protoOut.data();
+ while (iter.readBuffer() != NULL) {
+ size_t toRead = iter.currentToRead();
+ std::memcpy(&(outData[pos]), iter.readBuffer(), toRead);
+ pos += toRead;
+ iter.rp()->move(toRead);
+ }
+
+ DimensionsValue result;
+ EXPECT_EQ(true, result.ParseFromArray(&outData[0], outData.size()));
+ EXPECT_EQ(10, result.field());
+ EXPECT_EQ(DimensionsValue::ValueCase::kValueTuple, result.value_case());
+ EXPECT_EQ(2, result.value_tuple().dimensions_value_size());
+
+ const auto& dim1 = result.value_tuple().dimensions_value(0);
+ EXPECT_EQ(DimensionsValue::ValueCase::kValueTuple, dim1.value_case());
+ EXPECT_EQ(3, dim1.value_tuple().dimensions_value_size());
+
+ const auto& dim11 = dim1.value_tuple().dimensions_value(0);
+ EXPECT_EQ(DimensionsValue::ValueCase::kValueInt, dim11.value_case());
+ EXPECT_EQ(10025, dim11.value_int());
+
+ const auto& dim12 = dim1.value_tuple().dimensions_value(1);
+ EXPECT_EQ(DimensionsValue::ValueCase::kValueStr, dim12.value_case());
+ EXPECT_EQ("tag", dim12.value_str());
+
+ const auto& dim13 = dim1.value_tuple().dimensions_value(2);
+ EXPECT_EQ(DimensionsValue::ValueCase::kValueInt, dim13.value_case());
+ EXPECT_EQ(987654, dim13.value_int());
+
+ const auto& dim2 = result.value_tuple().dimensions_value(1);
+ EXPECT_EQ(DimensionsValue::ValueCase::kValueInt, dim2.value_case());
+ EXPECT_EQ(99999, dim2.value_int());
+}
+
+TEST(AtomMatcherTest, TestWriteAtomToProto) {
+ AttributionNode attribution_node1;
+ attribution_node1.set_uid(1111);
+ attribution_node1.set_tag("location1");
+
+ AttributionNode attribution_node2;
+ attribution_node2.set_uid(2222);
+ attribution_node2.set_tag("location2");
+
+ std::vector<AttributionNode> attribution_nodes = {attribution_node1, attribution_node2};
+
+ // Set up the event
+ LogEvent event(4, 12345);
+ event.write(attribution_nodes);
+ event.write((int32_t)999);
+ // Convert to a LogEvent
+ event.init();
+
+ android::util::ProtoOutputStream protoOutput;
+ writeFieldValueTreeToStream(event.GetTagId(), event.getValues(), &protoOutput);
+
+ vector<uint8_t> outData;
+ outData.resize(protoOutput.size());
+ size_t pos = 0;
+ auto iter = protoOutput.data();
+ while (iter.readBuffer() != NULL) {
+ size_t toRead = iter.currentToRead();
+ std::memcpy(&(outData[pos]), iter.readBuffer(), toRead);
+ pos += toRead;
+ iter.rp()->move(toRead);
+ }
+
+ Atom result;
+ EXPECT_EQ(true, result.ParseFromArray(&outData[0], outData.size()));
+ EXPECT_EQ(Atom::PushedCase::kBleScanResultReceived, result.pushed_case());
+ const auto& atom = result.ble_scan_result_received();
+ EXPECT_EQ(2, atom.attribution_node_size());
+ EXPECT_EQ(1111, atom.attribution_node(0).uid());
+ EXPECT_EQ("location1", atom.attribution_node(0).tag());
+ EXPECT_EQ(2222, atom.attribution_node(1).uid());
+ EXPECT_EQ("location2", atom.attribution_node(1).tag());
+ EXPECT_EQ(999, atom.num_of_results());
+}
+
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
\ No newline at end of file
diff --git a/cmds/statsd/tests/LogEntryMatcher_test.cpp b/cmds/statsd/tests/LogEntryMatcher_test.cpp
index 111b4ba..1023ea4 100644
--- a/cmds/statsd/tests/LogEntryMatcher_test.cpp
+++ b/cmds/statsd/tests/LogEntryMatcher_test.cpp
@@ -14,6 +14,7 @@
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
#include "matchers/matcher_util.h"
+#include "stats_log_util.h"
#include "stats_util.h"
#include <gtest/gtest.h>
@@ -35,8 +36,6 @@
const int ATTRIBUTION_UID_FIELD_ID = 1;
const int ATTRIBUTION_TAG_FIELD_ID = 2;
-// Private API from liblog.
-extern "C" void android_log_rewind(android_log_context ctx);
#ifdef __ANDROID__
TEST(AtomMatcherTest, TestSimpleMatcher) {
@@ -597,7 +596,6 @@
matcherResults.push_back(MatchingState::kMatched);
EXPECT_FALSE(combinationMatch(children, operation, matcherResults));
}
-
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
diff --git a/cmds/statsd/tests/LogEvent_test.cpp b/cmds/statsd/tests/LogEvent_test.cpp
index fd28460..b649215 100644
--- a/cmds/statsd/tests/LogEvent_test.cpp
+++ b/cmds/statsd/tests/LogEvent_test.cpp
@@ -22,548 +22,142 @@
namespace os {
namespace statsd {
-TEST(LogEventTest, testEmptyEvent) {
- const int32_t TAG_ID = 123;
- LogEvent event(TAG_ID, 0);
- event.init();
+TEST(LogEventTest, TestLogParsing) {
+ LogEvent event1(1, 2000);
- DimensionsValue dimensionsValue;
- EXPECT_FALSE(event.GetSimpleAtomDimensionsValueProto(234, &dimensionsValue));
- FieldMatcher dimensions;
- dimensions.set_field(event.GetTagId());
- EXPECT_FALSE(event.GetAtomDimensionsValueProto(dimensions, &dimensionsValue));
+ std::vector<AttributionNode> nodes;
- dimensions.add_child()->set_field(3);
- dimensions.mutable_child(0)->set_position(Position::FIRST);
- EXPECT_FALSE(event.GetAtomDimensionsValueProto(dimensions, &dimensionsValue));
+ AttributionNode node1;
+ node1.set_uid(1000);
+ node1.set_tag("tag1");
+ nodes.push_back(node1);
- dimensions.mutable_child(0)->set_position(Position::ANY);
- EXPECT_FALSE(event.GetAtomDimensionsValueProto(dimensions, &dimensionsValue));
+ AttributionNode node2;
+ node2.set_uid(2000);
+ node2.set_tag("tag2");
+ nodes.push_back(node2);
- dimensions.mutable_child(0)->set_position(Position::LAST);
- EXPECT_FALSE(event.GetAtomDimensionsValueProto(dimensions, &dimensionsValue));
+ event1.write(nodes);
+ event1.write("hello");
+ event1.write((int32_t)10);
+ event1.write((int64_t)20);
+ event1.write((float)1.1);
+ event1.init();
+
+ const auto& items = event1.getValues();
+ EXPECT_EQ((size_t)8, items.size());
+ EXPECT_EQ(1, event1.GetTagId());
+
+ const FieldValue& item0 = event1.getValues()[0];
+ EXPECT_EQ(0x2010101, item0.mField.getField());
+ EXPECT_EQ(Type::INT, item0.mValue.getType());
+ EXPECT_EQ(1000, item0.mValue.int_value);
+
+ const FieldValue& item1 = event1.getValues()[1];
+ EXPECT_EQ(0x2010182, item1.mField.getField());
+ EXPECT_EQ(Type::STRING, item1.mValue.getType());
+ EXPECT_EQ("tag1", item1.mValue.str_value);
+
+ const FieldValue& item2 = event1.getValues()[2];
+ EXPECT_EQ(0x2018201, item2.mField.getField());
+ EXPECT_EQ(Type::INT, item2.mValue.getType());
+ EXPECT_EQ(2000, item2.mValue.int_value);
+
+ const FieldValue& item3 = event1.getValues()[3];
+ EXPECT_EQ(0x2018282, item3.mField.getField());
+ EXPECT_EQ(Type::STRING, item3.mValue.getType());
+ EXPECT_EQ("tag2", item3.mValue.str_value);
+
+ const FieldValue& item4 = event1.getValues()[4];
+ EXPECT_EQ(0x20000, item4.mField.getField());
+ EXPECT_EQ(Type::STRING, item4.mValue.getType());
+ EXPECT_EQ("hello", item4.mValue.str_value);
+
+ const FieldValue& item5 = event1.getValues()[5];
+ EXPECT_EQ(0x30000, item5.mField.getField());
+ EXPECT_EQ(Type::INT, item5.mValue.getType());
+ EXPECT_EQ(10, item5.mValue.int_value);
+
+ const FieldValue& item6 = event1.getValues()[6];
+ EXPECT_EQ(0x40000, item6.mField.getField());
+ EXPECT_EQ(Type::LONG, item6.mValue.getType());
+ EXPECT_EQ((int64_t)20, item6.mValue.long_value);
+
+ const FieldValue& item7 = event1.getValues()[7];
+ EXPECT_EQ(0x50000, item7.mField.getField());
+ EXPECT_EQ(Type::FLOAT, item7.mValue.getType());
+ EXPECT_EQ((float)1.1, item7.mValue.float_value);
}
-TEST(LogEventTest, testRepeatedAttributionNode) {
- const int32_t TAG_ID = 123;
- LogEvent event(TAG_ID, 0);
- AttributionNode attribution_node1;
- attribution_node1.set_uid(1111);
- attribution_node1.set_tag("locationService");
+TEST(LogEventTest, TestLogParsing2) {
+ LogEvent event1(1, 2000);
- AttributionNode attribution_node2;
- attribution_node2.set_uid(2222);
- attribution_node2.set_tag("locationService2");
+ std::vector<AttributionNode> nodes;
- AttributionNode attribution_node3;
- attribution_node3.set_uid(3333);
- attribution_node3.set_tag("locationService3");
- std::vector<AttributionNode> attribution_nodes =
- {attribution_node1, attribution_node2, attribution_node3};
+ event1.write("hello");
- // 1nd field: int32.
- EXPECT_TRUE(event.write(int32_t(11)));
- // 2rd field: float.
- EXPECT_TRUE(event.write(3.45f));
- // Here it assume that the atom proto contains a repeated AttributionNode field.
- // 3rd field: attribution node. This is repeated field.
- EXPECT_TRUE(event.write(attribution_nodes));
- // 4th field: bool.
- EXPECT_TRUE(event.write(true));
- // 5th field: long.
- EXPECT_TRUE(event.write(uint64_t(1234)));
+ // repeated msg can be in the middle
+ AttributionNode node1;
+ node1.set_uid(1000);
+ node1.set_tag("tag1");
+ nodes.push_back(node1);
- event.init();
+ AttributionNode node2;
+ node2.set_uid(2000);
+ node2.set_tag("tag2");
+ nodes.push_back(node2);
+ event1.write(nodes);
- DimensionsValue dimensionsValue;
- // Query single primitive fields.
- EXPECT_TRUE(event.GetSimpleAtomDimensionsValueProto(1, &dimensionsValue));
- EXPECT_EQ(dimensionsValue.field(), event.GetTagId());
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value_size(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).field(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_int(), 11);
+ event1.write((int32_t)10);
+ event1.write((int64_t)20);
+ event1.write((float)1.1);
+ event1.init();
- EXPECT_TRUE(event.GetSimpleAtomDimensionsValueProto(2, &dimensionsValue));
- EXPECT_EQ(dimensionsValue.field(), event.GetTagId());
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value_size(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).field(), 2);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_float(), 3.45f);
+ const auto& items = event1.getValues();
+ EXPECT_EQ((size_t)8, items.size());
+ EXPECT_EQ(1, event1.GetTagId());
- EXPECT_TRUE(event.GetSimpleAtomDimensionsValueProto(4, &dimensionsValue));
- EXPECT_EQ(dimensionsValue.field(), event.GetTagId());
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value_size(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).field(), 4);
- // The bool value is stored in value_int field as logD does not support bool.
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_int(), true);
+ const FieldValue& item = event1.getValues()[0];
+ EXPECT_EQ(0x00010000, item.mField.getField());
+ EXPECT_EQ(Type::STRING, item.mValue.getType());
+ EXPECT_EQ("hello", item.mValue.str_value);
- EXPECT_TRUE(event.GetSimpleAtomDimensionsValueProto(5, &dimensionsValue));
- EXPECT_EQ(dimensionsValue.field(), event.GetTagId());
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value_size(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).field(), 5);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_long(), long(1234));
+ const FieldValue& item0 = event1.getValues()[1];
+ EXPECT_EQ(0x2020101, item0.mField.getField());
+ EXPECT_EQ(Type::INT, item0.mValue.getType());
+ EXPECT_EQ(1000, item0.mValue.int_value);
- // First attribution.
- FieldMatcher first_uid_dimensions;
- first_uid_dimensions.set_field(event.GetTagId());
- first_uid_dimensions.add_child()->set_field(3);
- first_uid_dimensions.mutable_child(0)->set_position(Position::FIRST);
- first_uid_dimensions.mutable_child(0)->add_child()->set_field(1);
- EXPECT_TRUE(event.GetAtomDimensionsValueProto(first_uid_dimensions, &dimensionsValue));
- EXPECT_EQ(dimensionsValue.field(), event.GetTagId());
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value_size(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).field(), 3);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value_size(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(0).field(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(0).value_int(), 1111);
+ const FieldValue& item1 = event1.getValues()[2];
+ EXPECT_EQ(0x2020182, item1.mField.getField());
+ EXPECT_EQ(Type::STRING, item1.mValue.getType());
+ EXPECT_EQ("tag1", item1.mValue.str_value);
- FieldMatcher first_tag_dimensions = first_uid_dimensions;
- first_tag_dimensions.mutable_child(0)->mutable_child(0)->set_field(2);
- EXPECT_TRUE(event.GetAtomDimensionsValueProto(first_tag_dimensions, &dimensionsValue));
- EXPECT_EQ(dimensionsValue.field(), event.GetTagId());
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value_size(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).field(), 3);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value_size(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(0).field(), 2);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(0).value_str(), "locationService");
+ const FieldValue& item2 = event1.getValues()[3];
+ EXPECT_EQ(0x2028201, item2.mField.getField());
+ EXPECT_EQ(Type::INT, item2.mValue.getType());
+ EXPECT_EQ(2000, item2.mValue.int_value);
- FieldMatcher first_attribution_dimensions = first_uid_dimensions;
- first_attribution_dimensions.mutable_child(0)->add_child()->set_field(2);
- EXPECT_TRUE(event.GetAtomDimensionsValueProto(first_attribution_dimensions, &dimensionsValue));
- EXPECT_EQ(dimensionsValue.field(), event.GetTagId());
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value_size(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).field(), 3);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value_size(), 2);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(0).field(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(0).value_int(), 1111);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(1).field(), 2);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(1).value_str(), "locationService");
+ const FieldValue& item3 = event1.getValues()[4];
+ EXPECT_EQ(0x2028282, item3.mField.getField());
+ EXPECT_EQ(Type::STRING, item3.mValue.getType());
+ EXPECT_EQ("tag2", item3.mValue.str_value);
- FieldMatcher last_attribution_dimensions = first_attribution_dimensions;
- last_attribution_dimensions.mutable_child(0)->set_position(Position::LAST);
- EXPECT_TRUE(event.GetAtomDimensionsValueProto(last_attribution_dimensions, &dimensionsValue));
- EXPECT_EQ(dimensionsValue.field(), event.GetTagId());
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value_size(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).field(), 3);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value_size(), 2);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(0).field(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(0).value_int(), 3333);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(1).field(), 2);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(1).value_str(), "locationService3");
+ const FieldValue& item5 = event1.getValues()[5];
+ EXPECT_EQ(0x30000, item5.mField.getField());
+ EXPECT_EQ(Type::INT, item5.mValue.getType());
+ EXPECT_EQ(10, item5.mValue.int_value);
- FieldMatcher any_attribution_dimensions = first_attribution_dimensions;
- any_attribution_dimensions.mutable_child(0)->set_position(Position::ANY);
- std::vector<DimensionsValue> dimensionsValues;
- event.GetAtomDimensionsValueProtos(any_attribution_dimensions, &dimensionsValues);
- EXPECT_EQ(dimensionsValues.size(), 3u);
- EXPECT_EQ(dimensionsValues[0].field(), event.GetTagId());
- EXPECT_EQ(dimensionsValues[0].value_tuple().dimensions_value_size(), 1);
- EXPECT_EQ(dimensionsValues[0].value_tuple().dimensions_value(0).field(), 3);
- EXPECT_EQ(dimensionsValues[0].value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value_size(), 2);
- EXPECT_EQ(dimensionsValues[0].value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(0).field(), 1);
- EXPECT_EQ(dimensionsValues[0].value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(0).value_int(), 1111);
- EXPECT_EQ(dimensionsValues[0].value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(1).field(), 2);
- EXPECT_EQ(dimensionsValues[0].value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(1).value_str(), "locationService");
- EXPECT_EQ(dimensionsValues[1].field(), event.GetTagId());
- EXPECT_EQ(dimensionsValues[1].value_tuple().dimensions_value_size(), 1);
- EXPECT_EQ(dimensionsValues[1].value_tuple().dimensions_value(0).field(), 3);
- EXPECT_EQ(dimensionsValues[1].value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value_size(), 2);
- EXPECT_EQ(dimensionsValues[1].value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(0).field(), 1);
- EXPECT_EQ(dimensionsValues[1].value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(0).value_int(), 2222);
- EXPECT_EQ(dimensionsValues[1].value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(1).field(), 2);
- EXPECT_EQ(dimensionsValues[1].value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(1).value_str(), "locationService2");
- EXPECT_EQ(dimensionsValues[2].field(), event.GetTagId());
- EXPECT_EQ(dimensionsValues[2].value_tuple().dimensions_value_size(), 1);
- EXPECT_EQ(dimensionsValues[2].value_tuple().dimensions_value(0).field(), 3);
- EXPECT_EQ(dimensionsValues[2].value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value_size(), 2);
- EXPECT_EQ(dimensionsValues[2].value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(0).field(), 1);
- EXPECT_EQ(dimensionsValues[2].value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(0).value_int(), 3333);
- EXPECT_EQ(dimensionsValues[2].value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(1).field(), 2);
- EXPECT_EQ(dimensionsValues[2].value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(1).value_str(), "locationService3");
+ const FieldValue& item6 = event1.getValues()[6];
+ EXPECT_EQ(0x40000, item6.mField.getField());
+ EXPECT_EQ(Type::LONG, item6.mValue.getType());
+ EXPECT_EQ((int64_t)20, item6.mValue.long_value);
- FieldMatcher mixed_dimensions = any_attribution_dimensions;
- mixed_dimensions.add_child()->set_field(1000);
- mixed_dimensions.add_child()->set_field(6); // missing field.
- mixed_dimensions.add_child()->set_field(3); // position not set.
- mixed_dimensions.add_child()->set_field(5);
- mixed_dimensions.add_child()->set_field(1);
- dimensionsValues.clear();
- event.GetAtomDimensionsValueProtos(mixed_dimensions, &dimensionsValues);
- EXPECT_EQ(dimensionsValues.size(), 3u);
- EXPECT_EQ(dimensionsValues[0].field(), event.GetTagId());
- EXPECT_EQ(dimensionsValues[0].value_tuple().dimensions_value_size(), 3);
- EXPECT_EQ(dimensionsValues[0].value_tuple().dimensions_value(0).field(), 3);
- EXPECT_EQ(dimensionsValues[0].value_tuple().dimensions_value(0).value_tuple().dimensions_value_size(), 2);
- EXPECT_EQ(dimensionsValues[0].value_tuple().dimensions_value(0).value_tuple().dimensions_value(0).field(), 1);
- EXPECT_EQ(dimensionsValues[0].value_tuple().dimensions_value(0).value_tuple().dimensions_value(0).value_int(),
- 1111);
- EXPECT_EQ(dimensionsValues[0].value_tuple().dimensions_value(0).value_tuple().dimensions_value(1).field(), 2);
- EXPECT_EQ(dimensionsValues[0].value_tuple().dimensions_value(0).value_tuple().dimensions_value(1).value_str(),
- "locationService");
- EXPECT_EQ(dimensionsValues[0].value_tuple().dimensions_value(1).field(), 5);
- EXPECT_EQ(dimensionsValues[0].value_tuple().dimensions_value(1).value_long(), long(1234));
- EXPECT_EQ(dimensionsValues[0].value_tuple().dimensions_value(2).field(), 1);
- EXPECT_EQ(dimensionsValues[0].value_tuple().dimensions_value(2).value_int(), 11);
-
- EXPECT_EQ(dimensionsValues[1].field(), event.GetTagId());
- EXPECT_EQ(dimensionsValues[1].value_tuple().dimensions_value_size(), 3);
- EXPECT_EQ(dimensionsValues[1].value_tuple().dimensions_value(0).field(), 3);
- EXPECT_EQ(dimensionsValues[1].value_tuple().dimensions_value(0).value_tuple().dimensions_value_size(), 2);
- EXPECT_EQ(dimensionsValues[1].value_tuple().dimensions_value(0).value_tuple().dimensions_value(0).field(), 1);
- EXPECT_EQ(dimensionsValues[1].value_tuple().dimensions_value(0).value_tuple().dimensions_value(0).value_int(),
- 2222);
- EXPECT_EQ(dimensionsValues[1].value_tuple().dimensions_value(0).value_tuple().dimensions_value(1).field(), 2);
- EXPECT_EQ(dimensionsValues[1].value_tuple().dimensions_value(0).value_tuple().dimensions_value(1).value_str(),
- "locationService2");
- EXPECT_EQ(dimensionsValues[1].value_tuple().dimensions_value(1).field(), 5);
- EXPECT_EQ(dimensionsValues[1].value_tuple().dimensions_value(1).value_long(), long(1234));
- EXPECT_EQ(dimensionsValues[1].value_tuple().dimensions_value(2).field(), 1);
- EXPECT_EQ(dimensionsValues[1].value_tuple().dimensions_value(2).value_int(), 11);
-
- EXPECT_EQ(dimensionsValues[2].field(), event.GetTagId());
- EXPECT_EQ(dimensionsValues[2].value_tuple().dimensions_value_size(), 3);
- EXPECT_EQ(dimensionsValues[2].value_tuple().dimensions_value(0).field(), 3);
- EXPECT_EQ(dimensionsValues[2].value_tuple().dimensions_value(0).value_tuple().dimensions_value_size(), 2);
- EXPECT_EQ(dimensionsValues[2].value_tuple().dimensions_value(0).value_tuple().dimensions_value(0).field(), 1);
- EXPECT_EQ(dimensionsValues[2].value_tuple().dimensions_value(0).value_tuple().dimensions_value(0).value_int(),
- 3333);
- EXPECT_EQ(dimensionsValues[2].value_tuple().dimensions_value(0).value_tuple().dimensions_value(1).field(), 2);
- EXPECT_EQ(dimensionsValues[2].value_tuple().dimensions_value(0).value_tuple().dimensions_value(1).value_str(),
- "locationService3");
- EXPECT_EQ(dimensionsValues[2].value_tuple().dimensions_value(1).field(), 5);
- EXPECT_EQ(dimensionsValues[2].value_tuple().dimensions_value(1).value_long(), long(1234));
- EXPECT_EQ(dimensionsValues[2].value_tuple().dimensions_value(2).field(), 1);
- EXPECT_EQ(dimensionsValues[2].value_tuple().dimensions_value(2).value_int(), 11);
-
- FieldMatcher wrong_dimensions = mixed_dimensions;
- // Wrong tagId.
- wrong_dimensions.set_field(event.GetTagId() + 100);
- dimensionsValues.clear();
- event.GetAtomDimensionsValueProtos(wrong_dimensions, &dimensionsValues);
- EXPECT_TRUE(dimensionsValues.empty());
+ const FieldValue& item7 = event1.getValues()[7];
+ EXPECT_EQ(0x50000, item7.mField.getField());
+ EXPECT_EQ(Type::FLOAT, item7.mValue.getType());
+ EXPECT_EQ((float)1.1, item7.mValue.float_value);
}
-TEST(LogEventTest, testMessageField) {
- const int32_t TAG_ID = 123;
- LogEvent event(TAG_ID, 0);
- AttributionNode attribution_node1;
- attribution_node1.set_uid(1111);
- attribution_node1.set_tag("locationService");
-
- AttributionNode attribution_node2;
- attribution_node2.set_uid(2222);
- attribution_node2.set_tag("locationService2");
-
- // 1nd field: int32.
- EXPECT_TRUE(event.write(int32_t(11)));
- // 2rd field: float.
- EXPECT_TRUE(event.write(3.45f));
- // Here it assume that the atom proto contains two optional AttributionNode fields.
- // 3rd field: attribution node. This is not repeated field.
- EXPECT_TRUE(event.write(attribution_node1));
- // 4th field: another attribution field. This is not repeated field.
- EXPECT_TRUE(event.write(attribution_node2));
- // 5th field: bool.
- EXPECT_TRUE(event.write(true));
- // 6th field: long.
- EXPECT_TRUE(event.write(uint64_t(1234)));
-
- event.init();
-
- FieldMatcher uid_dimensions1;
- uid_dimensions1.set_field(event.GetTagId());
- uid_dimensions1.add_child()->set_field(3);
- uid_dimensions1.mutable_child(0)->add_child()->set_field(1);
-
- FieldMatcher tag_dimensions1;
- tag_dimensions1.set_field(event.GetTagId());
- tag_dimensions1.add_child()->set_field(3);
- tag_dimensions1.mutable_child(0)->add_child()->set_field(2);
-
- FieldMatcher attribution_dimensions1;
- attribution_dimensions1.set_field(event.GetTagId());
- attribution_dimensions1.add_child()->set_field(3);
- attribution_dimensions1.mutable_child(0)->add_child()->set_field(1);
- attribution_dimensions1.mutable_child(0)->add_child()->set_field(2);
-
- FieldMatcher uid_dimensions2 = uid_dimensions1;
- uid_dimensions2.mutable_child(0)->set_field(4);
-
- FieldMatcher tag_dimensions2 = tag_dimensions1;
- tag_dimensions2.mutable_child(0)->set_field(4);
-
- FieldMatcher attribution_dimensions2 = attribution_dimensions1;
- attribution_dimensions2.mutable_child(0)->set_field(4);
-
- FieldMatcher mixed_dimensions = attribution_dimensions1;
- mixed_dimensions.add_child()->set_field(4);
- mixed_dimensions.mutable_child(1)->add_child()->set_field(1);
- mixed_dimensions.add_child()->set_field(1000);
- mixed_dimensions.add_child()->set_field(5);
- mixed_dimensions.add_child()->set_field(1);
-
- DimensionsValue dimensionsValue;
-
- // Query single primitive fields.
- EXPECT_TRUE(event.GetSimpleAtomDimensionsValueProto(1, &dimensionsValue));
- EXPECT_EQ(dimensionsValue.field(), event.GetTagId());
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value_size(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).field(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_int(), 11);
-
- EXPECT_TRUE(event.GetSimpleAtomDimensionsValueProto(2, &dimensionsValue));
- EXPECT_EQ(dimensionsValue.field(), event.GetTagId());
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value_size(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).field(), 2);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_float(), 3.45f);
-
- EXPECT_TRUE(event.GetSimpleAtomDimensionsValueProto(5, &dimensionsValue));
- EXPECT_EQ(dimensionsValue.field(), event.GetTagId());
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value_size(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).field(), 5);
- // The bool value is stored in value_int field as logD does not support bool.
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_int(), true);
-
- EXPECT_TRUE(event.GetSimpleAtomDimensionsValueProto(6, &dimensionsValue));
- EXPECT_EQ(dimensionsValue.field(), event.GetTagId());
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value_size(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).field(), 6);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_long(), long(1234));
-
- // Query atom field 3: attribution node uid field only.
- EXPECT_TRUE(event.GetAtomDimensionsValueProto(uid_dimensions1, &dimensionsValue));
- EXPECT_EQ(dimensionsValue.field(), event.GetTagId());
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value_size(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).field(), 3);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value_size(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(0).field(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(0).value_int(), 1111);
-
- // Query atom field 3: attribution node tag field only.
- EXPECT_TRUE(event.GetAtomDimensionsValueProto(tag_dimensions1, &dimensionsValue));
- EXPECT_EQ(dimensionsValue.field(), event.GetTagId());
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value_size(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).field(), 3);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value_size(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(0).field(), 2);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(0).value_str(), "locationService");
-
- // Query atom field 3: attribution node uid + tag fields.
- EXPECT_TRUE(event.GetAtomDimensionsValueProto(attribution_dimensions1, &dimensionsValue));
- EXPECT_EQ(dimensionsValue.field(), event.GetTagId());
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value_size(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).field(), 3);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value_size(), 2);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(0).field(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(0).value_int(), 1111);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(1).field(), 2);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(1).value_str(), "locationService");
-
- // Query atom field 4: attribution node uid field only.
- EXPECT_TRUE(event.GetAtomDimensionsValueProto(uid_dimensions2, &dimensionsValue));
- EXPECT_EQ(dimensionsValue.field(), event.GetTagId());
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value_size(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).field(), 4);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value_size(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(0).field(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(0).value_int(), 2222);
-
- // Query atom field 4: attribution node tag field only.
- EXPECT_TRUE(event.GetAtomDimensionsValueProto(tag_dimensions2, &dimensionsValue));
- EXPECT_EQ(dimensionsValue.field(), event.GetTagId());
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value_size(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).field(), 4);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value_size(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(0).field(), 2);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(0).value_str(), "locationService2");
-
- // Query atom field 4: attribution node uid + tag fields.
- EXPECT_TRUE(event.GetAtomDimensionsValueProto(attribution_dimensions2, &dimensionsValue));
- EXPECT_EQ(dimensionsValue.field(), event.GetTagId());
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value_size(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).field(), 4);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value_size(), 2);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(0).field(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(0).value_int(), 2222);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(1).field(), 2);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(1).value_str(), "locationService2");
-
- // Query multiple fields:
- // 1/ Field 3: attribution uid + tag.
- // 2/ Field 4: attribution uid only.
- // 3/ Field not exist.
- // 4/ Primitive fields #5
- // 5/ Primitive fields #1
- EXPECT_TRUE(event.GetAtomDimensionsValueProto(mixed_dimensions, &dimensionsValue));
- EXPECT_EQ(dimensionsValue.field(), event.GetTagId());
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value_size(), 4);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).field(), 3);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value_size(), 2);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(0).field(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(0).value_int(), 1111);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(1).field(), 2);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_tuple()
- .dimensions_value(1).value_str(), "locationService");
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(1).field(), 4);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(1).value_tuple()
- .dimensions_value_size(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(1).value_tuple()
- .dimensions_value(0).field(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(1).value_tuple()
- .dimensions_value(0).value_int(), 2222);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(2).field(), 5);
- // The bool value is stored in value_int field as logD does not support bool.
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(2).value_int(), true);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(3).field(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(3).value_int(), 11);
-}
-
-TEST(LogEventTest, testAllPrimitiveFields) {
- const int32_t TAG_ID = 123;
- LogEvent event(TAG_ID, 0);
-
- // 1nd field: int32.
- EXPECT_TRUE(event.write(int32_t(11)));
- // 2rd field: float.
- EXPECT_TRUE(event.write(3.45f));
- // 3th field: string.
- EXPECT_TRUE(event.write("test"));
- // 4th field: bool.
- EXPECT_TRUE(event.write(true));
- // 5th field: bool.
- EXPECT_TRUE(event.write(false));
- // 6th field: long.
- EXPECT_TRUE(event.write(uint64_t(1234)));
-
- event.init();
-
- DimensionsValue dimensionsValue;
- EXPECT_TRUE(event.GetSimpleAtomDimensionsValueProto(1, &dimensionsValue));
- EXPECT_EQ(dimensionsValue.field(), event.GetTagId());
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value_size(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).field(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_int(), 11);
-
- EXPECT_TRUE(event.GetSimpleAtomDimensionsValueProto(2, &dimensionsValue));
- EXPECT_EQ(dimensionsValue.field(), event.GetTagId());
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value_size(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).field(), 2);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_float(), 3.45f);
-
- EXPECT_TRUE(event.GetSimpleAtomDimensionsValueProto(3, &dimensionsValue));
- EXPECT_EQ(dimensionsValue.field(), event.GetTagId());
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value_size(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).field(), 3);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_str(), "test");
-
- EXPECT_TRUE(event.GetSimpleAtomDimensionsValueProto(4, &dimensionsValue));
- EXPECT_EQ(dimensionsValue.field(), event.GetTagId());
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value_size(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).field(), 4);
- // The bool value is stored in value_int field as logD does not support bool.
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_int(), true);
-
- EXPECT_TRUE(event.GetSimpleAtomDimensionsValueProto(5, &dimensionsValue));
- EXPECT_EQ(dimensionsValue.field(), event.GetTagId());
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value_size(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).field(), 5);
- // The bool value is stored in value_int field as logD does not support bool.
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_int(), false);
-
- EXPECT_TRUE(event.GetSimpleAtomDimensionsValueProto(6, &dimensionsValue));
- EXPECT_EQ(dimensionsValue.field(), event.GetTagId());
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value_size(), 1);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).field(), 6);
- EXPECT_EQ(dimensionsValue.value_tuple().dimensions_value(0).value_long(), long(1234));
-
- // Field not exist.
- EXPECT_FALSE(event.GetSimpleAtomDimensionsValueProto(7, &dimensionsValue));
-}
-
-TEST(LogEventTest, testWriteAtomProtoToStream) {
- AttributionNode attribution_node1;
- attribution_node1.set_uid(1111);
- attribution_node1.set_tag("locationService");
-
- AttributionNode attribution_node2;
- attribution_node2.set_uid(2222);
- attribution_node2.set_tag("locationService2");
-
- AttributionNode attribution_node3;
- attribution_node3.set_uid(3333);
- attribution_node3.set_tag("locationService3");
- std::vector<AttributionNode> attribution_nodes =
- {attribution_node1, attribution_node2, attribution_node3};
-
- LogEvent event(1, 0);
- EXPECT_TRUE(event.write("222"));
- EXPECT_TRUE(event.write(attribution_nodes));
- EXPECT_TRUE(event.write(345));
- EXPECT_TRUE(event.write(attribution_node3));
- EXPECT_TRUE(event.write("hello"));
- event.init();
-
- util::ProtoOutputStream protoOutput;
- // For now only see whether it will crash.
- // TODO(yanglu): test parsing from stream.
- event.ToProto(protoOutput);
-}
} // namespace statsd
} // namespace os
diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp
index aab5bed..cb72697 100644
--- a/cmds/statsd/tests/StatsLogProcessor_test.cpp
+++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp
@@ -45,7 +45,7 @@
}
MOCK_METHOD0(byteSize, size_t());
- MOCK_METHOD1(onDumpReport, void(ProtoOutputStream* output));
+ MOCK_METHOD2(onDumpReport, void(const uint64_t timeNs, ProtoOutputStream* output));
};
TEST(StatsLogProcessorTest, TestRateLimitByteSize) {
@@ -69,24 +69,26 @@
sp<UidMap> m = new UidMap();
sp<AnomalyMonitor> anomalyMonitor;
int broadcastCount = 0;
- StatsLogProcessor p(m, anomalyMonitor, 0,
- [&broadcastCount](const ConfigKey& key) { broadcastCount++; });
+ StatsLogProcessor p(m, anomalyMonitor, 0, [&broadcastCount](const ConfigKey& key) {
+ broadcastCount++;
+ });
MockMetricsManager mockMetricsManager;
ConfigKey key(100, 12345);
EXPECT_CALL(mockMetricsManager, byteSize())
- .Times(2)
+ .Times(1)
.WillRepeatedly(Return(int(StatsdStats::kMaxMetricsBytesPerConfig * .95)));
// Expect only one broadcast despite always returning a size that should trigger broadcast.
p.flushIfNecessaryLocked(1, key, mockMetricsManager);
EXPECT_EQ(1, broadcastCount);
+ // b/73089712
// This next call to flush should not trigger a broadcast.
- p.mLastByteSizeTimes.clear(); // Force another check for byte size.
- p.flushIfNecessaryLocked(2, key, mockMetricsManager);
- EXPECT_EQ(1, broadcastCount);
+ // p.mLastByteSizeTimes.clear(); // Force another check for byte size.
+ // p.flushIfNecessaryLocked(2, key, mockMetricsManager);
+ // EXPECT_EQ(1, broadcastCount);
}
TEST(StatsLogProcessorTest, TestDropWhenByteSizeTooLarge) {
@@ -103,7 +105,7 @@
.Times(1)
.WillRepeatedly(Return(int(StatsdStats::kMaxMetricsBytesPerConfig * 1.2)));
- EXPECT_CALL(mockMetricsManager, onDumpReport(_)).Times(1);
+ EXPECT_CALL(mockMetricsManager, onDumpReport(_, _)).Times(1);
// Expect to call the onDumpReport and skip the broadcast.
p.flushIfNecessaryLocked(1, key, mockMetricsManager);
diff --git a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
index a415ea1..b4a7bb7 100644
--- a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
+++ b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
@@ -34,10 +34,10 @@
const ConfigKey kConfigKey(0, 12345);
MetricDimensionKey getMockMetricDimensionKey(int key, string value) {
- DimensionsValue dimensionsValue;
- dimensionsValue.set_field(key);
- dimensionsValue.set_value_str(value);
- return MetricDimensionKey(HashableDimensionKey(dimensionsValue), DEFAULT_DIMENSION_KEY);
+ int pos[] = {key, 0, 0};
+ HashableDimensionKey dim;
+ dim.addValue(FieldValue(Field(1, pos, 0), Value(value)));
+ return MetricDimensionKey(dim, DEFAULT_DIMENSION_KEY);
}
void AddValueToBucket(const std::vector<std::pair<MetricDimensionKey, long>>& key_value_pair_list,
diff --git a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
index d1b7b28..038d449 100644
--- a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
+++ b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
@@ -80,31 +80,31 @@
const std::vector<int> &uids, const string& conditionName) {
std::map<int64_t, std::vector<HashableDimensionKey>> outputKeyMap;
std::vector<int> uid_indexes;
+ int pos[] = {1, 1, 1};
+ int depth = 2;
+ Field field(1, pos, depth);
switch(position) {
case Position::FIRST:
uid_indexes.push_back(0);
break;
case Position::LAST:
uid_indexes.push_back(uids.size() - 1);
+ field.setField(0x02018001);
break;
case Position::ANY:
uid_indexes.resize(uids.size());
std::iota(uid_indexes.begin(), uid_indexes.end(), 0);
+ field.setField(0x02010001);
break;
default:
break;
}
for (const int idx : uid_indexes) {
- DimensionsValue dimensionsValue;
- dimensionsValue.set_field(TAG_ID);
- dimensionsValue.mutable_value_tuple()->add_dimensions_value()->set_field(
- ATTRIBUTION_NODE_FIELD_ID);
- dimensionsValue.mutable_value_tuple()->mutable_dimensions_value(0)
- ->mutable_value_tuple()->add_dimensions_value()->set_field(ATTRIBUTION_NODE_FIELD_ID);
- dimensionsValue.mutable_value_tuple()->mutable_dimensions_value(0)
- ->mutable_value_tuple()->mutable_dimensions_value(0)->set_value_int(uids[idx]);
- outputKeyMap[StringToId(conditionName)].push_back(HashableDimensionKey(dimensionsValue));
+ Value value((int32_t)uids[idx]);
+ HashableDimensionKey dim;
+ dim.addValue(FieldValue(field, value));
+ outputKeyMap[StringToId(conditionName)].push_back(dim);
}
return outputKeyMap;
}
@@ -265,7 +265,7 @@
TEST(SimpleConditionTrackerTest, TestSlicedCondition) {
for (Position position :
{ Position::ANY, Position::FIRST, Position::LAST}) {
- FieldMatcher dimensionInCondition;
+ vector<Matcher> dimensionInCondition;
std::unordered_set<HashableDimensionKey> dimensionKeys;
SimplePredicate simplePredicate = getWakeLockHeldCondition(
@@ -374,7 +374,7 @@
}
TEST(SimpleConditionTrackerTest, TestSlicedWithNoOutputDim) {
- FieldMatcher dimensionInCondition;
+ vector<Matcher> dimensionInCondition;
std::unordered_set<HashableDimensionKey> dimensionKeys;
SimplePredicate simplePredicate = getWakeLockHeldCondition(
@@ -470,7 +470,7 @@
TEST(SimpleConditionTrackerTest, TestStopAll) {
for (Position position :
{Position::ANY, Position::FIRST, Position::LAST}) {
- FieldMatcher dimensionInCondition;
+ vector<Matcher> dimensionInCondition;
std::unordered_set<HashableDimensionKey> dimensionKeys;
SimplePredicate simplePredicate = getWakeLockHeldCondition(
true /*nesting*/, true /*default to false*/, true /*output slice by uid*/,
@@ -576,7 +576,6 @@
conditionCache, dimensionKeys);
EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
}
-
}
} // namespace statsd
diff --git a/cmds/statsd/tests/dimension_test.cpp b/cmds/statsd/tests/dimension_test.cpp
deleted file mode 100644
index 678abae..0000000
--- a/cmds/statsd/tests/dimension_test.cpp
+++ /dev/null
@@ -1,149 +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.
-
-#include "dimension.h"
-
-#include <gtest/gtest.h>
-
-using namespace android::os::statsd;
-
-#ifdef __ANDROID__
-
-TEST(DimensionTest, subLeafNodes) {
- DimensionsValue dimension;
- int tagId = 100;
- dimension.set_field(tagId);
- auto child = dimension.mutable_value_tuple()->add_dimensions_value();
- child->set_field(1);
- child->set_value_int(2000);
-
- child = dimension.mutable_value_tuple()->add_dimensions_value();
- child->set_field(3);
- child->set_value_str("test");
-
- child = dimension.mutable_value_tuple()->add_dimensions_value();
- child->set_field(4);
- auto grandChild = child->mutable_value_tuple()->add_dimensions_value();
- grandChild->set_field(1);
- grandChild->set_value_float(1.3f);
- grandChild = child->mutable_value_tuple()->add_dimensions_value();
- grandChild->set_field(3);
- grandChild->set_value_str("tag");
-
- child = dimension.mutable_value_tuple()->add_dimensions_value();
- child->set_field(6);
- child->set_value_bool(false);
-
- DimensionsValue sub_dimension;
- FieldMatcher matcher;
-
- // Tag id not matched.
- matcher.set_field(tagId + 1);
- EXPECT_FALSE(getSubDimension(dimension, matcher, &sub_dimension));
-
- // Field not exist.
- matcher.Clear();
- matcher.set_field(tagId);
- matcher.add_child()->set_field(5);
- EXPECT_FALSE(getSubDimension(dimension, matcher, &sub_dimension));
-
- // Field exists.
- matcher.Clear();
- matcher.set_field(tagId);
- matcher.add_child()->set_field(3);
- EXPECT_TRUE(getSubDimension(dimension, matcher, &sub_dimension));
-
- // Field exists.
- matcher.Clear();
- sub_dimension.Clear();
- matcher.set_field(tagId);
- matcher.add_child()->set_field(6);
- EXPECT_TRUE(getSubDimension(dimension, matcher, &sub_dimension));
-
- // Field exists.
- matcher.Clear();
- sub_dimension.Clear();
- matcher.set_field(tagId);
- matcher.add_child()->set_field(1);
- EXPECT_TRUE(getSubDimension(dimension, matcher, &sub_dimension));
-
- // Not leaf field.
- matcher.Clear();
- sub_dimension.Clear();
- matcher.set_field(tagId);
- matcher.add_child()->set_field(4);
- EXPECT_FALSE(getSubDimension(dimension, matcher, &sub_dimension));
-
- // Grand-child leaf field not exist.
- matcher.Clear();
- sub_dimension.Clear();
- matcher.set_field(tagId);
- auto childMatcher = matcher.add_child();
- childMatcher->set_field(4);
- childMatcher->add_child()->set_field(2);
- EXPECT_FALSE(getSubDimension(dimension, matcher, &sub_dimension));
-
- // Grand-child leaf field.
- matcher.Clear();
- sub_dimension.Clear();
- matcher.set_field(tagId);
- childMatcher = matcher.add_child();
- childMatcher->set_field(4);
- childMatcher->add_child()->set_field(1);
- EXPECT_TRUE(getSubDimension(dimension, matcher, &sub_dimension));
-
- matcher.Clear();
- sub_dimension.Clear();
- matcher.set_field(tagId);
- childMatcher = matcher.add_child();
- childMatcher->set_field(4);
- childMatcher->add_child()->set_field(3);
- EXPECT_TRUE(getSubDimension(dimension, matcher, &sub_dimension));
-
- // Multiple grand-child fields.
- matcher.Clear();
- sub_dimension.Clear();
- matcher.set_field(tagId);
- childMatcher = matcher.add_child();
- childMatcher->set_field(4);
- childMatcher->add_child()->set_field(3);
- childMatcher->add_child()->set_field(1);
- EXPECT_TRUE(getSubDimension(dimension, matcher, &sub_dimension));
-
- // Multiple fields.
- matcher.Clear();
- sub_dimension.Clear();
- matcher.set_field(tagId);
- childMatcher = matcher.add_child();
- childMatcher->set_field(4);
- childMatcher->add_child()->set_field(3);
- childMatcher->add_child()->set_field(1);
- matcher.add_child()->set_field(3);
- EXPECT_TRUE(getSubDimension(dimension, matcher, &sub_dimension));
-
- // Subset of the fields not exist.
- matcher.Clear();
- sub_dimension.Clear();
- matcher.set_field(tagId);
- childMatcher = matcher.add_child();
- childMatcher->set_field(4);
- childMatcher->add_child()->set_field(3);
- childMatcher->add_child()->set_field(1);
- matcher.add_child()->set_field(2);
- EXPECT_FALSE(getSubDimension(dimension, matcher, &sub_dimension));
-}
-
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
diff --git a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
index a56db28..0228004 100644
--- a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
@@ -47,7 +47,7 @@
*countMetric->mutable_dimensions_in_what() =
CreateAttributionUidAndTagDimensions(
android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
- countMetric->set_bucket(ONE_MINUTE);
+ countMetric->set_bucket(FIVE_MINUTES);
return config;
}
@@ -146,9 +146,13 @@
processor->OnLogEvent(event.get());
}
ConfigMetricsReportList reports;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, &reports);
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
EXPECT_EQ(reports.reports_size(), 1);
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+
StatsLogReport::CountMetricDataWrapper countMetrics;
sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
EXPECT_EQ(countMetrics.data_size(), 4);
@@ -159,11 +163,11 @@
"App1");
EXPECT_EQ(data.bucket_info_size(), 2);
EXPECT_EQ(data.bucket_info(0).count(), 2);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
EXPECT_EQ(data.bucket_info(1).count(), 1);
- EXPECT_EQ(data.bucket_info(1).start_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
data = countMetrics.data(1);
ValidateAttributionUidAndTagDimension(
@@ -171,11 +175,11 @@
"GMSCoreModule1");
EXPECT_EQ(data.bucket_info_size(), 2);
EXPECT_EQ(data.bucket_info(0).count(), 1);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
EXPECT_EQ(data.bucket_info(1).count(), 1);
- EXPECT_EQ(data.bucket_info(1).start_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
data = countMetrics.data(2);
ValidateAttributionUidAndTagDimension(
@@ -183,8 +187,8 @@
"GMSCoreModule3");
EXPECT_EQ(data.bucket_info_size(), 1);
EXPECT_EQ(data.bucket_info(0).count(), 1);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + 4 * bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + 4 * bucketSizeNs);
data = countMetrics.data(3);
ValidateAttributionUidAndTagDimension(
@@ -192,8 +196,8 @@
"GMSCoreModule2");
EXPECT_EQ(data.bucket_info_size(), 1);
EXPECT_EQ(data.bucket_info(0).count(), 1);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
}
#else
@@ -202,4 +206,4 @@
} // namespace statsd
} // namespace os
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_test.cpp b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_test.cpp
index b5d48ef..4dffd13 100644
--- a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_test.cpp
@@ -43,8 +43,8 @@
auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
// The predicate is dimensioning by any attribution node and both by uid and tag.
*holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions() =
- CreateAttributionUidAndTagDimensions(
- android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
+ CreateAttributionUidAndTagDimensions(android::util::WAKELOCK_STATE_CHANGED,
+ {Position::FIRST});
*config.add_predicate() = holdingWakelockPredicate;
auto combinationPredicate = config.add_predicate();
@@ -57,11 +57,11 @@
metric->set_id(StringToId("ScreenBrightnessChangeMetric"));
metric->set_what(screenBrightnessChangeAtomMatcher.id());
metric->set_condition(combinationPredicate->id());
- *metric->mutable_dimensions_in_what() = CreateDimensions(
- android::util::SCREEN_BRIGHTNESS_CHANGED, {1 /* level */});
+ *metric->mutable_dimensions_in_what() =
+ CreateDimensions(android::util::SCREEN_BRIGHTNESS_CHANGED, {1 /* level */});
*metric->mutable_dimensions_in_condition() = CreateAttributionUidDimensions(
android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
- metric->set_bucket(ONE_MINUTE);
+ metric->set_bucket(FIVE_MINUTES);
return config;
}
@@ -72,62 +72,54 @@
auto config = CreateCountMetricWithNoLinkConfig();
int64_t bucketStartTimeNs = 10000000000;
int64_t bucketSizeNs =
- TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
+ TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
- std::vector<AttributionNode> attributions1 =
- {CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
- CreateAttribution(222, "GMSCoreModule2")};
+ std::vector<AttributionNode> attributions1 = {CreateAttribution(111, "App1"),
+ CreateAttribution(222, "GMSCoreModule1"),
+ CreateAttribution(222, "GMSCoreModule2")};
- std::vector<AttributionNode> attributions2 =
- {CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
- CreateAttribution(555, "GMSCoreModule2")};
+ std::vector<AttributionNode> attributions2 = {CreateAttribution(333, "App2"),
+ CreateAttribution(222, "GMSCoreModule1"),
+ CreateAttribution(555, "GMSCoreModule2")};
std::vector<std::unique_ptr<LogEvent>> events;
- events.push_back(CreateScreenStateChangedEvent(
- android::view::DISPLAY_STATE_ON, bucketStartTimeNs + 10));
- events.push_back(CreateScreenStateChangedEvent(
- android::view::DISPLAY_STATE_OFF, bucketStartTimeNs + 100));
- events.push_back(CreateScreenStateChangedEvent(
- android::view::DISPLAY_STATE_ON, bucketStartTimeNs + bucketSizeNs + 1));
- events.push_back(CreateScreenStateChangedEvent(
- android::view::DISPLAY_STATE_OFF, bucketStartTimeNs + 2 * bucketSizeNs - 10));
+ events.push_back(
+ CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, bucketStartTimeNs + 10));
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+ bucketStartTimeNs + 100));
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+ bucketStartTimeNs + bucketSizeNs + 1));
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+ bucketStartTimeNs + 2 * bucketSizeNs - 10));
- events.push_back(CreateAcquireWakelockEvent(
- attributions1, "wl1", bucketStartTimeNs + 200));
- events.push_back(CreateReleaseWakelockEvent(
- attributions1, "wl1", bucketStartTimeNs + bucketSizeNs + 1));
+ events.push_back(CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 200));
+ events.push_back(
+ CreateReleaseWakelockEvent(attributions1, "wl1", bucketStartTimeNs + bucketSizeNs + 1));
- events.push_back(CreateAcquireWakelockEvent(
- attributions2, "wl2", bucketStartTimeNs + bucketSizeNs - 100));
- events.push_back(CreateReleaseWakelockEvent(
- attributions2, "wl2", bucketStartTimeNs + 2 * bucketSizeNs - 50));
+ events.push_back(CreateAcquireWakelockEvent(attributions2, "wl2",
+ bucketStartTimeNs + bucketSizeNs - 100));
+ events.push_back(CreateReleaseWakelockEvent(attributions2, "wl2",
+ bucketStartTimeNs + 2 * bucketSizeNs - 50));
- events.push_back(CreateScreenBrightnessChangedEvent(
- 123, bucketStartTimeNs + 11));
- events.push_back(CreateScreenBrightnessChangedEvent(
- 123, bucketStartTimeNs + 101));
- events.push_back(CreateScreenBrightnessChangedEvent(
- 123, bucketStartTimeNs + 201));
- events.push_back(CreateScreenBrightnessChangedEvent(
- 456, bucketStartTimeNs + 203));
- events.push_back(CreateScreenBrightnessChangedEvent(
- 456, bucketStartTimeNs + bucketSizeNs - 99));
- events.push_back(CreateScreenBrightnessChangedEvent(
- 456, bucketStartTimeNs + bucketSizeNs - 2));
- events.push_back(CreateScreenBrightnessChangedEvent(
- 789, bucketStartTimeNs + bucketSizeNs - 1));
- events.push_back(CreateScreenBrightnessChangedEvent(
- 456, bucketStartTimeNs + bucketSizeNs + 2));
- events.push_back(CreateScreenBrightnessChangedEvent(
- 789, bucketStartTimeNs + 2 * bucketSizeNs - 11));
- events.push_back(CreateScreenBrightnessChangedEvent(
- 789, bucketStartTimeNs + 2 * bucketSizeNs - 9));
- events.push_back(CreateScreenBrightnessChangedEvent(
- 789, bucketStartTimeNs + 2 * bucketSizeNs - 1));
+ events.push_back(CreateScreenBrightnessChangedEvent(123, bucketStartTimeNs + 11));
+ events.push_back(CreateScreenBrightnessChangedEvent(123, bucketStartTimeNs + 101));
+ events.push_back(CreateScreenBrightnessChangedEvent(123, bucketStartTimeNs + 201));
+ events.push_back(CreateScreenBrightnessChangedEvent(456, bucketStartTimeNs + 203));
+ events.push_back(
+ CreateScreenBrightnessChangedEvent(456, bucketStartTimeNs + bucketSizeNs - 99));
+ events.push_back(CreateScreenBrightnessChangedEvent(456, bucketStartTimeNs + bucketSizeNs - 2));
+ events.push_back(CreateScreenBrightnessChangedEvent(789, bucketStartTimeNs + bucketSizeNs - 1));
+ events.push_back(CreateScreenBrightnessChangedEvent(456, bucketStartTimeNs + bucketSizeNs + 2));
+ events.push_back(
+ CreateScreenBrightnessChangedEvent(789, bucketStartTimeNs + 2 * bucketSizeNs - 11));
+ events.push_back(
+ CreateScreenBrightnessChangedEvent(789, bucketStartTimeNs + 2 * bucketSizeNs - 9));
+ events.push_back(
+ CreateScreenBrightnessChangedEvent(789, bucketStartTimeNs + 2 * bucketSizeNs - 1));
sortLogEventsByTimestamp(&events);
@@ -136,7 +128,10 @@
}
ConfigMetricsReportList reports;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, &reports);
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
EXPECT_EQ(reports.reports_size(), 1);
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
@@ -147,8 +142,8 @@
auto data = countMetrics.data(0);
EXPECT_EQ(data.bucket_info_size(), 1);
EXPECT_EQ(data.bucket_info(0).count(), 1);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs );
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
EXPECT_EQ(data.dimensions_in_what().field(), android::util::SCREEN_BRIGHTNESS_CHANGED);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
@@ -158,44 +153,47 @@
data = countMetrics.data(1);
EXPECT_EQ(data.bucket_info_size(), 1);
EXPECT_EQ(data.bucket_info(0).count(), 1);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
EXPECT_EQ(data.dimensions_in_what().field(), android::util::SCREEN_BRIGHTNESS_CHANGED);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 123);
- ValidateAttributionUidDimension(data.dimensions_in_condition(), android::util::WAKELOCK_STATE_CHANGED, 111);
+ ValidateAttributionUidDimension(data.dimensions_in_condition(),
+ android::util::WAKELOCK_STATE_CHANGED, 111);
data = countMetrics.data(2);
EXPECT_EQ(data.bucket_info_size(), 1);
EXPECT_EQ(data.bucket_info(0).count(), 3);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
EXPECT_EQ(data.dimensions_in_what().field(), android::util::SCREEN_BRIGHTNESS_CHANGED);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 456);
- ValidateAttributionUidDimension(data.dimensions_in_condition(), android::util::WAKELOCK_STATE_CHANGED, 111);
+ ValidateAttributionUidDimension(data.dimensions_in_condition(),
+ android::util::WAKELOCK_STATE_CHANGED, 111);
data = countMetrics.data(3);
EXPECT_EQ(data.bucket_info_size(), 2);
EXPECT_EQ(data.bucket_info(0).count(), 2);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
EXPECT_EQ(data.bucket_info(1).count(), 1);
- EXPECT_EQ(data.bucket_info(1).start_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
EXPECT_EQ(data.dimensions_in_what().field(), android::util::SCREEN_BRIGHTNESS_CHANGED);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 456);
- ValidateAttributionUidDimension(data.dimensions_in_condition(), android::util::WAKELOCK_STATE_CHANGED, 333);
+ ValidateAttributionUidDimension(data.dimensions_in_condition(),
+ android::util::WAKELOCK_STATE_CHANGED, 333);
data = countMetrics.data(4);
EXPECT_EQ(data.bucket_info_size(), 1);
EXPECT_EQ(data.bucket_info(0).count(), 2);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
EXPECT_EQ(data.dimensions_in_what().field(), android::util::SCREEN_BRIGHTNESS_CHANGED);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
@@ -205,24 +203,26 @@
data = countMetrics.data(5);
EXPECT_EQ(data.bucket_info_size(), 1);
EXPECT_EQ(data.bucket_info(0).count(), 1);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
EXPECT_EQ(data.dimensions_in_what().field(), android::util::SCREEN_BRIGHTNESS_CHANGED);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 789);
- ValidateAttributionUidDimension(data.dimensions_in_condition(), android::util::WAKELOCK_STATE_CHANGED, 111);
+ ValidateAttributionUidDimension(data.dimensions_in_condition(),
+ android::util::WAKELOCK_STATE_CHANGED, 111);
data = countMetrics.data(6);
EXPECT_EQ(data.bucket_info_size(), 1);
EXPECT_EQ(data.bucket_info(0).count(), 1);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
EXPECT_EQ(data.dimensions_in_what().field(), android::util::SCREEN_BRIGHTNESS_CHANGED);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 789);
- ValidateAttributionUidDimension(data.dimensions_in_condition(), android::util::WAKELOCK_STATE_CHANGED, 333);
+ ValidateAttributionUidDimension(data.dimensions_in_condition(),
+ android::util::WAKELOCK_STATE_CHANGED, 333);
}
namespace {
@@ -239,8 +239,8 @@
auto screenIsOffPredicate = CreateScreenIsOffPredicate();
auto isSyncingPredicate = CreateIsSyncingPredicate();
auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
- *syncDimension = CreateAttributionUidAndTagDimensions(
- android::util::SYNC_STATE_CHANGED, {Position::FIRST});
+ *syncDimension = CreateAttributionUidAndTagDimensions(android::util::SYNC_STATE_CHANGED,
+ {Position::FIRST});
syncDimension->add_child()->set_field(2 /* name field*/);
*config.add_predicate() = screenIsOffPredicate;
@@ -252,12 +252,12 @@
addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate);
auto metric = config.add_count_metric();
- metric->set_bucket(ONE_MINUTE);
+ metric->set_bucket(FIVE_MINUTES);
metric->set_id(StringToId("AppCrashMetric"));
metric->set_what(appCrashMatcher.id());
metric->set_condition(combinationPredicate->id());
- *metric->mutable_dimensions_in_what() = CreateDimensions(
- android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, {1 /* uid */});
+ *metric->mutable_dimensions_in_what() =
+ CreateDimensions(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, {1 /* uid */});
*metric->mutable_dimensions_in_condition() = CreateAttributionUidAndTagDimensions(
android::util::SYNC_STATE_CHANGED, {Position::FIRST});
@@ -267,8 +267,8 @@
auto dimensionWhat = links->mutable_fields_in_what();
dimensionWhat->set_field(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
dimensionWhat->add_child()->set_field(1); // uid field.
- *links->mutable_fields_in_condition() = CreateAttributionUidDimensions(
- android::util::SYNC_STATE_CHANGED, {Position::FIRST});
+ *links->mutable_fields_in_condition() =
+ CreateAttributionUidDimensions(android::util::SYNC_STATE_CHANGED, {Position::FIRST});
return config;
}
@@ -279,18 +279,18 @@
auto config = CreateCountMetricWithLinkConfig();
int64_t bucketStartTimeNs = 10000000000;
int64_t bucketSizeNs =
- TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
+ TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
- std::vector<AttributionNode> attributions1 =
- {CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
- CreateAttribution(222, "GMSCoreModule2")};
+ std::vector<AttributionNode> attributions1 = {CreateAttribution(111, "App1"),
+ CreateAttribution(222, "GMSCoreModule1"),
+ CreateAttribution(222, "GMSCoreModule2")};
- std::vector<AttributionNode> attributions2 =
- {CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
- CreateAttribution(555, "GMSCoreModule2")};
+ std::vector<AttributionNode> attributions2 = {CreateAttribution(333, "App2"),
+ CreateAttribution(222, "GMSCoreModule1"),
+ CreateAttribution(555, "GMSCoreModule2")};
std::vector<std::unique_ptr<LogEvent>> events;
@@ -311,26 +311,26 @@
events.push_back(CreateAppCrashEvent(777, bucketStartTimeNs + bucketSizeNs + 701));
- events.push_back(CreateScreenStateChangedEvent(
- android::view::DISPLAY_STATE_ON, bucketStartTimeNs + 10));
- events.push_back(CreateScreenStateChangedEvent(
- android::view::DISPLAY_STATE_OFF, bucketStartTimeNs + 100));
- events.push_back(CreateScreenStateChangedEvent(
- android::view::DISPLAY_STATE_ON, bucketStartTimeNs + 202));
- events.push_back(CreateScreenStateChangedEvent(
- android::view::DISPLAY_STATE_OFF, bucketStartTimeNs + bucketSizeNs + 700));
+ events.push_back(
+ CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, bucketStartTimeNs + 10));
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+ bucketStartTimeNs + 100));
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+ bucketStartTimeNs + 202));
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+ bucketStartTimeNs + bucketSizeNs + 700));
events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail", bucketStartTimeNs + 200));
- events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
- bucketStartTimeNs + bucketSizeNs + 300));
+ events.push_back(
+ CreateSyncEndEvent(attributions1, "ReadEmail", bucketStartTimeNs + bucketSizeNs + 300));
events.push_back(CreateSyncStartEvent(attributions1, "ReadDoc", bucketStartTimeNs + 400));
- events.push_back(CreateSyncEndEvent(attributions1, "ReadDoc",
- bucketStartTimeNs + bucketSizeNs - 1));
+ events.push_back(
+ CreateSyncEndEvent(attributions1, "ReadDoc", bucketStartTimeNs + bucketSizeNs - 1));
events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail", bucketStartTimeNs + 400));
- events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
- bucketStartTimeNs + bucketSizeNs + 600));
+ events.push_back(
+ CreateSyncEndEvent(attributions2, "ReadEmail", bucketStartTimeNs + bucketSizeNs + 600));
sortLogEventsByTimestamp(&events);
@@ -339,7 +339,10 @@
}
ConfigMetricsReportList reports;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, &reports);
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
EXPECT_EQ(reports.reports_size(), 1);
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
@@ -355,20 +358,20 @@
EXPECT_FALSE(data.dimensions_in_condition().has_field());
EXPECT_EQ(data.bucket_info_size(), 1);
EXPECT_EQ(data.bucket_info(0).count(), 1);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
data = countMetrics.data(1);
EXPECT_EQ(data.dimensions_in_what().field(), android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 111);
- ValidateAttributionUidAndTagDimension(
- data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 111, "App1");
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
+ android::util::SYNC_STATE_CHANGED, 111, "App1");
EXPECT_EQ(data.bucket_info_size(), 1);
EXPECT_EQ(data.bucket_info(0).count(), 2);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
data = countMetrics.data(2);
EXPECT_EQ(data.dimensions_in_what().field(), android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
@@ -378,23 +381,23 @@
EXPECT_FALSE(data.dimensions_in_condition().has_field());
EXPECT_EQ(data.bucket_info_size(), 1);
EXPECT_EQ(data.bucket_info(0).count(), 2);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
data = countMetrics.data(3);
EXPECT_EQ(data.dimensions_in_what().field(), android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 333);
- ValidateAttributionUidAndTagDimension(
- data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333, "App2");
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
+ android::util::SYNC_STATE_CHANGED, 333, "App2");
EXPECT_EQ(data.bucket_info_size(), 2);
EXPECT_EQ(data.bucket_info(0).count(), 1);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
EXPECT_EQ(data.bucket_info(1).count(), 1);
- EXPECT_EQ(data.bucket_info(1).start_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
data = countMetrics.data(4);
EXPECT_EQ(data.dimensions_in_what().field(), android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
@@ -404,8 +407,8 @@
EXPECT_FALSE(data.dimensions_in_condition().has_field());
EXPECT_EQ(data.bucket_info_size(), 1);
EXPECT_EQ(data.bucket_info(0).count(), 1);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
}
namespace {
@@ -424,8 +427,8 @@
auto screenIsOffPredicate = CreateScreenIsOffPredicate();
auto isSyncingPredicate = CreateIsSyncingPredicate();
auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
- *syncDimension = CreateAttributionUidAndTagDimensions(
- android::util::SYNC_STATE_CHANGED, {Position::FIRST});
+ *syncDimension = CreateAttributionUidAndTagDimensions(android::util::SYNC_STATE_CHANGED,
+ {Position::FIRST});
syncDimension->add_child()->set_field(2 /* name field */);
*config.add_predicate() = inBatterySaverModePredicate;
@@ -438,7 +441,7 @@
addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate);
auto metric = config.add_duration_metric();
- metric->set_bucket(ONE_MINUTE);
+ metric->set_bucket(FIVE_MINUTES);
metric->set_id(StringToId("BatterySaverModeDurationMetric"));
metric->set_what(inBatterySaverModePredicate.id());
metric->set_condition(combinationPredicate->id());
@@ -449,26 +452,25 @@
} // namespace
-
TEST(DimensionInConditionE2eTest, TestDurationMetricNoLink) {
- for (auto aggregationType : { DurationMetric::SUM, DurationMetric::MAX_SPARSE}) {
+ for (auto aggregationType : {DurationMetric::SUM, DurationMetric::MAX_SPARSE}) {
ConfigKey cfgKey;
auto config = CreateDurationMetricConfigNoLink(aggregationType);
int64_t bucketStartTimeNs = 10000000000;
int64_t bucketSizeNs =
- TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
- std::vector<AttributionNode> attributions1 =
- {CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
- CreateAttribution(222, "GMSCoreModule2")};
+ std::vector<AttributionNode> attributions1 = {CreateAttribution(111, "App1"),
+ CreateAttribution(222, "GMSCoreModule1"),
+ CreateAttribution(222, "GMSCoreModule2")};
- std::vector<AttributionNode> attributions2 =
- {CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
- CreateAttribution(555, "GMSCoreModule2")};
+ std::vector<AttributionNode> attributions2 = {CreateAttribution(333, "App2"),
+ CreateAttribution(222, "GMSCoreModule1"),
+ CreateAttribution(555, "GMSCoreModule2")};
std::vector<std::unique_ptr<LogEvent>> events;
@@ -485,26 +487,26 @@
events.push_back(CreateBatterySaverOnEvent(bucketStartTimeNs + bucketSizeNs + 870));
events.push_back(CreateBatterySaverOffEvent(bucketStartTimeNs + bucketSizeNs + 900));
- events.push_back(CreateScreenStateChangedEvent(
- android::view::DISPLAY_STATE_ON, bucketStartTimeNs + 10));
- events.push_back(CreateScreenStateChangedEvent(
- android::view::DISPLAY_STATE_OFF, bucketStartTimeNs + 100));
- events.push_back(CreateScreenStateChangedEvent(
- android::view::DISPLAY_STATE_ON, bucketStartTimeNs + 202));
- events.push_back(CreateScreenStateChangedEvent(
- android::view::DISPLAY_STATE_OFF, bucketStartTimeNs + bucketSizeNs + 800));
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+ bucketStartTimeNs + 10));
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+ bucketStartTimeNs + 100));
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+ bucketStartTimeNs + 202));
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+ bucketStartTimeNs + bucketSizeNs + 800));
events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail", bucketStartTimeNs + 200));
events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
- bucketStartTimeNs + bucketSizeNs + 300));
+ bucketStartTimeNs + bucketSizeNs + 300));
events.push_back(CreateSyncStartEvent(attributions1, "ReadDoc", bucketStartTimeNs + 400));
- events.push_back(CreateSyncEndEvent(attributions1, "ReadDoc",
- bucketStartTimeNs + bucketSizeNs - 1));
+ events.push_back(
+ CreateSyncEndEvent(attributions1, "ReadDoc", bucketStartTimeNs + bucketSizeNs - 1));
events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail", bucketStartTimeNs + 401));
events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
- bucketStartTimeNs + bucketSizeNs + 700));
+ bucketStartTimeNs + bucketSizeNs + 700));
sortLogEventsByTimestamp(&events);
@@ -513,7 +515,10 @@
}
ConfigMetricsReportList reports;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, &reports);
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
EXPECT_EQ(reports.reports_size(), 1);
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
@@ -526,35 +531,35 @@
EXPECT_FALSE(data.dimensions_in_condition().has_field());
EXPECT_EQ(data.bucket_info_size(), 2);
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 9);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
EXPECT_EQ(data.bucket_info(1).duration_nanos(), 30);
- EXPECT_EQ(data.bucket_info(1).start_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
data = metrics.data(1);
EXPECT_FALSE(data.dimensions_in_what().has_field());
- ValidateAttributionUidAndTagDimension(
- data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 111, "App1");
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
+ android::util::SYNC_STATE_CHANGED, 111, "App1");
EXPECT_EQ(data.bucket_info_size(), 2);
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 201 + bucketSizeNs - 600);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
EXPECT_EQ(data.bucket_info(1).duration_nanos(), 300);
- EXPECT_EQ(data.bucket_info(1).start_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
data = metrics.data(2);
EXPECT_FALSE(data.dimensions_in_what().has_field());
- ValidateAttributionUidAndTagDimension(
- data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333, "App2");
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
+ android::util::SYNC_STATE_CHANGED, 333, "App2");
EXPECT_EQ(data.bucket_info_size(), 2);
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 401 + bucketSizeNs - 600);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700);
- EXPECT_EQ(data.bucket_info(1).start_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
}
}
@@ -572,13 +577,13 @@
auto screenIsOffPredicate = CreateScreenIsOffPredicate();
auto isSyncingPredicate = CreateIsSyncingPredicate();
auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
- *syncDimension = CreateAttributionUidAndTagDimensions(
- android::util::SYNC_STATE_CHANGED, {Position::FIRST});
+ *syncDimension = CreateAttributionUidAndTagDimensions(android::util::SYNC_STATE_CHANGED,
+ {Position::FIRST});
syncDimension->add_child()->set_field(2 /* name field */);
auto isInBackgroundPredicate = CreateIsInBackgroundPredicate();
*isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() =
- CreateDimensions(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1 /* uid field */ });
+ CreateDimensions(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1 /* uid field */});
*config.add_predicate() = screenIsOffPredicate;
*config.add_predicate() = isSyncingPredicate;
@@ -590,12 +595,12 @@
addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate);
auto metric = config.add_duration_metric();
- metric->set_bucket(ONE_MINUTE);
+ metric->set_bucket(FIVE_MINUTES);
metric->set_id(StringToId("AppInBackgroundMetric"));
metric->set_what(isInBackgroundPredicate.id());
metric->set_condition(combinationPredicate->id());
- *metric->mutable_dimensions_in_what() = CreateDimensions(
- android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1 /* uid field */ });
+ *metric->mutable_dimensions_in_what() =
+ CreateDimensions(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1 /* uid field */});
*metric->mutable_dimensions_in_condition() = CreateAttributionUidAndTagDimensions(
android::util::SYNC_STATE_CHANGED, {Position::FIRST});
@@ -605,32 +610,32 @@
auto dimensionWhat = links->mutable_fields_in_what();
dimensionWhat->set_field(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED);
dimensionWhat->add_child()->set_field(1); // uid field.
- *links->mutable_fields_in_condition() = CreateAttributionUidDimensions(
- android::util::SYNC_STATE_CHANGED, {Position::FIRST});
+ *links->mutable_fields_in_condition() =
+ CreateAttributionUidDimensions(android::util::SYNC_STATE_CHANGED, {Position::FIRST});
return config;
}
} // namespace
TEST(DimensionInConditionE2eTest, TestDurationMetricWithLink) {
- for (auto aggregationType : { DurationMetric::SUM, DurationMetric::MAX_SPARSE}) {
+ for (auto aggregationType : {DurationMetric::SUM, DurationMetric::MAX_SPARSE}) {
ConfigKey cfgKey;
auto config = CreateDurationMetricConfigWithLink(aggregationType);
int64_t bucketStartTimeNs = 10000000000;
int64_t bucketSizeNs =
- TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
- std::vector<AttributionNode> attributions1 =
- {CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
- CreateAttribution(222, "GMSCoreModule2")};
+ std::vector<AttributionNode> attributions1 = {CreateAttribution(111, "App1"),
+ CreateAttribution(222, "GMSCoreModule1"),
+ CreateAttribution(222, "GMSCoreModule2")};
- std::vector<AttributionNode> attributions2 =
- {CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
- CreateAttribution(555, "GMSCoreModule2")};
+ std::vector<AttributionNode> attributions2 = {CreateAttribution(333, "App2"),
+ CreateAttribution(222, "GMSCoreModule1"),
+ CreateAttribution(555, "GMSCoreModule2")};
std::vector<std::unique_ptr<LogEvent>> events;
@@ -643,26 +648,26 @@
events.push_back(CreateMoveToBackgroundEvent(333, bucketStartTimeNs + 399));
events.push_back(CreateMoveToForegroundEvent(333, bucketStartTimeNs + bucketSizeNs + 800));
- events.push_back(CreateScreenStateChangedEvent(
- android::view::DISPLAY_STATE_ON, bucketStartTimeNs + 10));
- events.push_back(CreateScreenStateChangedEvent(
- android::view::DISPLAY_STATE_OFF, bucketStartTimeNs + 100));
- events.push_back(CreateScreenStateChangedEvent(
- android::view::DISPLAY_STATE_ON, bucketStartTimeNs + 202));
- events.push_back(CreateScreenStateChangedEvent(
- android::view::DISPLAY_STATE_OFF, bucketStartTimeNs + bucketSizeNs + 801));
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+ bucketStartTimeNs + 10));
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+ bucketStartTimeNs + 100));
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+ bucketStartTimeNs + 202));
+ events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
+ bucketStartTimeNs + bucketSizeNs + 801));
events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail", bucketStartTimeNs + 200));
events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
- bucketStartTimeNs + bucketSizeNs + 300));
+ bucketStartTimeNs + bucketSizeNs + 300));
events.push_back(CreateSyncStartEvent(attributions1, "ReadDoc", bucketStartTimeNs + 400));
- events.push_back(CreateSyncEndEvent(attributions1, "ReadDoc",
- bucketStartTimeNs + bucketSizeNs - 1));
+ events.push_back(
+ CreateSyncEndEvent(attributions1, "ReadDoc", bucketStartTimeNs + bucketSizeNs - 1));
events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail", bucketStartTimeNs + 401));
events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
- bucketStartTimeNs + bucketSizeNs + 700));
+ bucketStartTimeNs + bucketSizeNs + 700));
sortLogEventsByTimestamp(&events);
@@ -671,7 +676,10 @@
}
ConfigMetricsReportList reports;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, &reports);
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
EXPECT_EQ(reports.reports_size(), 1);
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
@@ -685,34 +693,34 @@
EXPECT_FALSE(data.dimensions_in_condition().has_field());
EXPECT_EQ(data.bucket_info_size(), 1);
EXPECT_EQ(data.bucket_info(0).duration_nanos(), 9);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
data = metrics.data(1);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 111);
- ValidateAttributionUidAndTagDimension(
- data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 111, "App1");
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
+ android::util::SYNC_STATE_CHANGED, 111, "App1");
EXPECT_EQ(data.bucket_info_size(), 2);
EXPECT_EQ(data.bucket_info(0).duration_nanos(), bucketSizeNs - 201);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
EXPECT_EQ(data.bucket_info(1).duration_nanos(), 100);
- EXPECT_EQ(data.bucket_info(1).start_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
data = metrics.data(2);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 333);
- ValidateAttributionUidAndTagDimension(
- data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333, "App2");
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
+ android::util::SYNC_STATE_CHANGED, 333, "App2");
EXPECT_EQ(data.bucket_info_size(), 2);
EXPECT_EQ(data.bucket_info(0).duration_nanos(), bucketSizeNs - 401);
- EXPECT_EQ(data.bucket_info(0).start_bucket_nanos(), bucketStartTimeNs);
- EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700);
- EXPECT_EQ(data.bucket_info(1).start_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
- EXPECT_EQ(data.bucket_info(1).end_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
}
}
@@ -722,4 +730,4 @@
} // namespace statsd
} // namespace os
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_test.cpp
index a80fdc5..3843e0a 100644
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_test.cpp
@@ -53,7 +53,7 @@
fieldMatcher->add_child()->set_field(7); // activity_start_msec(int64)
*gaugeMetric->mutable_dimensions_in_what() =
CreateDimensions(android::util::APP_START_CHANGED, {1 /* uid field */ });
- gaugeMetric->set_bucket(ONE_MINUTE);
+ gaugeMetric->set_bucket(FIVE_MINUTES);
auto links = gaugeMetric->add_links();
links->set_condition(isInBackgroundPredicate.id());
@@ -140,7 +140,10 @@
processor->OnLogEvent(event.get());
}
ConfigMetricsReportList reports;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 3 * bucketSizeNs, &reports);
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 3 * bucketSizeNs, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
EXPECT_EQ(reports.reports_size(), 1);
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
@@ -158,21 +161,21 @@
EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
EXPECT_EQ(data.bucket_info(0).atom(0).app_start_changed().type(), AppStartChanged::HOT);
EXPECT_EQ(data.bucket_info(0).atom(0).app_start_changed().activity_name(), "activity_name2");
- EXPECT_EQ(data.bucket_info(0).atom(0).app_start_changed().activity_start_msec(), 102L);
+ EXPECT_EQ(data.bucket_info(0).atom(0).app_start_changed().activity_start_millis(), 102L);
EXPECT_EQ(data.bucket_info(1).atom_size(), 1);
EXPECT_EQ(data.bucket_info(1).start_bucket_nanos(), bucketStartTimeNs + bucketSizeNs);
EXPECT_EQ(data.bucket_info(1).end_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
EXPECT_EQ(data.bucket_info(1).atom(0).app_start_changed().type(), AppStartChanged::WARM);
EXPECT_EQ(data.bucket_info(1).atom(0).app_start_changed().activity_name(), "activity_name4");
- EXPECT_EQ(data.bucket_info(1).atom(0).app_start_changed().activity_start_msec(), 104L);
+ EXPECT_EQ(data.bucket_info(1).atom(0).app_start_changed().activity_start_millis(), 104L);
EXPECT_EQ(data.bucket_info(2).atom_size(), 1);
EXPECT_EQ(data.bucket_info(2).start_bucket_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
EXPECT_EQ(data.bucket_info(2).end_bucket_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
EXPECT_EQ(data.bucket_info(2).atom(0).app_start_changed().type(), AppStartChanged::COLD);
EXPECT_EQ(data.bucket_info(2).atom(0).app_start_changed().activity_name(), "activity_name5");
- EXPECT_EQ(data.bucket_info(2).atom(0).app_start_changed().activity_start_msec(), 105L);
+ EXPECT_EQ(data.bucket_info(2).atom(0).app_start_changed().activity_start_millis(), 105L);
data = gaugeMetrics.data(1);
@@ -186,7 +189,7 @@
EXPECT_EQ(data.bucket_info(0).end_bucket_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
EXPECT_EQ(data.bucket_info(0).atom(0).app_start_changed().type(), AppStartChanged::COLD);
EXPECT_EQ(data.bucket_info(0).atom(0).app_start_changed().activity_name(), "activity_name7");
- EXPECT_EQ(data.bucket_info(0).atom(0).app_start_changed().activity_start_msec(), 201L);
+ EXPECT_EQ(data.bucket_info(0).atom(0).app_start_changed().activity_start_millis(), 201L);
}
#else
@@ -195,4 +198,4 @@
} // namespace statsd
} // namespace os
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
index 233031c..1b51780 100644
--- a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
@@ -71,7 +71,7 @@
// The metric is dimensioning by uid only.
*countMetric->mutable_dimensions_in_what() =
CreateDimensions(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, {1});
- countMetric->set_bucket(ONE_MINUTE);
+ countMetric->set_bucket(FIVE_MINUTES);
// Links between crash atom and condition of app is in syncing.
auto links = countMetric->add_links();
@@ -95,8 +95,10 @@
}
} // namespace
-
-TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks) {
+// If we want to test multiple dump data, we must do it in separate tests, because in the e2e tests,
+// we should use the real API which will clear the data after dump data is called.
+// TODO: better refactor the code so that the tests are not so verbose.
+TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks1) {
auto config = CreateStatsdConfig();
uint64_t bucketStartTimeNs = 10000000000;
uint64_t bucketSizeNs =
@@ -195,7 +197,10 @@
processor->OnLogEvent(event.get());
}
ConfigMetricsReportList reports;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, &reports);
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
EXPECT_EQ(reports.reports_size(), 1);
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data_size(), 1);
@@ -208,16 +213,115 @@
// Uid field.
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), appUid);
+}
- reports.Clear();
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, &reports);
+TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks2) {
+ auto config = CreateStatsdConfig();
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
+
+ ConfigKey cfgKey;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+
+ int appUid = 123;
+ auto crashEvent1 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 1);
+ auto crashEvent2 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 201);
+ auto crashEvent3 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 101);
+
+ auto crashEvent4 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 51);
+ auto crashEvent5 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 299);
+ auto crashEvent6 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 2001);
+
+ auto crashEvent7 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 16);
+ auto crashEvent8 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 249);
+
+ auto crashEvent9 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 351);
+ auto crashEvent10 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 2);
+
+ auto screenTurnedOnEvent = CreateScreenStateChangedEvent(
+ android::view::DisplayStateEnum::DISPLAY_STATE_ON, bucketStartTimeNs + 2);
+ auto screenTurnedOffEvent = CreateScreenStateChangedEvent(
+ android::view::DisplayStateEnum::DISPLAY_STATE_OFF, bucketStartTimeNs + 200);
+ auto screenTurnedOnEvent2 =
+ CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
+ bucketStartTimeNs + 2 * bucketSizeNs - 100);
+
+ std::vector<AttributionNode> attributions = {CreateAttribution(appUid, "App1"),
+ CreateAttribution(appUid + 1, "GMSCoreModule1")};
+ auto syncOnEvent1 = CreateSyncStartEvent(attributions, "ReadEmail", bucketStartTimeNs + 50);
+ auto syncOffEvent1 =
+ CreateSyncEndEvent(attributions, "ReadEmail", bucketStartTimeNs + bucketSizeNs + 300);
+ auto syncOnEvent2 =
+ CreateSyncStartEvent(attributions, "ReadDoc", bucketStartTimeNs + bucketSizeNs + 2000);
+
+ auto moveToBackgroundEvent1 = CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + 15);
+ auto moveToForegroundEvent1 =
+ CreateMoveToForegroundEvent(appUid, bucketStartTimeNs + bucketSizeNs + 250);
+
+ auto moveToBackgroundEvent2 =
+ CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + bucketSizeNs + 350);
+ auto moveToForegroundEvent2 =
+ CreateMoveToForegroundEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 1);
+
+ /*
+ bucket #1 bucket #2
+
+
+ | | | | | | | | | | (crashEvents)
+ |-------------------------------------|-----------------------------------|---------
+
+ | | (MoveToBkground)
+
+ | | (MoveToForeground)
+
+ | | (SyncIsOn)
+ | (SyncIsOff)
+ | | (ScreenIsOn)
+ | (ScreenIsOff)
+ */
+ std::vector<std::unique_ptr<LogEvent>> events;
+ events.push_back(std::move(crashEvent1));
+ events.push_back(std::move(crashEvent2));
+ events.push_back(std::move(crashEvent3));
+ events.push_back(std::move(crashEvent4));
+ events.push_back(std::move(crashEvent5));
+ events.push_back(std::move(crashEvent6));
+ events.push_back(std::move(crashEvent7));
+ events.push_back(std::move(crashEvent8));
+ events.push_back(std::move(crashEvent9));
+ events.push_back(std::move(crashEvent10));
+ events.push_back(std::move(screenTurnedOnEvent));
+ events.push_back(std::move(screenTurnedOffEvent));
+ events.push_back(std::move(screenTurnedOnEvent2));
+ events.push_back(std::move(syncOnEvent1));
+ events.push_back(std::move(syncOffEvent1));
+ events.push_back(std::move(syncOnEvent2));
+ events.push_back(std::move(moveToBackgroundEvent1));
+ events.push_back(std::move(moveToForegroundEvent1));
+ events.push_back(std::move(moveToBackgroundEvent2));
+ events.push_back(std::move(moveToForegroundEvent2));
+
+ sortLogEventsByTimestamp(&events);
+
+ for (const auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
EXPECT_EQ(reports.reports_size(), 1);
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data_size(), 1);
EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info_size(), 2);
EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(0).count(), 1);
EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(1).count(), 3);
- data = reports.reports(0).metrics(0).count_metrics().data(0);
+ auto data = reports.reports(0).metrics(0).count_metrics().data(0);
// Validate dimension value.
EXPECT_EQ(data.dimensions_in_what().field(),
android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
@@ -233,4 +337,4 @@
} // namespace statsd
} // namespace os
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
index a99dbe8..efdab98 100644
--- a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
@@ -56,7 +56,7 @@
*durationMetric->mutable_dimensions_in_what() =
CreateAttributionUidDimensions(
android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
- durationMetric->set_bucket(ONE_MINUTE);
+ durationMetric->set_bucket(FIVE_MINUTES);
return config;
}
@@ -114,7 +114,7 @@
} // namespace
-TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration) {
+TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration1) {
ConfigKey cfgKey;
auto config = CreateStatsdConfig(DurationMetric::SUM);
uint64_t bucketStartTimeNs = 10000000000;
@@ -124,8 +124,11 @@
EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
FeedEvents(config, processor);
+ vector<uint8_t> buffer;
ConfigMetricsReportList reports;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, &reports);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
EXPECT_EQ(reports.reports_size(), 1);
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
@@ -142,15 +145,30 @@
// The wakelock holding interval starts from the screen off event and to the end of the 1st
// bucket.
EXPECT_EQ((unsigned long long)data.bucket_info(0).duration_nanos(), bucketSizeNs - 200);
+}
- reports.Clear();
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, &reports);
+TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration2) {
+ ConfigKey cfgKey;
+ auto config = CreateStatsdConfig(DurationMetric::SUM);
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ FeedEvents(config, processor);
+ vector<uint8_t> buffer;
+ ConfigMetricsReportList reports;
+
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
EXPECT_EQ(reports.reports_size(), 1);
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
// Dump the report after the end of 2nd bucket.
EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 2);
- data = reports.reports(0).metrics(0).duration_metrics().data(0);
+ auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
// Validate dimension value.
ValidateAttributionUidDimension(data.dimensions_in_what(),
android::util::WAKELOCK_STATE_CHANGED, 111);
@@ -162,6 +180,19 @@
// The wakelock holding interval in the 2nd bucket starts at the beginning of the bucket and
// ends at the second screen on event.
EXPECT_EQ((unsigned long long)data.bucket_info(1).duration_nanos(), 500UL);
+}
+TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration3) {
+ ConfigKey cfgKey;
+ auto config = CreateStatsdConfig(DurationMetric::SUM);
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ FeedEvents(config, processor);
+ vector<uint8_t> buffer;
+ ConfigMetricsReportList reports;
std::vector<std::unique_ptr<LogEvent>> events;
events.push_back(
@@ -175,13 +206,15 @@
for (const auto& event : events) {
processor->OnLogEvent(event.get());
}
- reports.Clear();
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, &reports);
+
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
EXPECT_EQ(reports.reports_size(), 1);
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 6);
- data = reports.reports(0).metrics(0).duration_metrics().data(0);
+ auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
ValidateAttributionUidDimension(data.dimensions_in_what(),
android::util::WAKELOCK_STATE_CHANGED, 111);
// The last wakelock holding spans 4 buckets.
@@ -191,7 +224,7 @@
EXPECT_EQ((unsigned long long)data.bucket_info(5).duration_nanos(), 100UL);
}
-TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration) {
+TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration1) {
ConfigKey cfgKey;
auto config = CreateStatsdConfig(DurationMetric::MAX_SPARSE);
uint64_t bucketStartTimeNs = 10000000000;
@@ -202,15 +235,35 @@
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
FeedEvents(config, processor);
ConfigMetricsReportList reports;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, &reports);
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
EXPECT_EQ(reports.reports_size(), 1);
- EXPECT_EQ(reports.reports(0).metrics_size(), 1);
- // Nothing has ended in the first bucket.
- EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 0);
- reports.Clear();
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, &reports);
+ // When using ProtoOutputStream, if nothing written to a sub msg, it won't be treated as
+ // one. It was previsouly 1 because we had a fake onDumpReport which calls add_metric() by
+ // itself.
+ EXPECT_EQ(0, reports.reports(0).metrics_size());
+}
+
+TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration2) {
+ ConfigKey cfgKey;
+ auto config = CreateStatsdConfig(DurationMetric::MAX_SPARSE);
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ FeedEvents(config, processor);
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
EXPECT_EQ(reports.reports_size(), 1);
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
@@ -222,6 +275,20 @@
android::util::WAKELOCK_STATE_CHANGED, 111);
// The max is acquire event for wl1 to screen off start.
EXPECT_EQ((unsigned long long)data.bucket_info(0).duration_nanos(), bucketSizeNs + 2 - 200);
+}
+
+TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration3) {
+ ConfigKey cfgKey;
+ auto config = CreateStatsdConfig(DurationMetric::MAX_SPARSE);
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ FeedEvents(config, processor);
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
std::vector<std::unique_ptr<LogEvent>> events;
events.push_back(
@@ -235,20 +302,22 @@
for (const auto& event : events) {
processor->OnLogEvent(event.get());
}
- reports.Clear();
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, &reports);
+
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
EXPECT_EQ(reports.reports_size(), 1);
EXPECT_EQ(reports.reports(0).metrics_size(), 1);
EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 2);
- data = reports.reports(0).metrics(0).duration_metrics().data(0);
+ auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
ValidateAttributionUidDimension(data.dimensions_in_what(),
android::util::WAKELOCK_STATE_CHANGED, 111);
// The last wakelock holding spans 4 buckets.
EXPECT_EQ((unsigned long long)data.bucket_info(1).duration_nanos(), 3 * bucketSizeNs);
- EXPECT_EQ((unsigned long long)data.bucket_info(1).start_bucket_nanos(),
+ EXPECT_EQ((unsigned long long)data.bucket_info(1).start_bucket_elapsed_nanos(),
bucketStartTimeNs + 5 * bucketSizeNs);
- EXPECT_EQ((unsigned long long)data.bucket_info(1).end_bucket_nanos(),
+ EXPECT_EQ((unsigned long long)data.bucket_info(1).end_bucket_elapsed_nanos(),
bucketStartTimeNs + 6 * bucketSizeNs);
}
@@ -258,4 +327,4 @@
} // namespace statsd
} // namespace os
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
index a134300..bd11443 100644
--- a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
+++ b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
@@ -225,7 +225,7 @@
bool dropboxAtomGood = false;
for (const auto& atomStats : report.atom_stats()) {
- if (atomStats.tag() == android::util::SENSOR_STATE_CHANGED && atomStats.count() == 2) {
+ if (atomStats.tag() == android::util::SENSOR_STATE_CHANGED && atomStats.count() == 3) {
sensorAtomGood = true;
}
if (atomStats.tag() == android::util::DROPBOX_ERROR_CHANGED && atomStats.count() == 1) {
diff --git a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
index 87a1079..20ddbe9 100644
--- a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
@@ -13,7 +13,6 @@
// limitations under the License.
#include "src/metrics/CountMetricProducer.h"
-#include "src/dimension.h"
#include "src/stats_log_util.h"
#include "metrics_test_helper.h"
#include "tests/statsd_test_util.h"
@@ -49,12 +48,15 @@
metric.set_bucket(ONE_MINUTE);
LogEvent event1(tagId, bucketStartTimeNs + 1);
+ event1.init();
LogEvent event2(tagId, bucketStartTimeNs + 2);
+ event2.init();
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
bucketStartTimeNs);
+ countProducer.setBucketSize(60 * NS_PER_SEC);
// 2 events in bucket 1.
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
@@ -77,6 +79,8 @@
// 1 matched event happens in bucket 2.
LogEvent event3(tagId, bucketStartTimeNs + bucketSizeNs + 2);
+ event3.init();
+
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
countProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
@@ -107,11 +111,15 @@
metric.set_condition(StringToId("SCREEN_ON"));
LogEvent event1(1, bucketStartTimeNs + 1);
+ event1.init();
+
LogEvent event2(1, bucketStartTimeNs + 10);
+ event2.init();
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
CountMetricProducer countProducer(kConfigKey, metric, 1, wizard, bucketStartTimeNs);
+ countProducer.setBucketSize(60 * NS_PER_SEC);
countProducer.onConditionChanged(true, bucketStartTimeNs);
countProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
@@ -173,6 +181,7 @@
CountMetricProducer countProducer(kConfigKey, metric, 1 /*condition tracker index*/, wizard,
bucketStartTimeNs);
+ countProducer.setBucketSize(60 * NS_PER_SEC);
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
countProducer.flushIfNeededLocked(bucketStartTimeNs + 1);
@@ -211,6 +220,8 @@
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, wizard,
bucketStartTimeNs);
+ countProducer.setBucketSize(60 * NS_PER_SEC);
+
sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert);
EXPECT_TRUE(anomalyTracker != nullptr);
@@ -268,6 +279,7 @@
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, wizard,
bucketStartTimeNs);
+ countProducer.setBucketSize(60 * NS_PER_SEC);
// Bucket is flushed yet.
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
@@ -323,16 +335,25 @@
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
bucketStartTimeNs);
+ countProducer.setBucketSize(60 * NS_PER_SEC);
+
sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert);
int tagId = 1;
LogEvent event1(tagId, bucketStartTimeNs + 1);
+ event1.init();
LogEvent event2(tagId, bucketStartTimeNs + 2);
+ event2.init();
LogEvent event3(tagId, bucketStartTimeNs + 2 * bucketSizeNs + 1);
+ event3.init();
LogEvent event4(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 1);
+ event4.init();
LogEvent event5(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 2);
+ event5.init();
LogEvent event6(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 3);
+ event6.init();
LogEvent event7(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 2 * NS_PER_SEC);
+ event7.init();
// Two events in bucket #0.
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
@@ -356,13 +377,13 @@
EXPECT_EQ(3L, countProducer.mCurrentSlicedCounter->begin()->second);
// Anomaly at event 6 is within refractory period. The alarm is at event 5 timestamp not event 6
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
- event5.GetTimestampNs() / NS_PER_SEC + refPeriodSec);
+ event5.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec);
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event7);
EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
EXPECT_EQ(4L, countProducer.mCurrentSlicedCounter->begin()->second);
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
- event7.GetTimestampNs() / NS_PER_SEC + refPeriodSec);
+ event7.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec);
}
} // namespace statsd
diff --git a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
index 23e15f7..7969596 100644
--- a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
@@ -51,12 +51,15 @@
int tagId = 1;
LogEvent event1(tagId, bucketStartTimeNs + 1);
+ event1.init();
LogEvent event2(tagId, bucketStartTimeNs + bucketSizeNs + 2);
+ event2.init();
FieldMatcher dimensions;
DurationMetricProducer durationProducer(
kConfigKey, metric, -1 /*no condition*/, 1 /* start index */, 2 /* stop index */,
3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs);
+ durationProducer.setBucketSize(60 * NS_PER_SEC);
durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
@@ -86,14 +89,20 @@
int tagId = 1;
LogEvent event1(tagId, bucketStartTimeNs + 1);
+ event1.init();
LogEvent event2(tagId, bucketStartTimeNs + 2);
+ event2.init();
LogEvent event3(tagId, bucketStartTimeNs + bucketSizeNs + 1);
+ event3.init();
LogEvent event4(tagId, bucketStartTimeNs + bucketSizeNs + 3);
+ event4.init();
FieldMatcher dimensions;
DurationMetricProducer durationProducer(
kConfigKey, metric, 0 /* condition index */, 1 /* start index */, 2 /* stop index */,
3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs);
+ durationProducer.setBucketSize(60 * NS_PER_SEC);
+
EXPECT_FALSE(durationProducer.mCondition);
EXPECT_FALSE(durationProducer.isConditionSliced());
@@ -143,8 +152,11 @@
DurationMetricProducer durationProducer(
kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */,
3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs);
+ durationProducer.setBucketSize(60 * NS_PER_SEC);
- durationProducer.onMatchedLogEvent(1 /* start index*/, LogEvent(tagId, startTimeNs));
+ LogEvent start_event(tagId, startTimeNs);
+ start_event.init();
+ durationProducer.onMatchedLogEvent(1 /* start index*/, start_event);
EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
@@ -158,7 +170,9 @@
EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
// We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
- durationProducer.onMatchedLogEvent(2 /* stop index*/, LogEvent(tagId, endTimeNs));
+ LogEvent end_event(tagId, endTimeNs);
+ end_event.init();
+ durationProducer.onMatchedLogEvent(2 /* stop index*/, end_event);
buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
EXPECT_EQ(3UL, buckets.size());
EXPECT_EQ(eventUpgradeTimeNs, buckets[1].mBucketStartNs);
@@ -193,8 +207,11 @@
DurationMetricProducer durationProducer(
kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */,
3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs);
+ durationProducer.setBucketSize(60 * NS_PER_SEC);
- durationProducer.onMatchedLogEvent(1 /* start index*/, LogEvent(tagId, startTimeNs));
+ LogEvent start_event(tagId, startTimeNs);
+ start_event.init();
+ durationProducer.onMatchedLogEvent(1 /* start index*/, start_event);
EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
@@ -211,7 +228,9 @@
EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
// We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
- durationProducer.onMatchedLogEvent(2 /* stop index*/, LogEvent(tagId, endTimeNs));
+ LogEvent end_event(tagId, endTimeNs);
+ end_event.init();
+ durationProducer.onMatchedLogEvent(2 /* stop index*/, end_event);
buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
EXPECT_EQ(3UL, buckets.size());
EXPECT_EQ(eventUpgradeTimeNs, buckets[2].mBucketStartNs);
@@ -242,13 +261,19 @@
DurationMetricProducer durationProducer(
kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */,
3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs);
+ durationProducer.setBucketSize(60 * NS_PER_SEC);
+
sp<AnomalyTracker> anomalyTracker = durationProducer.addAnomalyTracker(alert);
EXPECT_TRUE(anomalyTracker != nullptr);
- durationProducer.onMatchedLogEvent(1 /* start index*/, LogEvent(tagId, startTimeNs));
+ LogEvent start_event(tagId, startTimeNs);
+ start_event.init();
+ durationProducer.onMatchedLogEvent(1 /* start index*/, start_event);
durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
// We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
- durationProducer.onMatchedLogEvent(2 /* stop index*/, LogEvent(tagId, endTimeNs));
+ LogEvent end_event(tagId, endTimeNs);
+ end_event.init();
+ durationProducer.onMatchedLogEvent(2 /* stop index*/, end_event);
EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - startTimeNs,
(uint64_t)anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
@@ -275,8 +300,11 @@
DurationMetricProducer durationProducer(
kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */,
3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs);
+ durationProducer.setBucketSize(60 * NS_PER_SEC);
- durationProducer.onMatchedLogEvent(1 /* start index*/, LogEvent(tagId, startTimeNs));
+ LogEvent start_event(tagId, startTimeNs);
+ start_event.init();
+ durationProducer.onMatchedLogEvent(1 /* start index*/, start_event);
EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
@@ -285,7 +313,9 @@
EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
// We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
- durationProducer.onMatchedLogEvent(2 /* stop index*/, LogEvent(tagId, endTimeNs));
+ LogEvent end_event(tagId, endTimeNs);
+ end_event.init();
+ durationProducer.onMatchedLogEvent(2 /* stop index*/, end_event);
EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
durationProducer.flushIfNeededLocked(bucketStartTimeNs + 3 * bucketSizeNs + 1);
@@ -318,8 +348,11 @@
DurationMetricProducer durationProducer(
kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */,
3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs);
+ durationProducer.setBucketSize(60 * NS_PER_SEC);
- durationProducer.onMatchedLogEvent(1 /* start index*/, LogEvent(tagId, startTimeNs));
+ LogEvent start_event(tagId, startTimeNs);
+ start_event.init();
+ durationProducer.onMatchedLogEvent(1 /* start index*/, start_event);
EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
@@ -328,7 +361,9 @@
EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
// Stop occurs in the same partial bucket as created for the app upgrade.
- durationProducer.onMatchedLogEvent(2 /* stop index*/, LogEvent(tagId, endTimeNs));
+ LogEvent end_event(tagId, endTimeNs);
+ end_event.init();
+ durationProducer.onMatchedLogEvent(2 /* stop index*/, end_event);
EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
diff --git a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
index 3deab37..8246268 100644
--- a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
@@ -13,7 +13,6 @@
// limitations under the License.
#include "src/metrics/EventMetricProducer.h"
-#include "src/dimension.h"
#include "metrics_test_helper.h"
#include "tests/statsd_test_util.h"
diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
index 470d4d0..0eb8ce2 100644
--- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
@@ -67,6 +67,7 @@
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
tagId, bucketStartTimeNs, pullerManager);
+ gaugeProducer.setBucketSize(60 * NS_PER_SEC);
vector<shared_ptr<LogEvent>> allData;
allData.clear();
@@ -80,9 +81,10 @@
gaugeProducer.onDataPulled(allData);
EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
auto it = gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->begin();
- EXPECT_EQ(10, it->second.value_int());
+ EXPECT_EQ(INT, it->mValue.getType());
+ EXPECT_EQ(10, it->mValue.int_value);
it++;
- EXPECT_EQ(11, it->second.value_int());
+ EXPECT_EQ(11, it->mValue.int_value);
EXPECT_EQ(0UL, gaugeProducer.mPastBuckets.size());
allData.clear();
@@ -96,16 +98,20 @@
gaugeProducer.onDataPulled(allData);
EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
it = gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->begin();
- EXPECT_EQ(24, it->second.value_int());
+ EXPECT_EQ(INT, it->mValue.getType());
+ EXPECT_EQ(24, it->mValue.int_value);
it++;
- EXPECT_EQ(25, it->second.value_int());
+ EXPECT_EQ(INT, it->mValue.getType());
+ EXPECT_EQ(25, it->mValue.int_value);
// One dimension.
EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.begin()->second.size());
it = gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.front().mFields->begin();
- EXPECT_EQ(10L, it->second.value_int());
+ EXPECT_EQ(INT, it->mValue.getType());
+ EXPECT_EQ(10L, it->mValue.int_value);
it++;
- EXPECT_EQ(11L, it->second.value_int());
+ EXPECT_EQ(INT, it->mValue.getType());
+ EXPECT_EQ(11L, it->mValue.int_value);
EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.begin()->second.back().mBucketNum);
gaugeProducer.flushIfNeededLocked(bucket4StartTimeNs);
@@ -114,9 +120,11 @@
EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.size());
it = gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.front().mFields->begin();
- EXPECT_EQ(24L, it->second.value_int());
+ EXPECT_EQ(INT, it->mValue.getType());
+ EXPECT_EQ(24L, it->mValue.int_value);
it++;
- EXPECT_EQ(25L, it->second.value_int());
+ EXPECT_EQ(INT, it->mValue.getType());
+ EXPECT_EQ(25L, it->mValue.int_value);
EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.back().mBucketNum);
}
@@ -137,6 +145,7 @@
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-1 /* -1 means no pulling */, bucketStartTimeNs,
pullerManager);
+ gaugeProducer.setBucketSize(60 * NS_PER_SEC);
sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert);
EXPECT_TRUE(anomalyTracker != nullptr);
@@ -218,6 +227,7 @@
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
tagId, bucketStartTimeNs, pullerManager);
+ gaugeProducer.setBucketSize(60 * NS_PER_SEC);
vector<shared_ptr<LogEvent>> allData;
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
@@ -230,7 +240,7 @@
EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin()
->second.front()
.mFields->begin()
- ->second.value_int());
+ ->mValue.int_value);
gaugeProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
EXPECT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
@@ -240,7 +250,7 @@
EXPECT_EQ(2, gaugeProducer.mCurrentSlicedBucket->begin()
->second.front()
.mFields->begin()
- ->second.value_int());
+ ->mValue.int_value);
allData.clear();
event = make_shared<LogEvent>(tagId, bucketStartTimeNs + bucketSizeNs + 1);
@@ -254,7 +264,7 @@
EXPECT_EQ(3, gaugeProducer.mCurrentSlicedBucket->begin()
->second.front()
.mFields->begin()
- ->second.value_int());
+ ->mValue.int_value);
}
TEST(GaugeMetricProducerTest, TestWithCondition) {
@@ -285,12 +295,14 @@
GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard, tagId,
bucketStartTimeNs, pullerManager);
+ gaugeProducer.setBucketSize(60 * NS_PER_SEC);
gaugeProducer.onConditionChanged(true, bucketStartTimeNs + 8);
EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
- EXPECT_EQ(100,
- gaugeProducer.mCurrentSlicedBucket->begin()->
- second.front().mFields->begin()->second.value_int());
+ EXPECT_EQ(100, gaugeProducer.mCurrentSlicedBucket->begin()
+ ->second.front()
+ .mFields->begin()
+ ->mValue.int_value);
EXPECT_EQ(0UL, gaugeProducer.mPastBuckets.size());
vector<shared_ptr<LogEvent>> allData;
@@ -303,19 +315,26 @@
gaugeProducer.onDataPulled(allData);
EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
- EXPECT_EQ(110,
- gaugeProducer.mCurrentSlicedBucket->begin()->
- second.front().mFields->begin()->second.value_int());
+ EXPECT_EQ(110, gaugeProducer.mCurrentSlicedBucket->begin()
+ ->second.front()
+ .mFields->begin()
+ ->mValue.int_value);
EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
- EXPECT_EQ(100, gaugeProducer.mPastBuckets.begin()->second.back()
- .mGaugeAtoms.front().mFields->begin()->second.value_int());
+ EXPECT_EQ(100, gaugeProducer.mPastBuckets.begin()
+ ->second.back()
+ .mGaugeAtoms.front()
+ .mFields->begin()
+ ->mValue.int_value);
gaugeProducer.onConditionChanged(false, bucket2StartTimeNs + 10);
gaugeProducer.flushIfNeededLocked(bucket3StartTimeNs + 10);
EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.size());
- EXPECT_EQ(110L, gaugeProducer.mPastBuckets.begin()->second.back()
- .mGaugeAtoms.front().mFields->begin()->second.value_int());
+ EXPECT_EQ(110L, gaugeProducer.mPastBuckets.begin()
+ ->second.back()
+ .mGaugeAtoms.front()
+ .mFields->begin()
+ ->mValue.int_value);
EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.begin()->second.back().mBucketNum);
}
@@ -335,6 +354,7 @@
gaugeFieldMatcher->add_child()->set_field(2);
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
tagId, bucketStartTimeNs, pullerManager);
+ gaugeProducer.setBucketSize(60 * NS_PER_SEC);
Alert alert;
alert.set_id(101);
@@ -353,9 +373,10 @@
gaugeProducer.onDataPulled({event1});
EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
- EXPECT_EQ(13L,
- gaugeProducer.mCurrentSlicedBucket->begin()->
- second.front().mFields->begin()->second.value_int());
+ EXPECT_EQ(13L, gaugeProducer.mCurrentSlicedBucket->begin()
+ ->second.front()
+ .mFields->begin()
+ ->mValue.int_value);
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
std::shared_ptr<LogEvent> event2 =
@@ -366,11 +387,12 @@
gaugeProducer.onDataPulled({event2});
EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
- EXPECT_EQ(15L,
- gaugeProducer.mCurrentSlicedBucket->begin()->
- second.front().mFields->begin()->second.value_int());
+ EXPECT_EQ(15L, gaugeProducer.mCurrentSlicedBucket->begin()
+ ->second.front()
+ .mFields->begin()
+ ->mValue.int_value);
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
- event2->GetTimestampNs() / NS_PER_SEC + refPeriodSec);
+ event2->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec);
std::shared_ptr<LogEvent> event3 =
std::make_shared<LogEvent>(tagId, bucketStartTimeNs + 2 * bucketSizeNs + 10);
@@ -380,11 +402,12 @@
gaugeProducer.onDataPulled({event3});
EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
- EXPECT_EQ(26L,
- gaugeProducer.mCurrentSlicedBucket->begin()->
- second.front().mFields->begin()->second.value_int());
+ EXPECT_EQ(26L, gaugeProducer.mCurrentSlicedBucket->begin()
+ ->second.front()
+ .mFields->begin()
+ ->mValue.int_value);
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
- event2->GetTimestampNs() / NS_PER_SEC + refPeriodSec);
+ event2->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec);
// The event4 does not have the gauge field. Thus the current bucket value is 0.
std::shared_ptr<LogEvent> event4 =
diff --git a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
index 2658e4e..3397f14 100644
--- a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
@@ -53,7 +53,8 @@
const HashableDimensionKey key1 = getMockedDimensionKey(TagId, 1, "1");
const HashableDimensionKey key2 = getMockedDimensionKey(TagId, 1, "2");
- FieldMatcher dimensionInCondition;
+ vector<Matcher> dimensionInCondition;
+
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
@@ -89,7 +90,7 @@
const HashableDimensionKey key1 = getMockedDimensionKey(TagId, 1, "1");
const HashableDimensionKey key2 = getMockedDimensionKey(TagId, 1, "2");
- FieldMatcher dimensionInCondition;
+ vector<Matcher> dimensionInCondition;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
@@ -126,7 +127,7 @@
const std::vector<HashableDimensionKey> conditionKey = {getMockedDimensionKey(TagId, 4, "1")};
const HashableDimensionKey key1 = getMockedDimensionKey(TagId, 1, "1");
const HashableDimensionKey key2 = getMockedDimensionKey(TagId, 1, "2");
- FieldMatcher dimensionInCondition;
+ vector<Matcher> dimensionInCondition;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
@@ -168,7 +169,7 @@
const std::vector<HashableDimensionKey> conditionKey = {getMockedDimensionKey(TagId, 4, "1")};
const HashableDimensionKey key1 = getMockedDimensionKey(TagId, 1, "1");
const HashableDimensionKey key2 = getMockedDimensionKey(TagId, 1, "2");
- FieldMatcher dimensionInCondition;
+ vector<Matcher> dimensionInCondition;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
@@ -206,7 +207,7 @@
const std::vector<HashableDimensionKey> conditionKey = {getMockedDimensionKey(TagId, 4, "1")};
const HashableDimensionKey key1 = getMockedDimensionKey(TagId, 1, "1");
- FieldMatcher dimensionInCondition;
+ vector<Matcher> dimensionInCondition;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
ConditionKey conditionKey1;
diff --git a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
index 4b579b1..cb731c5 100644
--- a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
@@ -52,14 +52,13 @@
{getMockedDimensionKey(TagId, 1, "maps")};
const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
- FieldMatcher dimensionInCondition;
+ vector<Matcher> dimensionInCondition;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
uint64_t bucketStartTimeNs = 10000000000;
- uint64_t bucketEndTimeNs = bucketStartTimeNs + bucketSizeNs;
uint64_t bucketNum = 0;
uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
uint64_t durationTimeNs = 2 * 1000;
@@ -88,14 +87,13 @@
{getMockedDimensionKey(TagId, 1, "maps")};
const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
- FieldMatcher dimensionInCondition;
+ vector<Matcher> dimensionInCondition;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
uint64_t bucketStartTimeNs = 10000000000;
- uint64_t bucketEndTimeNs = bucketStartTimeNs + bucketSizeNs;
uint64_t bucketNum = 0;
uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
@@ -122,14 +120,13 @@
{getMockedDimensionKey(TagId, 1, "maps")};
const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
- FieldMatcher dimensionInCondition;
+ vector<Matcher> dimensionInCondition;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
uint64_t bucketStartTimeNs = 10000000000;
- uint64_t bucketEndTimeNs = bucketStartTimeNs + bucketSizeNs;
uint64_t bucketNum = 0;
uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
@@ -155,14 +152,13 @@
{getMockedDimensionKey(TagId, 1, "maps")};
const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
- FieldMatcher dimensionInCondition;
+ vector<Matcher> dimensionInCondition;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
uint64_t bucketStartTimeNs = 10000000000;
- uint64_t bucketEndTimeNs = bucketStartTimeNs + bucketSizeNs;
uint64_t bucketNum = 0;
uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
uint64_t durationTimeNs = 2 * 1000;
@@ -197,7 +193,7 @@
{getMockedDimensionKey(TagId, 1, "maps")};
const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
- FieldMatcher dimensionInCondition;
+ vector<Matcher> dimensionInCondition;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
ConditionKey key1;
@@ -210,7 +206,6 @@
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
uint64_t bucketStartTimeNs = 10000000000;
- uint64_t bucketEndTimeNs = bucketStartTimeNs + bucketSizeNs;
uint64_t bucketNum = 0;
uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
uint64_t durationTimeNs = 2 * 1000;
@@ -238,7 +233,7 @@
{getMockedDimensionKey(TagId, 1, "maps")};
const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
- FieldMatcher dimensionInCondition;
+ vector<Matcher> dimensionInCondition;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
ConditionKey key1;
@@ -253,7 +248,6 @@
uint64_t bucketStartTimeNs = 10000000000;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
- uint64_t bucketEndTimeNs = bucketStartTimeNs + bucketSizeNs;
uint64_t bucketNum = 0;
uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
uint64_t durationTimeNs = 2 * 1000;
@@ -283,7 +277,7 @@
{getMockedDimensionKey(TagId, 1, "maps")};
const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
- FieldMatcher dimensionInCondition;
+ vector<Matcher> dimensionInCondition;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
ConditionKey key1;
@@ -296,7 +290,6 @@
uint64_t bucketStartTimeNs = 10000000000;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
- uint64_t bucketEndTimeNs = bucketStartTimeNs + bucketSizeNs;
uint64_t bucketNum = 0;
uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
@@ -326,7 +319,7 @@
{getMockedDimensionKey(TagId, 1, "maps")};
const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
- FieldMatcher dimensionInCondition;
+ vector<Matcher> dimensionInCondition;
Alert alert;
alert.set_id(101);
alert.set_metric_id(1);
@@ -338,7 +331,6 @@
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
uint64_t bucketStartTimeNs = 10 * NS_PER_SEC;
- uint64_t bucketEndTimeNs = bucketStartTimeNs + bucketSizeNs;
uint64_t bucketNum = 0;
uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
@@ -395,7 +387,7 @@
const std::vector<HashableDimensionKey> kConditionKey1 = {getMockedDimensionKey(TagId, 1, "maps")};
const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
- FieldMatcher dimensionInCondition;
+ vector<Matcher> dimensionInCondition;
Alert alert;
alert.set_id(101);
alert.set_metric_id(1);
@@ -408,7 +400,6 @@
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
uint64_t bucketStartTimeNs = 10 * NS_PER_SEC;
- uint64_t bucketEndTimeNs = bucketStartTimeNs + bucketSizeNs;
uint64_t bucketNum = 0;
uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
@@ -421,15 +412,15 @@
tracker.noteStop(kEventKey1, eventStartTimeNs + 10, false);
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey), 0U);
EXPECT_TRUE(tracker.mStarted.empty());
- EXPECT_EQ(10LL, tracker.mDuration);
+ EXPECT_EQ(10LL, tracker.mDuration); // 10ns
EXPECT_EQ(0u, tracker.mStarted.size());
tracker.noteStart(kEventKey1, true, eventStartTimeNs + 20, ConditionKey());
EXPECT_EQ(1u, anomalyTracker->mAlarms.size());
- EXPECT_EQ((long long)(51ULL * NS_PER_SEC),
+ EXPECT_EQ((long long)(52ULL * NS_PER_SEC), // (10s + 1s + 1ns + 20ns) - 10ns + 40s, rounded up
(long long)(anomalyTracker->mAlarms.begin()->second->timestampSec * NS_PER_SEC));
- // The alarm is set to fire at 51s, and when it does, an anomaly would be declared. However,
+ // The alarm is set to fire at 52s, and when it does, an anomaly would be declared. However,
// because this is a unit test, the alarm won't actually fire at all. Since the alarm fails
// to fire in time, the anomaly is instead caught when noteStop is called, at around 71s.
tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs + 25, &buckets);
@@ -446,7 +437,7 @@
{getMockedDimensionKey(TagId, 1, "maps")};
const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
- FieldMatcher dimensionInCondition;
+ vector<Matcher> dimensionInCondition;
Alert alert;
alert.set_id(101);
alert.set_metric_id(1);
@@ -460,7 +451,6 @@
ConditionKey conkey;
conkey[StringToId("APP_BACKGROUND")] = kConditionKey1;
uint64_t bucketStartTimeNs = 10 * NS_PER_SEC;
- uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
uint64_t bucketSizeNs = 30 * NS_PER_SEC;
sp<DurationAnomalyTracker> anomalyTracker = new DurationAnomalyTracker(alert, kConfigKey);
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 325a372..ce4fa32 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -66,6 +66,7 @@
ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
tagId, bucketStartTimeNs, pullerManager);
+ valueProducer.setBucketSize(60 * NS_PER_SEC);
vector<shared_ptr<LogEvent>> allData;
allData.clear();
@@ -79,6 +80,8 @@
// has one slice
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
+ valueProducer.setBucketSize(60 * NS_PER_SEC);
+
// startUpdated:true tainted:0 sum:0 start:11
EXPECT_EQ(true, curInterval.startUpdated);
EXPECT_EQ(0, curInterval.tainted);
@@ -162,7 +165,7 @@
ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, tagId, bucketStartTimeNs,
pullerManager);
-
+ valueProducer.setBucketSize(60 * NS_PER_SEC);
valueProducer.onConditionChanged(true, bucketStartTimeNs + 8);
// has one slice
@@ -215,6 +218,7 @@
make_shared<StrictMock<MockStatsPullerManager>>();
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, -1, bucketStartTimeNs,
pullerManager);
+ valueProducer.setBucketSize(60 * NS_PER_SEC);
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event1->write(1);
@@ -269,6 +273,7 @@
}));
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, tagId, bucketStartTimeNs,
pullerManager);
+ valueProducer.setBucketSize(60 * NS_PER_SEC);
vector<shared_ptr<LogEvent>> allData;
allData.clear();
@@ -311,6 +316,7 @@
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, -1, bucketStartTimeNs,
pullerManager);
+ valueProducer.setBucketSize(60 * NS_PER_SEC);
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event1->write(1);
@@ -357,6 +363,8 @@
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-1 /*not pulled*/, bucketStartTimeNs);
+ valueProducer.setBucketSize(60 * NS_PER_SEC);
+
sp<AnomalyTracker> anomalyTracker = valueProducer.addAnomalyTracker(alert);
@@ -406,16 +414,16 @@
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event4);
// Anomaly at event 4 since Value sum == 131 > 130!
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
- event4->GetTimestampNs() / NS_PER_SEC + refPeriodSec);
+ event4->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec);
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event5);
// Event 5 is within 3 sec refractory period. Thus last alarm timestamp is still event4.
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
- event4->GetTimestampNs() / NS_PER_SEC + refPeriodSec);
+ event4->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec);
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event6);
// Anomaly at event 6 since Value sum == 160 > 130 and after refractory period.
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
- event6->GetTimestampNs() / NS_PER_SEC + refPeriodSec);
+ event6->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec);
}
} // namespace statsd
diff --git a/cmds/statsd/tests/metrics/metrics_test_helper.cpp b/cmds/statsd/tests/metrics/metrics_test_helper.cpp
index ab9345a..7b9c0d6 100644
--- a/cmds/statsd/tests/metrics/metrics_test_helper.cpp
+++ b/cmds/statsd/tests/metrics/metrics_test_helper.cpp
@@ -19,20 +19,26 @@
namespace statsd {
HashableDimensionKey getMockedDimensionKey(int tagId, int key, string value) {
- DimensionsValue dimensionsValue;
- dimensionsValue.set_field(tagId);
- dimensionsValue.mutable_value_tuple()->add_dimensions_value()->set_field(key);
- dimensionsValue.mutable_value_tuple()->mutable_dimensions_value(0)->set_value_str(value);
- return HashableDimensionKey(dimensionsValue);
+ HashableDimensionKey dimension;
+ int pos[] = {key, 0, 0};
+ dimension.addValue(FieldValue(Field(tagId, pos, 0), Value(value)));
+
+ return dimension;
}
MetricDimensionKey getMockedMetricDimensionKey(int tagId, int key, string value) {
- DimensionsValue dimensionsValue;
- dimensionsValue.set_field(tagId);
- dimensionsValue.mutable_value_tuple()->add_dimensions_value()->set_field(key);
- dimensionsValue.mutable_value_tuple()->mutable_dimensions_value(0)->set_value_str(value);
- return MetricDimensionKey(HashableDimensionKey(dimensionsValue), DEFAULT_DIMENSION_KEY);
+ return MetricDimensionKey(getMockedDimensionKey(tagId, key, value), DEFAULT_DIMENSION_KEY);
}
+
+void buildSimpleAtomFieldMatcher(const int tagId, FieldMatcher* matcher) {
+ matcher->set_field(tagId);
+}
+
+void buildSimpleAtomFieldMatcher(const int tagId, const int fieldNum, FieldMatcher* matcher) {
+ matcher->set_field(tagId);
+ matcher->add_child()->set_field(fieldNum);
+}
+
} // namespace statsd
} // namespace os
} // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/tests/metrics/metrics_test_helper.h b/cmds/statsd/tests/metrics/metrics_test_helper.h
index b48de54..a01de63 100644
--- a/cmds/statsd/tests/metrics/metrics_test_helper.h
+++ b/cmds/statsd/tests/metrics/metrics_test_helper.h
@@ -26,12 +26,10 @@
class MockConditionWizard : public ConditionWizard {
public:
- MOCK_METHOD4(
- query,
- ConditionState(const int conditionIndex,
- const ConditionKey& conditionParameters,
- const FieldMatcher& dimensionFields,
- std::unordered_set<HashableDimensionKey> *dimensionKeySet));
+ MOCK_METHOD4(query,
+ ConditionState(const int conditionIndex, const ConditionKey& conditionParameters,
+ const vector<Matcher>& dimensionFields,
+ std::unordered_set<HashableDimensionKey>* dimensionKeySet));
};
class MockStatsPullerManager : public StatsPullerManager {
@@ -49,6 +47,10 @@
HashableDimensionKey getMockedDimensionKey(int tagId, int key, std::string value);
MetricDimensionKey getMockedMetricDimensionKey(int tagId, int key, std::string value);
+// Utils to build FieldMatcher proto for simple one-depth atoms.
+void buildSimpleAtomFieldMatcher(const int tagId, const int atomFieldNum, FieldMatcher* matcher);
+void buildSimpleAtomFieldMatcher(const int tagId, FieldMatcher* matcher);
+
} // namespace statsd
} // namespace os
} // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp
index 13055cb..b7acef7 100644
--- a/cmds/statsd/tests/statsd_test_util.cpp
+++ b/cmds/statsd/tests/statsd_test_util.cpp
@@ -186,7 +186,7 @@
Predicate CreateScreenIsOffPredicate() {
Predicate predicate;
- predicate.set_id(StringToId("ScreenIsOff"));
+ predicate.set_id(1111123);
predicate.mutable_simple_predicate()->set_start(StringToId("ScreenTurnedOff"));
predicate.mutable_simple_predicate()->set_stop(StringToId("ScreenTurnedOn"));
return predicate;
@@ -202,7 +202,7 @@
Predicate CreateIsSyncingPredicate() {
Predicate predicate;
- predicate.set_id(StringToId("IsSyncing"));
+ predicate.set_id(33333333333333);
predicate.mutable_simple_predicate()->set_start(StringToId("SyncStart"));
predicate.mutable_simple_predicate()->set_stop(StringToId("SyncEnd"));
return predicate;
@@ -406,7 +406,7 @@
void sortLogEventsByTimestamp(std::vector<std::unique_ptr<LogEvent>> *events) {
std::sort(events->begin(), events->end(),
[](const std::unique_ptr<LogEvent>& a, const std::unique_ptr<LogEvent>& b) {
- return a->GetTimestampNs() < b->GetTimestampNs();
+ return a->GetElapsedTimestampNs() < b->GetElapsedTimestampNs();
});
}
@@ -461,6 +461,93 @@
.value_tuple().dimensions_value(1).value_str(), tag);
}
+bool EqualsTo(const DimensionsValue& s1, const DimensionsValue& s2) {
+ if (s1.field() != s2.field()) {
+ return false;
+ }
+ if (s1.value_case() != s2.value_case()) {
+ return false;
+ }
+ switch (s1.value_case()) {
+ case DimensionsValue::ValueCase::kValueStr:
+ return (s1.value_str() == s2.value_str());
+ case DimensionsValue::ValueCase::kValueInt:
+ return s1.value_int() == s2.value_int();
+ case DimensionsValue::ValueCase::kValueLong:
+ return s1.value_long() == s2.value_long();
+ case DimensionsValue::ValueCase::kValueBool:
+ return s1.value_bool() == s2.value_bool();
+ case DimensionsValue::ValueCase::kValueFloat:
+ return s1.value_float() == s2.value_float();
+ case DimensionsValue::ValueCase::kValueTuple: {
+ if (s1.value_tuple().dimensions_value_size() !=
+ s2.value_tuple().dimensions_value_size()) {
+ return false;
+ }
+ bool allMatched = true;
+ for (int i = 0; allMatched && i < s1.value_tuple().dimensions_value_size(); ++i) {
+ allMatched &= EqualsTo(s1.value_tuple().dimensions_value(i),
+ s2.value_tuple().dimensions_value(i));
+ }
+ return allMatched;
+ }
+ case DimensionsValue::ValueCase::VALUE_NOT_SET:
+ default:
+ return true;
+ }
+}
+
+bool LessThan(const DimensionsValue& s1, const DimensionsValue& s2) {
+ if (s1.field() != s2.field()) {
+ return s1.field() < s2.field();
+ }
+ if (s1.value_case() != s2.value_case()) {
+ return s1.value_case() < s2.value_case();
+ }
+ switch (s1.value_case()) {
+ case DimensionsValue::ValueCase::kValueStr:
+ return s1.value_str() < s2.value_str();
+ case DimensionsValue::ValueCase::kValueInt:
+ return s1.value_int() < s2.value_int();
+ case DimensionsValue::ValueCase::kValueLong:
+ return s1.value_long() < s2.value_long();
+ case DimensionsValue::ValueCase::kValueBool:
+ return (int)s1.value_bool() < (int)s2.value_bool();
+ case DimensionsValue::ValueCase::kValueFloat:
+ return s1.value_float() < s2.value_float();
+ case DimensionsValue::ValueCase::kValueTuple: {
+ if (s1.value_tuple().dimensions_value_size() !=
+ s2.value_tuple().dimensions_value_size()) {
+ return s1.value_tuple().dimensions_value_size() <
+ s2.value_tuple().dimensions_value_size();
+ }
+ for (int i = 0; i < s1.value_tuple().dimensions_value_size(); ++i) {
+ if (EqualsTo(s1.value_tuple().dimensions_value(i),
+ s2.value_tuple().dimensions_value(i))) {
+ continue;
+ } else {
+ return LessThan(s1.value_tuple().dimensions_value(i),
+ s2.value_tuple().dimensions_value(i));
+ }
+ }
+ return false;
+ }
+ case DimensionsValue::ValueCase::VALUE_NOT_SET:
+ default:
+ return false;
+ }
+}
+
+bool LessThan(const DimensionsPair& s1, const DimensionsPair& s2) {
+ if (LessThan(s1.dimInWhat, s2.dimInWhat)) {
+ return true;
+ } else if (LessThan(s2.dimInWhat, s1.dimInWhat)) {
+ return false;
+ }
+
+ return LessThan(s1.dimInCondition, s2.dimInCondition);
+}
+
} // namespace statsd
} // namespace os
} // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/tests/statsd_test_util.h b/cmds/statsd/tests/statsd_test_util.h
index 6638893..5d83ed7 100644
--- a/cmds/statsd/tests/statsd_test_util.h
+++ b/cmds/statsd/tests/statsd_test_util.h
@@ -159,14 +159,30 @@
void ValidateAttributionUidAndTagDimension(
const DimensionsValue& value, int atomId, int uid, const std::string& tag);
+struct DimensionsPair {
+ DimensionsPair(DimensionsValue m1, DimensionsValue m2) : dimInWhat(m1), dimInCondition(m2){};
+
+ DimensionsValue dimInWhat;
+ DimensionsValue dimInCondition;
+};
+
+bool LessThan(const DimensionsValue& s1, const DimensionsValue& s2);
+bool LessThan(const DimensionsPair& s1, const DimensionsPair& s2);
+
+struct DimensionCompare {
+ bool operator()(const DimensionsPair& s1, const DimensionsPair& s2) const {
+ return LessThan(s1, s2);
+ }
+};
+
template <typename T>
void sortMetricDataByDimensionsValue(const T& metricData, T* sortedMetricData) {
- std::map<MetricDimensionKey, int> dimensionIndexMap;
+ std::map<DimensionsPair, int, DimensionCompare> dimensionIndexMap;
for (int i = 0; i < metricData.data_size(); ++i) {
- dimensionIndexMap.insert(std::make_pair(
- MetricDimensionKey(HashableDimensionKey(metricData.data(i).dimensions_in_what()),
- HashableDimensionKey(metricData.data(i).dimensions_in_condition())),
- i));
+ dimensionIndexMap.insert(
+ std::make_pair(DimensionsPair(metricData.data(i).dimensions_in_what(),
+ metricData.data(i).dimensions_in_condition()),
+ i));
}
for (const auto& itr : dimensionIndexMap) {
*sortedMetricData->add_data() = metricData.data(itr.second);
diff --git a/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/DisplayProtoUtils.java b/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/DisplayProtoUtils.java
index 03e5fef..b6b16e4 100644
--- a/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/DisplayProtoUtils.java
+++ b/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/DisplayProtoUtils.java
@@ -32,9 +32,9 @@
for (StatsLog.ConfigMetricsReport report : reports.getReportsList()) {
sb.append("StatsLogReport size: ").append(report.getMetricsCount()).append("\n");
- sb.append("Last report time:").append(getDateStr(report.getLastReportNanos())).
+ sb.append("Last report time:").append(getDateStr(report.getLastReportElapsedNanos())).
append("\n");
- sb.append("Current report time:").append(getDateStr(report.getCurrentReportNanos())).
+ sb.append("Current report time:").append(getDateStr(report.getCurrentReportElapsedNanos())).
append("\n");
for (StatsLog.StatsLogReport log : report.getMetricsList()) {
sb.append("\n\n");
@@ -109,8 +109,8 @@
}
for (StatsLog.DurationBucketInfo info : duration.getBucketInfoList()) {
- sb.append("\t[").append(getDateStr(info.getStartBucketNanos())).append("-")
- .append(getDateStr(info.getEndBucketNanos())).append("] -> ")
+ sb.append("\t[").append(getDateStr(info.getStartBucketElapsedNanos())).append("-")
+ .append(getDateStr(info.getEndBucketElapsedNanos())).append("] -> ")
.append(info.getDurationNanos()).append(" ns\n");
}
}
@@ -121,7 +121,7 @@
StatsLog.StatsLogReport.EventMetricDataWrapper eventMetricDataWrapper =
log.getEventMetrics();
for (StatsLog.EventMetricData event : eventMetricDataWrapper.getDataList()) {
- sb.append(getDateStr(event.getTimestampNanos())).append(": ");
+ sb.append(getDateStr(event.getElapsedTimestampNanos())).append(": ");
sb.append(event.getAtom().getPushedCase().toString()).append("\n");
}
}
@@ -141,8 +141,8 @@
}
for (StatsLog.CountBucketInfo info : count.getBucketInfoList()) {
- sb.append("\t[").append(getDateStr(info.getStartBucketNanos())).append("-")
- .append(getDateStr(info.getEndBucketNanos())).append("] -> ")
+ sb.append("\t[").append(getDateStr(info.getStartBucketElapsedNanos())).append("-")
+ .append(getDateStr(info.getEndBucketElapsedNanos())).append("] -> ")
.append(info.getCount()).append("\n");
}
}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/DisplayProtoUtils.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/DisplayProtoUtils.java
index 87b82c2..d55f3f3 100644
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/DisplayProtoUtils.java
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/DisplayProtoUtils.java
@@ -36,9 +36,9 @@
int numMetrics = 0;
for (StatsLog.ConfigMetricsReport report : reports.getReportsList()) {
sb.append("StatsLogReport size: ").append(report.getMetricsCount()).append("\n");
- sb.append("Last report time:").append(getDateStr(report.getLastReportNanos())).
+ sb.append("Last report time:").append(getDateStr(report.getLastReportElapsedNanos())).
append("\n");
- sb.append("Current report time:").append(getDateStr(report.getCurrentReportNanos())).
+ sb.append("Current report time:").append(getDateStr(report.getCurrentReportElapsedNanos())).
append("\n");
for (StatsLog.StatsLogReport log : report.getMetricsList()) {
numMetrics++;
@@ -120,8 +120,8 @@
}
for (StatsLog.DurationBucketInfo info : duration.getBucketInfoList()) {
- sb.append("\t[").append(getDateStr(info.getStartBucketNanos())).append("-")
- .append(getDateStr(info.getEndBucketNanos())).append("] -> ")
+ sb.append("\t[").append(getDateStr(info.getStartBucketElapsedNanos())).append("-")
+ .append(getDateStr(info.getEndBucketElapsedNanos())).append("] -> ")
.append(info.getDurationNanos()).append(" ns\n");
}
}
@@ -132,7 +132,7 @@
StatsLog.StatsLogReport.EventMetricDataWrapper eventMetricDataWrapper =
log.getEventMetrics();
for (StatsLog.EventMetricData event : eventMetricDataWrapper.getDataList()) {
- sb.append(getDateStr(event.getTimestampNanos())).append(": ");
+ sb.append(getDateStr(event.getElapsedTimestampNanos())).append(": ");
sb.append(event.getAtom().getPushedCase().toString()).append("\n");
}
}
@@ -152,8 +152,8 @@
}
for (StatsLog.CountBucketInfo info : count.getBucketInfoList()) {
- sb.append("\t[").append(getDateStr(info.getStartBucketNanos())).append("-")
- .append(getDateStr(info.getEndBucketNanos())).append("] -> ")
+ sb.append("\t[").append(getDateStr(info.getStartBucketElapsedNanos())).append("-")
+ .append(getDateStr(info.getEndBucketElapsedNanos())).append("] -> ")
.append(info.getCount()).append("\n");
}
}
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 7b70f59..b822f2c 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -1,7 +1,11 @@
Landroid/accounts/AccountManager;->mContext:Landroid/content/Context;
+Landroid/accounts/IAccountManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/accounts/IAccountManager;
+Landroid/accounts/IAccountManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
+Landroid/animation/LayoutTransition;->cancel()V
Landroid/animation/ValueAnimator;->animateValue(F)V
Landroid/animation/ValueAnimator;->getDurationScale()F
Landroid/animation/ValueAnimator;->sDurationScale:F
+Landroid/animation/ValueAnimator;->setDurationScale(F)V
Landroid/app/Activity;->convertFromTranslucent()V
Landroid/app/Activity;->convertToTranslucent(Landroid/app/Activity$TranslucentConversionListener;Landroid/app/ActivityOptions;)Z
Landroid/app/Activity;->getActivityOptions()Landroid/app/ActivityOptions;
@@ -12,6 +16,8 @@
Landroid/app/ActivityManager;->forceStopPackage(Ljava/lang/String;)V
Landroid/app/ActivityManager;->getCurrentUser()I
Landroid/app/ActivityManager;->getPackageImportance(Ljava/lang/String;)I
+Landroid/app/ActivityManager;->getService()Landroid/app/IActivityManager;
+Landroid/app/ActivityManager;->IActivityManagerSingleton:Landroid/util/Singleton;
Landroid/app/ActivityManager;->isLowRamDeviceStatic()Z
Landroid/app/ActivityManager;->isUserRunning(I)Z
Landroid/app/ActivityManager;->mContext:Landroid/content/Context;
@@ -22,17 +28,37 @@
Landroid/app/ActivityManager$RunningAppProcessInfo;->flags:I
Landroid/app/ActivityManager$RunningAppProcessInfo;->processState:I
Landroid/app/Activity;->mApplication:Landroid/app/Application;
+Landroid/app/Activity;->mComponent:Landroid/content/ComponentName;
+Landroid/app/Activity;->mFragments:Landroid/app/FragmentController;
Landroid/app/Activity;->mHandler:Landroid/os/Handler;
+Landroid/app/Activity;->mInstrumentation:Landroid/app/Instrumentation;
+Landroid/app/Activity;->mReferrer:Ljava/lang/String;
Landroid/app/Activity;->mResultCode:I
Landroid/app/Activity;->mResultData:Landroid/content/Intent;
+Landroid/app/Activity;->mResumed:Z
Landroid/app/Activity;->mToken:Landroid/os/IBinder;
Landroid/app/Activity;->mWindow:Landroid/view/Window;
Landroid/app/Activity;->mWindowManager:Landroid/view/WindowManager;
Landroid/app/Activity;->setDisablePreviewScreenshots(Z)V
Landroid/app/ActivityThread$ActivityClientRecord;->activityInfo:Landroid/content/pm/ActivityInfo;
+Landroid/app/ActivityThread$ActivityClientRecord;->activity:Landroid/app/Activity;
+Landroid/app/ActivityThread$ActivityClientRecord;->compatInfo:Landroid/content/res/CompatibilityInfo;
+Landroid/app/ActivityThread$ActivityClientRecord;->intent:Landroid/content/Intent;
+Landroid/app/ActivityThread$ActivityClientRecord;->mPreserveWindow:Z
+Landroid/app/ActivityThread$ActivityClientRecord;->packageInfo:Landroid/app/LoadedApk;
+Landroid/app/ActivityThread$ActivityClientRecord;->paused:Z
+Landroid/app/ActivityThread$ActivityClientRecord;->stopped:Z
Landroid/app/ActivityThread$ActivityClientRecord;->token:Landroid/os/IBinder;
+Landroid/app/ActivityThread$AppBindData;->appInfo:Landroid/content/pm/ApplicationInfo;
Landroid/app/ActivityThread$AppBindData;->info:Landroid/app/LoadedApk;
Landroid/app/ActivityThread$AppBindData;->instrumentationArgs:Landroid/os/Bundle;
+Landroid/app/ActivityThread$AppBindData;->providers:Ljava/util/List;
+Landroid/app/ActivityThread$BindServiceData;->intent:Landroid/content/Intent;
+Landroid/app/ActivityThread$BindServiceData;->token:Landroid/os/IBinder;
+Landroid/app/ActivityThread$CreateServiceData;->compatInfo:Landroid/content/res/CompatibilityInfo;
+Landroid/app/ActivityThread$CreateServiceData;->info:Landroid/content/pm/ServiceInfo;
+Landroid/app/ActivityThread$CreateServiceData;->intent:Landroid/content/Intent;
+Landroid/app/ActivityThread$CreateServiceData;->token:Landroid/os/IBinder;
Landroid/app/ActivityThread;->currentActivityThread()Landroid/app/ActivityThread;
Landroid/app/ActivityThread;->currentApplication()Landroid/app/Application;
Landroid/app/ActivityThread;->currentPackageName()Ljava/lang/String;
@@ -42,25 +68,41 @@
Landroid/app/ActivityThread;->getApplicationThread()Landroid/app/ActivityThread$ApplicationThread;
Landroid/app/ActivityThread;->getHandler()Landroid/os/Handler;
Landroid/app/ActivityThread;->getInstrumentation()Landroid/app/Instrumentation;
+Landroid/app/ActivityThread;->getPackageInfo(Landroid/content/pm/ApplicationInfo;Landroid/content/res/CompatibilityInfo;I)Landroid/app/LoadedApk;
+Landroid/app/ActivityThread;->getPackageInfoNoCheck(Landroid/content/pm/ApplicationInfo;Landroid/content/res/CompatibilityInfo;)Landroid/app/LoadedApk;
Landroid/app/ActivityThread;->getPackageManager()Landroid/content/pm/IPackageManager;
Landroid/app/ActivityThread;->getProcessName()Ljava/lang/String;
+Landroid/app/ActivityThread;->getSystemContext()Landroid/app/ContextImpl;
Landroid/app/ActivityThread$H;->BIND_SERVICE:I
Landroid/app/ActivityThread$H;->CREATE_SERVICE:I
Landroid/app/ActivityThread$H;->EXIT_APPLICATION:I
+Landroid/app/ActivityThread$H;->GC_WHEN_IDLE:I
Landroid/app/ActivityThread$H;->RECEIVER:I
Landroid/app/ActivityThread$H;->REMOVE_PROVIDER:I
Landroid/app/ActivityThread$H;->SERVICE_ARGS:I
Landroid/app/ActivityThread$H;->STOP_SERVICE:I
Landroid/app/ActivityThread$H;->UNBIND_SERVICE:I
Landroid/app/ActivityThread;->installContentProviders(Landroid/content/Context;Ljava/util/List;)V
+Landroid/app/ActivityThread;->installProvider(Landroid/content/Context;Landroid/app/ContentProviderHolder;Landroid/content/pm/ProviderInfo;ZZZ)Landroid/app/ContentProviderHolder;
Landroid/app/ActivityThread;->mActivities:Landroid/util/ArrayMap;
Landroid/app/ActivityThread;->mAllApplications:Ljava/util/ArrayList;
Landroid/app/ActivityThread;->mBoundApplication:Landroid/app/ActivityThread$AppBindData;
+Landroid/app/ActivityThread;->mH:Landroid/app/ActivityThread$H;
Landroid/app/ActivityThread;->mInitialApplication:Landroid/app/Application;
Landroid/app/ActivityThread;->mInstrumentation:Landroid/app/Instrumentation;
Landroid/app/ActivityThread;->mNumVisibleActivities:I
Landroid/app/ActivityThread;->mPackages:Landroid/util/ArrayMap;
+Landroid/app/ActivityThread;->mProviderMap:Landroid/util/ArrayMap;
+Landroid/app/ActivityThread;->mServices:Landroid/util/ArrayMap;
Landroid/app/ActivityThread;->performStopActivity(Landroid/os/IBinder;ZLjava/lang/String;)V
+Landroid/app/ActivityThread$ProviderClientRecord;->mLocalProvider:Landroid/content/ContentProvider;
+Landroid/app/ActivityThread$ReceiverData;->compatInfo:Landroid/content/res/CompatibilityInfo;
+Landroid/app/ActivityThread$ReceiverData;->info:Landroid/content/pm/ActivityInfo;
+Landroid/app/ActivityThread$ReceiverData;->intent:Landroid/content/Intent;
+Landroid/app/ActivityThread;->sCurrentActivityThread:Landroid/app/ActivityThread;
+Landroid/app/ActivityThread;->sendActivityResult(Landroid/os/IBinder;Ljava/lang/String;IILandroid/content/Intent;)V
+Landroid/app/ActivityThread$ServiceArgsData;->args:Landroid/content/Intent;
+Landroid/app/ActivityThread$ServiceArgsData;->token:Landroid/os/IBinder;
Landroid/app/ActivityThread;->sPackageManager:Landroid/content/pm/IPackageManager;
Landroid/app/admin/DevicePolicyManager;->getDeviceOwnerComponentOnAnyUser()Landroid/content/ComponentName;
Landroid/app/admin/DevicePolicyManager;->getDeviceOwner()Ljava/lang/String;
@@ -72,10 +114,14 @@
Landroid/app/admin/DevicePolicyManager;->packageHasActiveAdmins(Ljava/lang/String;)Z
Landroid/app/admin/DevicePolicyManager;->setActiveAdmin(Landroid/content/ComponentName;ZI)V
Landroid/app/admin/DevicePolicyManager;->setActiveAdmin(Landroid/content/ComponentName;Z)V
+Landroid/app/admin/IDevicePolicyManager$Stub;->TRANSACTION_packageHasActiveAdmins:I
+Landroid/app/admin/IDevicePolicyManager$Stub;->TRANSACTION_removeActiveAdmin:I
+Landroid/app/admin/SecurityLog$SecurityEvent;-><init>([B)V
Landroid/app/AlarmManager;->FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED:I
Landroid/app/AlarmManager;->FLAG_IDLE_UNTIL:I
Landroid/app/AlarmManager;->FLAG_STANDALONE:I
Landroid/app/AlarmManager;->FLAG_WAKE_FROM_IDLE:I
+Landroid/app/AlarmManager;->mService:Landroid/app/IAlarmManager;
Landroid/app/AlarmManager;->set(IJJJLandroid/app/AlarmManager$OnAlarmListener;Landroid/os/Handler;Landroid/os/WorkSource;)V
Landroid/app/AlarmManager;->set(IJJJLandroid/app/PendingIntent;Landroid/os/WorkSource;)V
Landroid/app/AlarmManager;->WINDOW_EXACT:J
@@ -85,26 +131,50 @@
Landroid/app/AppGlobals;->getInitialApplication()Landroid/app/Application;
Landroid/app/AppGlobals;->getPackageManager()Landroid/content/pm/IPackageManager;
Landroid/app/Application;->attach(Landroid/content/Context;)V
+Landroid/app/Application;->collectActivityLifecycleCallbacks()[Ljava/lang/Object;
+Landroid/app/Application;->dispatchActivityCreated(Landroid/app/Activity;Landroid/os/Bundle;)V
+Landroid/app/Application;->dispatchActivityDestroyed(Landroid/app/Activity;)V
+Landroid/app/Application;->dispatchActivityPaused(Landroid/app/Activity;)V
+Landroid/app/Application;->dispatchActivityResumed(Landroid/app/Activity;)V
+Landroid/app/Application;->dispatchActivitySaveInstanceState(Landroid/app/Activity;Landroid/os/Bundle;)V
+Landroid/app/Application;->dispatchActivityStarted(Landroid/app/Activity;)V
+Landroid/app/Application;->dispatchActivityStopped(Landroid/app/Activity;)V
Landroid/app/ApplicationLoaders;->getDefault()Landroid/app/ApplicationLoaders;
Landroid/app/ApplicationLoaders;->mLoaders:Landroid/util/ArrayMap;
Landroid/app/Application;->mComponentCallbacks:Ljava/util/ArrayList;
Landroid/app/Application;->mLoadedApk:Landroid/app/LoadedApk;
Landroid/app/ApplicationPackageManager;->deletePackage(Ljava/lang/String;Landroid/content/pm/IPackageDeleteObserver;I)V
+Landroid/app/ApplicationPackageManager;->getPackageSizeInfoAsUser(Ljava/lang/String;ILandroid/content/pm/IPackageStatsObserver;)V
+Landroid/app/ApplicationPackageManager;-><init>(Landroid/app/ContextImpl;Landroid/content/pm/IPackageManager;)V
Landroid/app/ApplicationPackageManager;->installExistingPackage(Ljava/lang/String;)I
Landroid/app/ApplicationPackageManager;->installExistingPackage(Ljava/lang/String;I)I
+Landroid/app/ApplicationPackageManager;->mPM:Landroid/content/pm/IPackageManager;
Landroid/app/AppOpsManager;->checkOp(IILjava/lang/String;)I
Landroid/app/AppOpsManager;->checkOpNoThrow(IILjava/lang/String;)I
+Landroid/app/AppOpsManager;->mService:Lcom/android/internal/app/IAppOpsService;
Landroid/app/AppOpsManager;->noteOp(I)I
Landroid/app/AppOpsManager;->noteOp(IILjava/lang/String;)I
+Landroid/app/AppOpsManager;->OP_COARSE_LOCATION:I
+Landroid/app/AppOpsManager;->OP_FINE_LOCATION:I
+Landroid/app/AppOpsManager;->OP_GET_USAGE_STATS:I
Landroid/app/AppOpsManager;->OP_POST_NOTIFICATION:I
+Landroid/app/AppOpsManager;->OP_READ_PHONE_STATE:I
+Landroid/app/AppOpsManager;->OP_READ_SMS:I
+Landroid/app/AppOpsManager;->OP_SYSTEM_ALERT_WINDOW:I
Landroid/app/AppOpsManager;->OP_WIFI_SCAN:I
Landroid/app/AppOpsManager;->OP_WRITE_SMS:I
+Landroid/app/AppOpsManager;->permissionToOpCode(Ljava/lang/String;)I
Landroid/app/AppOpsManager;->setMode(IILjava/lang/String;I)V
Landroid/app/AppOpsManager;->strOpToOp(Ljava/lang/String;)I
+Landroid/app/backup/BackupDataInput$EntityHeader;->dataSize:I
+Landroid/app/backup/BackupDataInput$EntityHeader;->key:Ljava/lang/String;
Landroid/app/backup/BackupDataInput;-><init>(Ljava/io/FileDescriptor;)V
Landroid/app/backup/BackupDataInputStream;->dataSize:I
Landroid/app/backup/BackupDataInputStream;->key:Ljava/lang/String;
Landroid/app/backup/BackupDataOutput;-><init>(Ljava/io/FileDescriptor;)V
+Landroid/app/backup/BackupDataOutput;->mBackupWriter:J
+Landroid/app/backup/BackupHelperDispatcher$Header;->chunkSize:I
+Landroid/app/backup/BackupHelperDispatcher$Header;->keyPrefix:Ljava/lang/String;
Landroid/app/backup/BackupManager;->backupNow()V
Landroid/app/backup/BackupManager;->beginRestoreSession()Landroid/app/backup/RestoreSession;
Landroid/app/backup/BackupManager;->cancelBackups()V
@@ -118,64 +188,135 @@
Landroid/app/backup/BackupManager;->selectBackupTransport(Ljava/lang/String;)Ljava/lang/String;
Landroid/app/backup/BackupManager;->setAutoRestore(Z)V
Landroid/app/backup/BackupManager;->setBackupEnabled(Z)V
+Landroid/app/backup/BackupManager;->updateTransportAttributes(Landroid/content/ComponentName;Ljava/lang/String;Landroid/content/Intent;Ljava/lang/String;Landroid/content/Intent;Ljava/lang/String;)V
Landroid/app/backup/BackupObserver;-><init>()V
Landroid/app/backup/BackupTransport;-><init>()V
Landroid/app/backup/FullBackup;->backupToTar(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/app/backup/FullBackupDataOutput;)I
+Landroid/app/backup/FullBackupDataOutput;->addSize(J)V
+Landroid/app/backup/FullBackupDataOutput;->mData:Landroid/app/backup/BackupDataOutput;
Landroid/app/backup/RestoreDescription;-><init>(Ljava/lang/String;I)V
Landroid/app/backup/RestoreSession;->endRestoreSession()V
Landroid/app/backup/RestoreSession;->getAvailableRestoreSets(Landroid/app/backup/RestoreObserver;)I
Landroid/app/backup/RestoreSession;->restoreAll(JLandroid/app/backup/RestoreObserver;)I
Landroid/app/backup/RestoreSet;-><init>(Ljava/lang/String;Ljava/lang/String;J)V
Landroid/app/backup/SelectBackupTransportCallback;-><init>()V
+Landroid/app/ContentProviderHolder;->provider:Landroid/content/IContentProvider;
Landroid/app/ContextImpl;->createActivityContext(Landroid/app/ActivityThread;Landroid/app/LoadedApk;Landroid/content/pm/ActivityInfo;Landroid/os/IBinder;ILandroid/content/res/Configuration;)Landroid/app/ContextImpl;
Landroid/app/ContextImpl;->getActivityToken()Landroid/os/IBinder;
+Landroid/app/ContextImpl;->getDisplay()Landroid/view/Display;
+Landroid/app/ContextImpl;->getPreferencesDir()Ljava/io/File;
+Landroid/app/ContextImpl;->mContentResolver:Landroid/app/ContextImpl$ApplicationContentResolver;
Landroid/app/ContextImpl;->mMainThread:Landroid/app/ActivityThread;
+Landroid/app/ContextImpl;->mOpPackageName:Ljava/lang/String;
+Landroid/app/ContextImpl;->mOuterContext:Landroid/content/Context;
Landroid/app/ContextImpl;->mPackageInfo:Landroid/app/LoadedApk;
+Landroid/app/ContextImpl;->mPackageManager:Landroid/content/pm/PackageManager;
+Landroid/app/ContextImpl;->mResources:Landroid/content/res/Resources;
+Landroid/app/ContextImpl;->mServiceCache:[Ljava/lang/Object;
+Landroid/app/ContextImpl;->mTheme:Landroid/content/res/Resources$Theme;
+Landroid/app/ContextImpl;->scheduleFinalCleanup(Ljava/lang/String;Ljava/lang/String;)V
Landroid/app/ContextImpl;->setOuterContext(Landroid/content/Context;)V
Landroid/app/DatePickerDialog;->mDatePicker:Landroid/widget/DatePicker;
Landroid/app/Dialog;->CANCEL:I
+Landroid/app/Dialog;->dismissDialog()V
Landroid/app/Dialog;->mCancelMessage:Landroid/os/Message;
Landroid/app/Dialog;->mDismissMessage:Landroid/os/Message;
Landroid/app/Dialog;->mListenersHandler:Landroid/os/Handler;
Landroid/app/Dialog;->mOwnerActivity:Landroid/app/Activity;
Landroid/app/Dialog;->mShowMessage:Landroid/os/Message;
Landroid/app/DownloadManager$Request;->mUri:Landroid/net/Uri;
+Landroid/app/FragmentManagerImpl;->mAdded:Ljava/util/ArrayList;
Landroid/app/Fragment;->mChildFragmentManager:Landroid/app/FragmentManagerImpl;
Landroid/app/IActivityManager;->forceStopPackage(Ljava/lang/String;I)V
Landroid/app/IActivityManager;->getLaunchedFromPackage(Landroid/os/IBinder;)Ljava/lang/String;
+Landroid/app/IActivityManager;->getTaskForActivity(Landroid/os/IBinder;Z)I
Landroid/app/IActivityManager;->resumeAppSwitches()V
+Landroid/app/IActivityManager;->setRequestedOrientation(Landroid/os/IBinder;I)V
+Landroid/app/IActivityManager$Stub$Proxy;->getConfiguration()Landroid/content/res/Configuration;
+Landroid/app/IActivityManager$Stub$Proxy;->getLaunchedFromUid(Landroid/os/IBinder;)I
+Landroid/app/IActivityManager$Stub$Proxy;->getProcessPss([I)[J
+Landroid/app/IActivityManager$Stub$Proxy;->isAppForeground(I)Z
+Landroid/app/IActivityManager$Stub$Proxy;->mRemote:Landroid/os/IBinder;
+Landroid/app/IAlarmManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
+Landroid/app/IAlarmManager$Stub;->TRANSACTION_remove:I
+Landroid/app/IAlarmManager$Stub;->TRANSACTION_set:I
Landroid/app/IApplicationThread;->scheduleTrimMemory(I)V
+Landroid/app/INotificationManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/INotificationManager;
+Landroid/app/INotificationManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/app/InstantAppResolverService;-><init>()V
Landroid/app/InstantAppResolverService$InstantAppResolutionCallback;->onInstantAppResolveInfo(Ljava/util/List;)V
+Landroid/app/Instrumentation;->execStartActivity(Landroid/content/Context;Landroid/os/IBinder;Landroid/os/IBinder;Landroid/app/Activity;Landroid/content/Intent;ILandroid/os/Bundle;)Landroid/app/Instrumentation$ActivityResult;
+Landroid/app/Instrumentation;->execStartActivity(Landroid/content/Context;Landroid/os/IBinder;Landroid/os/IBinder;Ljava/lang/String;Landroid/content/Intent;ILandroid/os/Bundle;)Landroid/app/Instrumentation$ActivityResult;
+Landroid/app/Instrumentation;->execStartActivity(Landroid/content/Context;Landroid/os/IBinder;Landroid/os/IBinder;Ljava/lang/String;Landroid/content/Intent;ILandroid/os/Bundle;Landroid/os/UserHandle;)Landroid/app/Instrumentation$ActivityResult;
Landroid/app/IntentService;->mServiceHandler:Landroid/app/IntentService$ServiceHandler;
+Landroid/app/ISearchManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/ISearchManager;
+Landroid/app/ISearchManager$Stub$Proxy;->getGlobalSearchActivity()Landroid/content/ComponentName;
+Landroid/app/ISearchManager$Stub$Proxy;->getWebSearchActivity()Landroid/content/ComponentName;
+Landroid/app/IUiModeManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/app/IWallpaperManager;->getWallpaper(Ljava/lang/String;Landroid/app/IWallpaperManagerCallback;ILandroid/os/Bundle;I)Landroid/os/ParcelFileDescriptor;
+Landroid/app/job/IJobScheduler$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/job/IJobScheduler;
+Landroid/app/job/IJobScheduler$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
+Landroid/app/LoadedApk;->mActivityThread:Landroid/app/ActivityThread;
+Landroid/app/LoadedApk;->makeApplication(ZLandroid/app/Instrumentation;)Landroid/app/Application;
+Landroid/app/LoadedApk;->mAppDir:Ljava/lang/String;
+Landroid/app/LoadedApk;->mApplicationInfo:Landroid/content/pm/ApplicationInfo;
Landroid/app/LoadedApk;->mApplication:Landroid/app/Application;
+Landroid/app/LoadedApk;->mBaseClassLoader:Ljava/lang/ClassLoader;
+Landroid/app/LoadedApk;->mClassLoader:Ljava/lang/ClassLoader;
+Landroid/app/LoadedApk;->mDataDir:Ljava/lang/String;
+Landroid/app/LoadedApk;->mPackageName:Ljava/lang/String;
Landroid/app/LoadedApk;->mReceivers:Landroid/util/ArrayMap;
Landroid/app/LoadedApk;->mResDir:Ljava/lang/String;
Landroid/app/LoadedApk;->mResources:Landroid/content/res/Resources;
+Landroid/app/LoadedApk;->mSplitResDirs:[Ljava/lang/String;
Landroid/app/LocalActivityManager;->mActivities:Ljava/util/Map;
Landroid/app/LocalActivityManager;->mActivityArray:Ljava/util/ArrayList;
+Landroid/app/NativeActivity;->hideIme(I)V
+Landroid/app/NativeActivity;->setWindowFlags(II)V
+Landroid/app/NativeActivity;->setWindowFormat(I)V
+Landroid/app/NativeActivity;->showIme(I)V
Landroid/app/Notification$Builder;->mActions:Ljava/util/ArrayList;
Landroid/app/Notification;->EXTRA_SUBSTITUTE_APP_NAME:Ljava/lang/String;
Landroid/app/Notification;->isGroupSummary()Z
Landroid/app/NotificationManager;->getService()Landroid/app/INotificationManager;
Landroid/app/NotificationManager;->notifyAsUser(Ljava/lang/String;ILandroid/app/Notification;Landroid/os/UserHandle;)V
+Landroid/app/NotificationManager;->sService:Landroid/app/INotificationManager;
+Landroid/app/Notification;->mLargeIcon:Landroid/graphics/drawable/Icon;
+Landroid/app/Notification;->mSmallIcon:Landroid/graphics/drawable/Icon;
Landroid/app/Notification;->setLatestEventInfo(Landroid/content/Context;Ljava/lang/CharSequence;Ljava/lang/CharSequence;Landroid/app/PendingIntent;)V
Landroid/app/PendingIntent;->getActivityAsUser(Landroid/content/Context;ILandroid/content/Intent;ILandroid/os/Bundle;Landroid/os/UserHandle;)Landroid/app/PendingIntent;
Landroid/app/PendingIntent;->getIntent()Landroid/content/Intent;
Landroid/app/PendingIntent;->isActivity()Z
Landroid/app/Presentation;->createPresentationContext(Landroid/content/Context;Landroid/view/Display;I)Landroid/content/Context;
Landroid/app/ProgressDialog;->mProgressNumber:Landroid/widget/TextView;
+Landroid/app/QueuedWork;->addFinisher(Ljava/lang/Runnable;)V
+Landroid/app/QueuedWork;->removeFinisher(Ljava/lang/Runnable;)V
+Landroid/app/ResourcesManager;->appendLibAssetForMainAssetPath(Ljava/lang/String;Ljava/lang/String;)V
+Landroid/app/ResourcesManager;->getInstance()Landroid/app/ResourcesManager;
+Landroid/app/ResourcesManager;->mActivityResourceReferences:Ljava/util/WeakHashMap;
+Landroid/app/ResourcesManager;->mResourceImpls:Landroid/util/ArrayMap;
+Landroid/app/ResourcesManager;->mResourceReferences:Ljava/util/ArrayList;
+Landroid/app/Service;->attach(Landroid/content/Context;Landroid/app/ActivityThread;Ljava/lang/String;Landroid/os/IBinder;Landroid/app/Application;Ljava/lang/Object;)V
+Landroid/app/Service;->mActivityManager:Landroid/app/IActivityManager;
+Landroid/app/Service;->mApplication:Landroid/app/Application;
+Landroid/app/Service;->mClassName:Ljava/lang/String;
+Landroid/app/Service;->mStartCompatibility:Z
+Landroid/app/Service;->mThread:Landroid/app/ActivityThread;
+Landroid/app/Service;->mToken:Landroid/os/IBinder;
Landroid/app/Service;->setForeground(Z)V
+Landroid/app/SharedPreferencesImpl;->mFile:Ljava/io/File;
Landroid/app/StatusBarManager;->collapsePanels()V
Landroid/app/StatusBarManager;->disable(I)V
Landroid/app/StatusBarManager;->expandNotificationsPanel()V
Landroid/app/StatusBarManager;->expandSettingsPanel(Ljava/lang/String;)V
Landroid/app/StatusBarManager;->expandSettingsPanel()V
Landroid/app/TimePickerDialog;->mTimePicker:Landroid/widget/TimePicker;
+Landroid/app/trust/ITrustManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/app/usage/UsageStatsManager;->getAppStandbyBuckets()Ljava/util/Map;
+Landroid/app/usage/UsageStatsManager;->mService:Landroid/app/usage/IUsageStatsManager;
Landroid/app/usage/UsageStatsManager;->setAppStandbyBuckets(Ljava/util/Map;)V
Landroid/app/usage/UsageStatsManager;->whitelistAppTemporarily(Ljava/lang/String;JLandroid/os/UserHandle;)V
+Landroid/app/usage/UsageStats;->mLastEvent:I
Landroid/app/WallpaperColors;->getColorHints()I
Landroid/app/WallpaperManager;->getBitmap()Landroid/graphics/Bitmap;
Landroid/app/WallpaperManager;->getBitmap(Z)Landroid/graphics/Bitmap;
@@ -194,6 +335,7 @@
Landroid/bluetooth/BluetoothAdapter;->getDiscoverableTimeout()I
Landroid/bluetooth/BluetoothAdapter;->isBleScanAlwaysAvailable()Z
Landroid/bluetooth/BluetoothAdapter;->isLeEnabled()Z
+Landroid/bluetooth/BluetoothAdapter;->mService:Landroid/bluetooth/IBluetooth;
Landroid/bluetooth/BluetoothAdapter;->setScanMode(II)Z
Landroid/bluetooth/BluetoothAdapter;->setScanMode(I)Z
Landroid/bluetooth/BluetoothDevice;->cancelBondProcess()Z
@@ -211,15 +353,29 @@
Landroid/bluetooth/BluetoothHeadset;->close()V
Landroid/bluetooth/BluetoothHeadset;->setPriority(Landroid/bluetooth/BluetoothDevice;I)Z
Landroid/bluetooth/BluetoothUuid;->RESERVED_UUIDS:[Landroid/os/ParcelUuid;
+Landroid/bluetooth/IBluetooth;->getAddress()Ljava/lang/String;
Landroid/bluetooth/IBluetooth$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetooth;
+Landroid/bluetooth/IBluetooth$Stub$Proxy;->getAddress()Ljava/lang/String;
Landroid/bluetooth/le/BluetoothLeScanner;->startScanFromSource(Ljava/util/List;Landroid/bluetooth/le/ScanSettings;Landroid/os/WorkSource;Landroid/bluetooth/le/ScanCallback;)V
Landroid/bluetooth/le/ScanSettings$Builder;->setScanResultType(I)Landroid/bluetooth/le/ScanSettings$Builder;
Landroid/content/AsyncTaskLoader;->mExecutor:Ljava/util/concurrent/Executor;
+Landroid/content/BroadcastReceiver$PendingResult;-><init>(ILjava/lang/String;Landroid/os/Bundle;IZZLandroid/os/IBinder;II)V
+Landroid/content/BroadcastReceiver;->setPendingResult(Landroid/content/BroadcastReceiver$PendingResult;)V
+Landroid/content/ContentProvider;->mContext:Landroid/content/Context;
+Landroid/content/ContentProvider;->mPathPermissions:[Landroid/content/pm/PathPermission;
+Landroid/content/ContentProvider;->mReadPermission:Ljava/lang/String;
+Landroid/content/ContentProvider;->mWritePermission:Ljava/lang/String;
Landroid/content/ContentProviderOperation;->mSelection:Ljava/lang/String;
Landroid/content/ContentProviderOperation;->mType:I
+Landroid/content/ContentProviderOperation;->TYPE_DELETE:I
+Landroid/content/ContentProviderOperation;->TYPE_INSERT:I
+Landroid/content/ContentProviderOperation;->TYPE_UPDATE:I
+Landroid/content/ContentResolver;->acquireProvider(Landroid/net/Uri;)Landroid/content/IContentProvider;
Landroid/content/ContentResolver;->getContentService()Landroid/content/IContentService;
Landroid/content/ContentResolver;->getSyncStatus(Landroid/accounts/Account;Ljava/lang/String;)Landroid/content/SyncStatusInfo;
Landroid/content/ContentResolver;->mContext:Landroid/content/Context;
+Landroid/content/ContentResolver;->mPackageName:Ljava/lang/String;
+Landroid/content/ContentValues;-><init>(Ljava/util/HashMap;)V
Landroid/content/ContentValues;->mValues:Ljava/util/HashMap;
Landroid/content/Context;->bindServiceAsUser(Landroid/content/Intent;Landroid/content/ServiceConnection;ILandroid/os/UserHandle;)Z
Landroid/content/Context;->createCredentialProtectedStorageContext()Landroid/content/Context;
@@ -227,40 +383,59 @@
Landroid/content/Context;->getSharedPrefsFile(Ljava/lang/String;)Ljava/io/File;
Landroid/content/Context;->getThemeResId()I
Landroid/content/Context;->isCredentialProtectedStorage()Z
+Landroid/content/Context;->PERSISTENT_DATA_BLOCK_SERVICE:Ljava/lang/String;
Landroid/content/Context;->sendBroadcastAsUser(Landroid/content/Intent;Landroid/os/UserHandle;Ljava/lang/String;I)V
Landroid/content/Context;->sendBroadcastAsUser(Landroid/content/Intent;Landroid/os/UserHandle;Ljava/lang/String;Landroid/os/Bundle;)V
Landroid/content/Context;->sendOrderedBroadcastAsUser(Landroid/content/Intent;Landroid/os/UserHandle;Ljava/lang/String;ILandroid/content/BroadcastReceiver;Landroid/os/Handler;ILjava/lang/String;Landroid/os/Bundle;)V
Landroid/content/Context;->sendOrderedBroadcastAsUser(Landroid/content/Intent;Landroid/os/UserHandle;Ljava/lang/String;ILandroid/os/Bundle;Landroid/content/BroadcastReceiver;Landroid/os/Handler;ILjava/lang/String;Landroid/os/Bundle;)V
Landroid/content/ContextWrapper;->createCredentialProtectedStorageContext()Landroid/content/Context;
+Landroid/content/ContextWrapper;->getDisplay()Landroid/view/Display;
Landroid/content/ContextWrapper;->mBase:Landroid/content/Context;
Landroid/content/CursorLoader;->mCancellationSignal:Landroid/os/CancellationSignal;
Landroid/content/CursorLoader;->mObserver:Landroid/content/Loader$ForceLoadContentObserver;
+Landroid/content/IClipboard$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/IClipboard;
Landroid/content/IContentService;->cancelSync(Landroid/accounts/Account;Ljava/lang/String;Landroid/content/ComponentName;)V
Landroid/content/IContentService;->getMasterSyncAutomatically()Z
Landroid/content/IContentService;->setMasterSyncAutomatically(Z)V
+Landroid/content/IContentService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/content/Intent;->ACTION_ALARM_CHANGED:Ljava/lang/String;
+Landroid/content/IntentFilter;->mActions:Ljava/util/ArrayList;
Landroid/content/IntentFilter;->setOrder(I)V
Landroid/content/Intent;->putExtra(Ljava/lang/String;Landroid/os/IBinder;)Landroid/content/Intent;
+Landroid/content/pm/ApplicationInfo;->enabledSetting:I
+Landroid/content/pm/ApplicationInfo;->getBaseResourcePath()Ljava/lang/String;
Landroid/content/pm/ApplicationInfo;->installLocation:I
Landroid/content/pm/ApplicationInfo;->isForwardLocked()Z
Landroid/content/pm/ApplicationInfo;->isInstantApp()Z
Landroid/content/pm/ApplicationInfo;->isPrivilegedApp()Z
Landroid/content/pm/ApplicationInfo;->primaryCpuAbi:Ljava/lang/String;
Landroid/content/pm/ApplicationInfo;->privateFlags:I
+Landroid/content/pm/ApplicationInfo;->scanPublicSourceDir:Ljava/lang/String;
+Landroid/content/pm/ApplicationInfo;->scanSourceDir:Ljava/lang/String;
+Landroid/content/pm/ApplicationInfo;->secondaryNativeLibraryDir:Ljava/lang/String;
Landroid/content/pm/ApplicationInfo;->targetSandboxVersion:I
Landroid/content/pm/InstantAppIntentFilter;-><init>(Ljava/lang/String;Ljava/util/List;)V
Landroid/content/pm/InstantAppResolveInfo;->getPackageName()Ljava/lang/String;
Landroid/content/pm/InstantAppResolveInfo;-><init>(Landroid/content/pm/InstantAppResolveInfo$InstantAppDigest;Ljava/lang/String;Ljava/util/List;I)V
Landroid/content/pm/InstantAppResolveInfo$InstantAppDigest;->getDigestPrefix()[I
Landroid/content/pm/InstantAppResolveInfo$InstantAppDigest;-><init>(Ljava/lang/String;)V
+Landroid/content/pm/IPackageManager;->getInstallLocation()I
Landroid/content/pm/IPackageManager;->getLastChosenActivity(Landroid/content/Intent;Ljava/lang/String;I)Landroid/content/pm/ResolveInfo;
+Landroid/content/pm/IPackageManager;->setApplicationEnabledSetting(Ljava/lang/String;IIILjava/lang/String;)V
+Landroid/content/pm/IPackageManager;->setComponentEnabledSetting(Landroid/content/ComponentName;III)V
Landroid/content/pm/IPackageManager;->setLastChosenActivity(Landroid/content/Intent;Ljava/lang/String;ILandroid/content/IntentFilter;ILandroid/content/ComponentName;)V
+Landroid/content/pm/IPackageManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/pm/IPackageManager;
+Landroid/content/pm/IPackageManager$Stub$Proxy;->getPackageInfo(Ljava/lang/String;II)Landroid/content/pm/PackageInfo;
+Landroid/content/pm/IPackageManager$Stub$Proxy;->getPackagesForUid(I)[Ljava/lang/String;
+Landroid/content/pm/IPackageManager$Stub$Proxy;->getSystemSharedLibraryNames()[Ljava/lang/String;
Landroid/content/pm/IPackageStatsObserver$Stub;-><init>()V
Landroid/content/pm/LauncherApps;->mPm:Landroid/content/pm/PackageManager;
Landroid/content/pm/LauncherApps;->startShortcut(Ljava/lang/String;Ljava/lang/String;Landroid/graphics/Rect;Landroid/os/Bundle;I)V
+Landroid/content/pm/PackageInstaller$SessionParams;->setAllocateAggressive(Z)V
Landroid/content/pm/PackageInstaller$SessionParams;->setGrantedRuntimePermissions([Ljava/lang/String;)V
Landroid/content/pm/PackageInstaller$SessionParams;->setInstallAsInstantApp(Z)V
Landroid/content/pm/PackageManager;->addOnPermissionsChangeListener(Landroid/content/pm/PackageManager$OnPermissionsChangedListener;)V
+Landroid/content/pm/PackageManager;->buildRequestPermissionsIntent([Ljava/lang/String;)Landroid/content/Intent;
Landroid/content/pm/PackageManager;->freeStorageAndNotify(JLandroid/content/pm/IPackageDataObserver;)V
Landroid/content/pm/PackageManager;->freeStorageAndNotify(Ljava/lang/String;JLandroid/content/pm/IPackageDataObserver;)V
Landroid/content/pm/PackageManager;->freeStorage(JLandroid/content/IntentSender;)V
@@ -271,29 +446,70 @@
Landroid/content/pm/PackageManager;->getPackageSizeInfo(Ljava/lang/String;Landroid/content/pm/IPackageStatsObserver;)V
Landroid/content/pm/PackageManager;->getResourcesForApplicationAsUser(Ljava/lang/String;I)Landroid/content/res/Resources;
Landroid/content/pm/PackageManager;->movePackage(Ljava/lang/String;Landroid/os/storage/VolumeInfo;)I
+Landroid/content/pm/PackageManager;->NO_NATIVE_LIBRARIES:I
Landroid/content/pm/PackageManager;->queryBroadcastReceivers(Landroid/content/Intent;II)Ljava/util/List;
Landroid/content/pm/PackageManager;->removeOnPermissionsChangeListener(Landroid/content/pm/PackageManager$OnPermissionsChangedListener;)V
Landroid/content/pm/PackageManager;->verifyIntentFilter(IILjava/util/List;)V
+Landroid/content/pm/PackageParser$Activity;->info:Landroid/content/pm/ActivityInfo;
+Landroid/content/pm/PackageParser$ActivityIntentInfo;->activity:Landroid/content/pm/PackageParser$Activity;
Landroid/content/pm/PackageParser;->collectCertificates(Landroid/content/pm/PackageParser$Package;Ljava/io/File;Z)V
Landroid/content/pm/PackageParser;->collectCertificates(Landroid/content/pm/PackageParser$Package;Z)V
+Landroid/content/pm/PackageParser$Component;->className:Ljava/lang/String;
+Landroid/content/pm/PackageParser$Component;->getComponentName()Landroid/content/ComponentName;
+Landroid/content/pm/PackageParser$Component;->intents:Ljava/util/ArrayList;
Landroid/content/pm/PackageParser;->generatePackageInfo(Landroid/content/pm/PackageParser$Package;[IIJJLjava/util/Set;Landroid/content/pm/PackageUserState;I)Landroid/content/pm/PackageInfo;
Landroid/content/pm/PackageParser;->generatePackageInfo(Landroid/content/pm/PackageParser$Package;[IIJJLjava/util/Set;Landroid/content/pm/PackageUserState;)Landroid/content/pm/PackageInfo;
+Landroid/content/pm/PackageParser;-><init>()V
+Landroid/content/pm/PackageParser$Package;->activities:Ljava/util/ArrayList;
+Landroid/content/pm/PackageParser$Package;->applicationInfo:Landroid/content/pm/ApplicationInfo;
+Landroid/content/pm/PackageParser$Package;->mVersionCode:I
+Landroid/content/pm/PackageParser$Package;->mVersionName:Ljava/lang/String;
+Landroid/content/pm/PackageParser$Package;->packageName:Ljava/lang/String;
+Landroid/content/pm/PackageParser$Package;->providers:Ljava/util/ArrayList;
+Landroid/content/pm/PackageParser$Package;->receivers:Ljava/util/ArrayList;
+Landroid/content/pm/PackageParser$Package;->requestedPermissions:Ljava/util/ArrayList;
+Landroid/content/pm/PackageParser$Package;->services:Ljava/util/ArrayList;
+Landroid/content/pm/PackageParser;->parseBaseApk(Ljava/lang/String;Landroid/content/res/Resources;Landroid/content/res/XmlResourceParser;I[Ljava/lang/String;)Landroid/content/pm/PackageParser$Package;
Landroid/content/pm/PackageParser;->parseMonolithicPackage(Ljava/io/File;I)Landroid/content/pm/PackageParser$Package;
Landroid/content/pm/PackageParser;->parsePackage(Ljava/io/File;I)Landroid/content/pm/PackageParser$Package;
Landroid/content/pm/PackageParser;->parsePackage(Ljava/io/File;IZ)Landroid/content/pm/PackageParser$Package;
+Landroid/content/pm/PackageParser$Provider;->info:Landroid/content/pm/ProviderInfo;
+Landroid/content/pm/PackageParser$ProviderIntentInfo;->provider:Landroid/content/pm/PackageParser$Provider;
+Landroid/content/pm/PackageParser$ServiceIntentInfo;->service:Landroid/content/pm/PackageParser$Service;
+Landroid/content/pm/PackageUserState;-><init>()V
+Landroid/content/pm/ParceledListSlice;-><init>(Ljava/util/List;)V
+Landroid/content/pm/ResolveInfo;->instantAppAvailable:Z
+Landroid/content/pm/Signature;->getPublicKey()Ljava/security/PublicKey;
Landroid/content/pm/UserInfo;->id:I
Landroid/content/pm/UserInfo;->isPrimary()Z
+Landroid/content/pm/UserInfo;->serialNumber:I
+Landroid/content/res/AssetFileDescriptor;->mFd:Landroid/os/ParcelFileDescriptor;
+Landroid/content/res/AssetFileDescriptor;->mLength:J
+Landroid/content/res/AssetFileDescriptor;->mStartOffset:J
+Landroid/content/res/AssetManager;->addAssetPathAsSharedLibrary(Ljava/lang/String;)I
Landroid/content/res/AssetManager;->addAssetPath(Ljava/lang/String;)I
+Landroid/content/res/AssetManager;->addAssetPathNative(Ljava/lang/String;Z)I
Landroid/content/res/AssetManager;->addAssetPaths([Ljava/lang/String;)[I
Landroid/content/res/AssetManager;->applyStyle(JIIJ[IIJJ)V
+Landroid/content/res/AssetManager;->ensureStringBlocks()[Landroid/content/res/StringBlock;
Landroid/content/res/AssetManager;->getArraySize(I)I
Landroid/content/res/AssetManager;->getAssignedPackageIdentifiers()Landroid/util/SparseArray;
Landroid/content/res/AssetManager;->getCookieName(I)Ljava/lang/String;
+Landroid/content/res/AssetManager;->getNativeStringBlock(I)J
Landroid/content/res/AssetManager;->getResourceBagText(II)Ljava/lang/CharSequence;
+Landroid/content/res/AssetManager;->getResourceEntryName(I)Ljava/lang/String;
+Landroid/content/res/AssetManager;->getResourceIdentifier(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I
+Landroid/content/res/AssetManager;->getResourceName(I)Ljava/lang/String;
+Landroid/content/res/AssetManager;->getResourcePackageName(I)Ljava/lang/String;
+Landroid/content/res/AssetManager;->getResourceTypeName(I)Ljava/lang/String;
+Landroid/content/res/AssetManager;->getStringBlockCount()I
+Landroid/content/res/AssetManager;-><init>()V
+Landroid/content/res/AssetManager;->isUpToDate()Z
Landroid/content/res/AssetManager;->loadResourceBagValue(IILandroid/util/TypedValue;Z)I
Landroid/content/res/AssetManager;->loadResourceValue(ISLandroid/util/TypedValue;Z)I
Landroid/content/res/AssetManager;->loadThemeAttributeValue(JILandroid/util/TypedValue;Z)I
Landroid/content/res/AssetManager;->mObject:J
+Landroid/content/res/AssetManager;->mStringBlocks:[Landroid/content/res/StringBlock;
Landroid/content/res/AssetManager;->openNonAssetFdNative(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;
Landroid/content/res/AssetManager;->openNonAsset(ILjava/lang/String;I)Ljava/io/InputStream;
Landroid/content/res/AssetManager;->openNonAsset(ILjava/lang/String;)Ljava/io/InputStream;
@@ -304,9 +520,16 @@
Landroid/content/res/AssetManager;->resolveAttrs(JII[I[I[I[I)Z
Landroid/content/res/AssetManager;->retrieveArray(I[I)I
Landroid/content/res/AssetManager;->retrieveAttributes(J[I[I[I)Z
+Landroid/content/res/AssetManager;->setConfiguration(IILjava/lang/String;IIIIIIIIIIIIIII)V
Landroid/content/res/AssetManager;->STYLE_NUM_ENTRIES:I
Landroid/content/res/AssetManager;->STYLE_RESOURCE_ID:I
+Landroid/content/res/ColorStateList$ColorStateListFactory;-><init>(Landroid/content/res/ColorStateList;)V
+Landroid/content/res/ColorStateList;->mColors:[I
+Landroid/content/res/ColorStateList;->mDefaultColor:I
+Landroid/content/res/ColorStateList;->mFactory:Landroid/content/res/ColorStateList$ColorStateListFactory;
+Landroid/content/res/CompatibilityInfo;->DEFAULT_COMPATIBILITY_INFO:Landroid/content/res/CompatibilityInfo;
Landroid/content/res/DrawableCache;->getInstance(JLandroid/content/res/Resources;Landroid/content/res/Resources$Theme;)Landroid/graphics/drawable/Drawable;
+Landroid/content/res/ObbInfo;->salt:[B
Landroid/content/res/Resources;->getCompatibilityInfo()Landroid/content/res/CompatibilityInfo;
Landroid/content/res/ResourcesImpl;->mAccessLock:Ljava/lang/Object;
Landroid/content/res/ResourcesImpl;->mAssets:Landroid/content/res/AssetManager;
@@ -315,15 +538,20 @@
Landroid/content/res/ResourcesImpl;->mDrawableCache:Landroid/content/res/DrawableCache;
Landroid/content/res/ResourcesImpl;->mPreloading:Z
Landroid/content/res/ResourcesImpl;->sPreloadedColorDrawables:Landroid/util/LongSparseArray;
+Landroid/content/res/ResourcesImpl;->sPreloadedComplexColors:Landroid/util/LongSparseArray;
Landroid/content/res/ResourcesImpl;->sPreloadedDrawables:[Landroid/util/LongSparseArray;
Landroid/content/res/ResourcesImpl;->TRACE_FOR_MISS_PRELOAD:Z
Landroid/content/res/ResourcesImpl;->TRACE_FOR_PRELOAD:Z
+Landroid/content/res/ResourcesKey;->mSplitResDirs:[Ljava/lang/String;
Landroid/content/res/Resources;->loadXmlResourceParser(ILjava/lang/String;)Landroid/content/res/XmlResourceParser;
Landroid/content/res/Resources;->loadXmlResourceParser(Ljava/lang/String;IILjava/lang/String;)Landroid/content/res/XmlResourceParser;
Landroid/content/res/Resources;->mResourcesImpl:Landroid/content/res/ResourcesImpl;
Landroid/content/res/Resources;->mTmpValue:Landroid/util/TypedValue;
Landroid/content/res/Resources;->mTypedArrayPool:Landroid/util/Pools$SynchronizedPool;
Landroid/content/res/Resources;->setCompatibilityInfo(Landroid/content/res/CompatibilityInfo;)V
+Landroid/content/res/Resources;->updateSystemConfiguration(Landroid/content/res/Configuration;Landroid/util/DisplayMetrics;Landroid/content/res/CompatibilityInfo;)V
+Landroid/content/res/StringBlock;-><init>(JZ)V
+Landroid/content/res/TypedArray;->getNonConfigurationString(II)Ljava/lang/String;
Landroid/content/res/TypedArray;->getValueAt(ILandroid/util/TypedValue;)Z
Landroid/content/res/TypedArray;->mAssets:Landroid/content/res/AssetManager;
Landroid/content/res/TypedArray;->mData:[I
@@ -336,18 +564,48 @@
Landroid/content/res/TypedArray;->mValue:Landroid/util/TypedValue;
Landroid/content/res/TypedArray;->mXml:Landroid/content/res/XmlBlock$Parser;
Landroid/content/res/XmlBlock;->close()V
+Landroid/content/res/XmlBlock;-><init>([B)V
Landroid/content/res/XmlBlock;->newParser()Landroid/content/res/XmlResourceParser;
Landroid/content/res/XmlBlock$Parser;->mParseState:J
Landroid/content/SyncStatusInfo;->lastSuccessTime:J
+Landroid/database/AbstractCursor;->mExtras:Landroid/os/Bundle;
Landroid/database/AbstractCursor;->mNotifyUri:Landroid/net/Uri;
Landroid/database/CursorWindow;->mWindowPtr:J
Landroid/database/CursorWindow;->sCursorWindowSize:I
Landroid/database/CursorWindow;->sWindowToPidMap:Landroid/util/LongSparseArray;
Landroid/database/CursorWrapper;->mCursor:Landroid/database/Cursor;
+Landroid/database/sqlite/SQLiteCustomFunction;->dispatchCallback([Ljava/lang/String;)V
+Landroid/database/sqlite/SQLiteCustomFunction;->name:Ljava/lang/String;
+Landroid/database/sqlite/SQLiteCustomFunction;->numArgs:I
+Landroid/database/sqlite/SQLiteDatabaseConfiguration;->maxSqlCacheSize:I
+Landroid/database/sqlite/SQLiteDatabase;->mConfigurationLocked:Landroid/database/sqlite/SQLiteDatabaseConfiguration;
+Landroid/database/sqlite/SQLiteDatabase;->mConnectionPoolLocked:Landroid/database/sqlite/SQLiteConnectionPool;
+Landroid/database/sqlite/SQLiteDebug$PagerStats;->largestMemAlloc:I
+Landroid/database/sqlite/SQLiteDebug$PagerStats;->memoryUsed:I
+Landroid/database/sqlite/SQLiteDebug$PagerStats;->pageCacheOverflow:I
+Landroid/database/sqlite/SQLiteOpenHelper;->mName:Ljava/lang/String;
+Landroid/ddm/DdmHandleAppName;->getAppName()Ljava/lang/String;
+Landroid/graphics/BaseCanvas;->mNativeCanvasWrapper:J
Landroid/graphics/Bitmap$Config;->nativeInt:I
+Landroid/graphics/Bitmap$Config;->nativeToConfig(I)Landroid/graphics/Bitmap$Config;
Landroid/graphics/Bitmap;->createAshmemBitmap()Landroid/graphics/Bitmap;
Landroid/graphics/Bitmap;->createAshmemBitmap(Landroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;
+Landroid/graphics/BitmapFactory;->nativeDecodeAsset(JLandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;
+Landroid/graphics/BitmapFactory;->nativeDecodeByteArray([BIILandroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;
+Landroid/graphics/BitmapFactory;->nativeDecodeFileDescriptor(Ljava/io/FileDescriptor;Landroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;
+Landroid/graphics/BitmapFactory;->nativeDecodeStream(Ljava/io/InputStream;[BLandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;
Landroid/graphics/Bitmap;->getDefaultDensity()I
+Landroid/graphics/Bitmap;-><init>(JIIIZZ[BLandroid/graphics/NinePatch$InsetStruct;)V
+Landroid/graphics/Bitmap;->mNativePtr:J
+Landroid/graphics/Bitmap;->mNinePatchChunk:[B
+Landroid/graphics/Bitmap;->mNinePatchInsets:Landroid/graphics/NinePatch$InsetStruct;
+Landroid/graphics/BitmapRegionDecoder;-><init>(J)V
+Landroid/graphics/Bitmap;->reinit(IIZ)V
+Landroid/graphics/Camera;->native_instance:J
+Landroid/graphics/Canvas;-><init>(J)V
+Landroid/graphics/Canvas;->release()V
+Landroid/graphics/drawable/AnimatedImageDrawable;->onAnimationEnd()V
+Landroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimatorRT;->callOnFinished(Landroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimatorRT;I)V
Landroid/graphics/drawable/AnimationDrawable;->mCurFrame:I
Landroid/graphics/drawable/BitmapDrawable;->getTint()Landroid/content/res/ColorStateList;
Landroid/graphics/drawable/BitmapDrawable;->getTintMode()Landroid/graphics/PorterDuff$Mode;
@@ -357,6 +615,11 @@
Landroid/graphics/drawable/DrawableContainer;->mDrawableContainerState:Landroid/graphics/drawable/DrawableContainer$DrawableContainerState;
Landroid/graphics/drawable/Drawable;->inflateWithAttributes(Landroid/content/res/Resources;Lorg/xmlpull/v1/XmlPullParser;Landroid/content/res/TypedArray;I)V
Landroid/graphics/drawable/Drawable;->mCallback:Ljava/lang/ref/WeakReference;
+Landroid/graphics/drawable/GradientDrawable$GradientState;->mAngle:I
+Landroid/graphics/drawable/GradientDrawable$GradientState;->mPadding:Landroid/graphics/Rect;
+Landroid/graphics/drawable/GradientDrawable$GradientState;->mPositions:[F
+Landroid/graphics/drawable/GradientDrawable;->mPadding:Landroid/graphics/Rect;
+Landroid/graphics/drawable/Icon;->getResPackage()Ljava/lang/String;
Landroid/graphics/drawable/NinePatchDrawable;->mNinePatchState:Landroid/graphics/drawable/NinePatchDrawable$NinePatchState;
Landroid/graphics/drawable/NinePatchDrawable$NinePatchState;->mNinePatch:Landroid/graphics/NinePatch;
Landroid/graphics/drawable/StateListDrawable;->extractStateSet(Landroid/util/AttributeSet;)[I
@@ -370,18 +633,45 @@
Landroid/graphics/FontFamily;->addFontFromBuffer(Ljava/nio/ByteBuffer;I[Landroid/graphics/fonts/FontVariationAxis;II)Z
Landroid/graphics/FontFamily;->freeze()Z
Landroid/graphics/FontFamily;-><init>()V
+Landroid/graphics/fonts/FontVariationAxis;->mStyleValue:F
+Landroid/graphics/fonts/FontVariationAxis;->mTag:I
+Landroid/graphics/GraphicBuffer;->createFromExisting(IIIIJ)Landroid/graphics/GraphicBuffer;
+Landroid/graphics/GraphicBuffer;-><init>(IIIIJ)V
+Landroid/graphics/GraphicBuffer;->mNativeObject:J
+Landroid/graphics/ImageDecoder;-><init>(JIIZ)V
+Landroid/graphics/ImageDecoder;->onPartialImage(I)Z
+Landroid/graphics/ImageDecoder;->postProcessAndRelease(Landroid/graphics/Canvas;)I
Landroid/graphics/LinearGradient;->mColors:[I
+Landroid/graphics/Matrix;->native_instance:J
+Landroid/graphics/Movie;-><init>(J)V
+Landroid/graphics/Movie;->mNativeMovie:J
+Landroid/graphics/NinePatch$InsetStruct;-><init>(IIIIIIIIFIF)V
Landroid/graphics/NinePatch;->mBitmap:Landroid/graphics/Bitmap;
+Landroid/graphics/Picture;->mNativePicture:J
+Landroid/graphics/Region;-><init>(JI)V
+Landroid/graphics/Region;->mNativeRegion:J
+Landroid/graphics/SurfaceTexture;->mFrameAvailableListener:J
+Landroid/graphics/SurfaceTexture;->mProducer:J
+Landroid/graphics/SurfaceTexture;->mSurfaceTexture:J
Landroid/graphics/SurfaceTexture;->nativeDetachFromGLContext()I
+Landroid/graphics/SurfaceTexture;->postEventFromNative(Ljava/lang/ref/WeakReference;)V
Landroid/graphics/Typeface;->mStyle:I
Landroid/graphics/Typeface;->sDefaults:[Landroid/graphics/Typeface;
Landroid/graphics/Typeface;->setDefault(Landroid/graphics/Typeface;)V
Landroid/graphics/Typeface;->sSystemFontMap:Ljava/util/Map;
+Landroid/hardware/camera2/CameraCharacteristics$Key;-><init>(Ljava/lang/String;Ljava/lang/Class;J)V
+Landroid/hardware/camera2/CaptureRequest$Key;-><init>(Ljava/lang/String;Ljava/lang/Class;J)V
+Landroid/hardware/camera2/CaptureResult$Key;-><init>(Ljava/lang/String;Ljava/lang/Class;J)V
+Landroid/hardware/camera2/impl/CameraMetadataNative;->mMetadataPtr:J
Landroid/hardware/Camera;->addCallbackBuffer([BI)V
+Landroid/hardware/Camera;->mNativeContext:J
Landroid/hardware/Camera;->openLegacy(II)Landroid/hardware/Camera;
+Landroid/hardware/Camera;->postEventFromNative(Ljava/lang/Object;IIILjava/lang/Object;)V
Landroid/hardware/display/DisplayManager;->getStableDisplaySize()Landroid/graphics/Point;
Landroid/hardware/display/WifiDisplayStatus;->mActiveDisplay:Landroid/hardware/display/WifiDisplay;
Landroid/hardware/display/WifiDisplayStatus;->mDisplays:[Landroid/hardware/display/WifiDisplay;
+Landroid/hardware/HardwareBuffer;-><init>(J)V
+Landroid/hardware/HardwareBuffer;->mNativeObject:J
Landroid/hardware/input/IInputManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/hardware/input/IInputManager;
Landroid/hardware/input/InputManager;->getInstance()Landroid/hardware/input/InputManager;
Landroid/hardware/input/InputManager;->mIm:Landroid/hardware/input/IInputManager;
@@ -422,19 +712,113 @@
Landroid/hardware/location/NanoAppInstanceInfo;->getAppVersion()I
Landroid/hardware/location/NanoAppInstanceInfo;->getHandle()I
Landroid/hardware/location/NanoAppInstanceInfo;->getName()Ljava/lang/String;
+Landroid/hardware/SerialPort;->mNativeContext:I
+Landroid/hardware/soundtrigger/SoundTrigger$ConfidenceLevel;->confidenceLevel:I
+Landroid/hardware/soundtrigger/SoundTrigger$ConfidenceLevel;-><init>(II)V
+Landroid/hardware/soundtrigger/SoundTrigger$ConfidenceLevel;->userId:I
+Landroid/hardware/soundtrigger/SoundTrigger$GenericRecognitionEvent;-><init>(IIZIIIZLandroid/media/AudioFormat;[B)V
+Landroid/hardware/soundtrigger/SoundTrigger$Keyphrase;->id:I
+Landroid/hardware/soundtrigger/SoundTrigger$Keyphrase;->locale:Ljava/lang/String;
+Landroid/hardware/soundtrigger/SoundTrigger$KeyphraseRecognitionEvent;-><init>(IIZIIIZLandroid/media/AudioFormat;[B[Landroid/hardware/soundtrigger/SoundTrigger$KeyphraseRecognitionExtra;)V
+Landroid/hardware/soundtrigger/SoundTrigger$KeyphraseRecognitionExtra;->coarseConfidenceLevel:I
+Landroid/hardware/soundtrigger/SoundTrigger$KeyphraseRecognitionExtra;->confidenceLevels:[Landroid/hardware/soundtrigger/SoundTrigger$ConfidenceLevel;
+Landroid/hardware/soundtrigger/SoundTrigger$KeyphraseRecognitionExtra;->id:I
+Landroid/hardware/soundtrigger/SoundTrigger$KeyphraseRecognitionExtra;-><init>(III[Landroid/hardware/soundtrigger/SoundTrigger$ConfidenceLevel;)V
+Landroid/hardware/soundtrigger/SoundTrigger$KeyphraseRecognitionExtra;->recognitionModes:I
+Landroid/hardware/soundtrigger/SoundTrigger$Keyphrase;->recognitionModes:I
+Landroid/hardware/soundtrigger/SoundTrigger$KeyphraseSoundModel;->keyphrases:[Landroid/hardware/soundtrigger/SoundTrigger$Keyphrase;
+Landroid/hardware/soundtrigger/SoundTrigger$Keyphrase;->text:Ljava/lang/String;
+Landroid/hardware/soundtrigger/SoundTrigger$Keyphrase;->users:[I
+Landroid/hardware/soundtrigger/SoundTriggerModule;->mId:I
+Landroid/hardware/soundtrigger/SoundTriggerModule;->mNativeContext:J
+Landroid/hardware/soundtrigger/SoundTriggerModule;->postEventFromNative(Ljava/lang/Object;IIILjava/lang/Object;)V
+Landroid/hardware/soundtrigger/SoundTrigger$ModuleProperties;-><init>(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;IIIIIZIZIZ)V
+Landroid/hardware/soundtrigger/SoundTrigger$RecognitionConfig;->captureRequested:Z
+Landroid/hardware/soundtrigger/SoundTrigger$RecognitionConfig;->data:[B
+Landroid/hardware/soundtrigger/SoundTrigger$RecognitionConfig;->keyphrases:[Landroid/hardware/soundtrigger/SoundTrigger$KeyphraseRecognitionExtra;
+Landroid/hardware/soundtrigger/SoundTrigger$RecognitionEvent;-><init>(IIZIIIZLandroid/media/AudioFormat;[B)V
+Landroid/hardware/soundtrigger/SoundTrigger$SoundModel;->data:[B
+Landroid/hardware/soundtrigger/SoundTrigger$SoundModelEvent;-><init>(II[B)V
+Landroid/hardware/soundtrigger/SoundTrigger$SoundModel;->uuid:Ljava/util/UUID;
+Landroid/hardware/soundtrigger/SoundTrigger$SoundModel;->vendorUuid:Ljava/util/UUID;
+Landroid/hardware/SystemSensorManager$BaseEventQueue;->dispatchAdditionalInfoEvent(III[F[I)V
+Landroid/hardware/SystemSensorManager$BaseEventQueue;->dispatchFlushCompleteEvent(I)V
+Landroid/hardware/SystemSensorManager$BaseEventQueue;->dispatchSensorEvent(I[FIJ)V
+Landroid/hardware/usb/UsbDeviceConnection;->mNativeContext:J
Landroid/hardware/usb/UsbManager;->setCurrentFunction(Ljava/lang/String;Z)V
+Landroid/hardware/usb/UsbRequest;->mNativeContext:J
+Landroid/icu/impl/number/DecimalFormatProperties;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/impl/number/DecimalFormatProperties;->writeObject(Ljava/io/ObjectOutputStream;)V
+Landroid/icu/impl/TimeZoneGenericNames;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/DateFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/DateFormatSymbols;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/DateIntervalFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/DecimalFormat_ICU58_Android;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/DecimalFormat_ICU58_Android;->writeObject(Ljava/io/ObjectOutputStream;)V
+Landroid/icu/text/DecimalFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/DecimalFormatSymbols;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/DecimalFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
+Landroid/icu/text/MessageFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/MessageFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
+Landroid/icu/text/NumberFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/NumberFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
+Landroid/icu/text/PluralFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/PluralRules$FixedDecimal;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/PluralRules$FixedDecimal;->writeObject(Ljava/io/ObjectOutputStream;)V
+Landroid/icu/text/PluralRules;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/PluralRules;->writeObject(Ljava/io/ObjectOutputStream;)V
+Landroid/icu/text/RuleBasedNumberFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/RuleBasedNumberFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
+Landroid/icu/text/SelectFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/SimpleDateFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/SimpleDateFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
+Landroid/icu/text/TimeZoneFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/text/TimeZoneFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
+Landroid/icu/util/Calendar;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/util/Calendar;->writeObject(Ljava/io/ObjectOutputStream;)V
+Landroid/icu/util/ChineseCalendar;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/util/IslamicCalendar;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/icu/util/SimpleTimeZone;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/location/CountryDetector;->detectCountry()Landroid/location/Country;
+Landroid/location/Country;->getCountryIso()Ljava/lang/String;
+Landroid/location/Country;->getSource()I
Landroid/location/GeocoderParams;->getClientPackage()Ljava/lang/String;
Landroid/location/GeocoderParams;->getLocale()Ljava/util/Locale;
+Landroid/location/ILocationManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
+Landroid/location/LocationManager;->mService:Landroid/location/ILocationManager;
Landroid/location/LocationManager;->requestLocationUpdates(Landroid/location/LocationRequest;Landroid/location/LocationListener;Landroid/os/Looper;)V
Landroid/location/LocationRequest;->createFromDeprecatedProvider(Ljava/lang/String;JFZ)Landroid/location/LocationRequest;
Landroid/location/LocationRequest;->setHideFromAppOps(Z)V
Landroid/location/LocationRequest;->setWorkSource(Landroid/os/WorkSource;)V
Landroid/location/Location;->setIsFromMockProvider(Z)V
+Landroid/Manifest$permission;->REAL_GET_TASKS:Ljava/lang/String;
Landroid/media/AudioAttributes$Builder;->setInternalCapturePreset(I)Landroid/media/AudioAttributes$Builder;
+Landroid/media/AudioAttributes;->mContentType:I
+Landroid/media/AudioAttributes;->mFlags:I
+Landroid/media/AudioAttributes;->mFormattedTags:Ljava/lang/String;
+Landroid/media/AudioAttributes;->mSource:I
+Landroid/media/AudioAttributes;->mUsage:I
+Landroid/media/AudioDevicePortConfig;-><init>(Landroid/media/AudioDevicePort;IIILandroid/media/AudioGainConfig;)V
+Landroid/media/AudioDevicePort;-><init>(Landroid/media/AudioHandle;Ljava/lang/String;[I[I[I[I[Landroid/media/AudioGain;ILjava/lang/String;)V
Landroid/media/AudioFocusInfo;->getClientId()Ljava/lang/String;
Landroid/media/AudioFocusInfo;->getClientUid()I
Landroid/media/AudioFocusInfo;->getLossReceived()I
+Landroid/media/AudioFormat;-><init>(IIII)V
+Landroid/media/AudioFormat;->mChannelMask:I
+Landroid/media/AudioFormat;->mEncoding:I
+Landroid/media/AudioFormat;->mSampleRate:I
+Landroid/media/audiofx/AudioEffect;-><init>(Ljava/util/UUID;Ljava/util/UUID;II)V
+Landroid/media/AudioGainConfig;-><init>(ILandroid/media/AudioGain;II[II)V
+Landroid/media/AudioGainConfig;->mChannelMask:I
+Landroid/media/AudioGainConfig;->mIndex:I
+Landroid/media/AudioGainConfig;->mMode:I
+Landroid/media/AudioGainConfig;->mRampDurationMs:I
+Landroid/media/AudioGainConfig;->mValues:[I
+Landroid/media/AudioGain;-><init>(IIIIIIIII)V
+Landroid/media/AudioHandle;-><init>(I)V
+Landroid/media/AudioHandle;->mId:I
Landroid/media/AudioManager;->abandonAudioFocus(Landroid/media/AudioManager$OnAudioFocusChangeListener;Landroid/media/AudioAttributes;)I
+Landroid/media/AudioManager;->getService()Landroid/media/IAudioService;
Landroid/media/AudioManager;->mAudioFocusIdListenerMap:Ljava/util/concurrent/ConcurrentHashMap;
Landroid/media/AudioManager;->registerAudioPolicy(Landroid/media/audiopolicy/AudioPolicy;)I
Landroid/media/AudioManager;->requestAudioFocus(Landroid/media/AudioFocusRequest;Landroid/media/audiopolicy/AudioPolicy;)I
@@ -445,13 +829,28 @@
Landroid/media/AudioManager;->STREAM_SYSTEM_ENFORCED:I
Landroid/media/AudioManager;->STREAM_TTS:I
Landroid/media/AudioManager;->unregisterAudioPolicyAsync(Landroid/media/audiopolicy/AudioPolicy;)V
+Landroid/media/AudioMixPortConfig;-><init>(Landroid/media/AudioMixPort;IIILandroid/media/AudioGainConfig;)V
+Landroid/media/AudioMixPort;-><init>(Landroid/media/AudioHandle;IILjava/lang/String;[I[I[I[I[Landroid/media/AudioGain;)V
+Landroid/media/AudioPatch;-><init>(Landroid/media/AudioHandle;[Landroid/media/AudioPortConfig;[Landroid/media/AudioPortConfig;)V
+Landroid/media/AudioPatch;->mHandle:Landroid/media/AudioHandle;
Landroid/media/audiopolicy/AudioMix$Builder;->build()Landroid/media/audiopolicy/AudioMix;
Landroid/media/audiopolicy/AudioMix$Builder;-><init>(Landroid/media/audiopolicy/AudioMixingRule;)V
Landroid/media/audiopolicy/AudioMix$Builder;->setFormat(Landroid/media/AudioFormat;)Landroid/media/audiopolicy/AudioMix$Builder;
Landroid/media/audiopolicy/AudioMix$Builder;->setRouteFlags(I)Landroid/media/audiopolicy/AudioMix$Builder;
+Landroid/media/audiopolicy/AudioMixingRule$AudioMixMatchCriterion;->mAttr:Landroid/media/AudioAttributes;
+Landroid/media/audiopolicy/AudioMixingRule$AudioMixMatchCriterion;->mIntProp:I
+Landroid/media/audiopolicy/AudioMixingRule$AudioMixMatchCriterion;->mRule:I
Landroid/media/audiopolicy/AudioMixingRule$Builder;->addRule(Landroid/media/AudioAttributes;I)Landroid/media/audiopolicy/AudioMixingRule$Builder;
Landroid/media/audiopolicy/AudioMixingRule$Builder;->build()Landroid/media/audiopolicy/AudioMixingRule;
Landroid/media/audiopolicy/AudioMixingRule$Builder;-><init>()V
+Landroid/media/audiopolicy/AudioMixingRule;->mCriteria:Ljava/util/ArrayList;
+Landroid/media/audiopolicy/AudioMix;->mCallbackFlags:I
+Landroid/media/audiopolicy/AudioMix;->mDeviceAddress:Ljava/lang/String;
+Landroid/media/audiopolicy/AudioMix;->mDeviceSystemType:I
+Landroid/media/audiopolicy/AudioMix;->mFormat:Landroid/media/AudioFormat;
+Landroid/media/audiopolicy/AudioMix;->mMixType:I
+Landroid/media/audiopolicy/AudioMix;->mRouteFlags:I
+Landroid/media/audiopolicy/AudioMix;->mRule:Landroid/media/audiopolicy/AudioMixingRule;
Landroid/media/audiopolicy/AudioPolicy$AudioPolicyFocusListener;-><init>()V
Landroid/media/audiopolicy/AudioPolicy$Builder;->addMix(Landroid/media/audiopolicy/AudioMix;)Landroid/media/audiopolicy/AudioPolicy$Builder;
Landroid/media/audiopolicy/AudioPolicy$Builder;->build()Landroid/media/audiopolicy/AudioPolicy;
@@ -459,18 +858,54 @@
Landroid/media/audiopolicy/AudioPolicy$Builder;->setAudioPolicyFocusListener(Landroid/media/audiopolicy/AudioPolicy$AudioPolicyFocusListener;)V
Landroid/media/audiopolicy/AudioPolicy$Builder;->setLooper(Landroid/os/Looper;)Landroid/media/audiopolicy/AudioPolicy$Builder;
Landroid/media/audiopolicy/AudioPolicy;->createAudioRecordSink(Landroid/media/audiopolicy/AudioMix;)Landroid/media/AudioRecord;
+Landroid/media/AudioPortConfig;-><init>(Landroid/media/AudioPort;IIILandroid/media/AudioGainConfig;)V
+Landroid/media/AudioPortConfig;->mChannelMask:I
+Landroid/media/AudioPortConfig;->mConfigMask:I
+Landroid/media/AudioPortConfig;->mFormat:I
+Landroid/media/AudioPortConfig;->mGain:Landroid/media/AudioGainConfig;
+Landroid/media/AudioPortConfig;->mPort:Landroid/media/AudioPort;
+Landroid/media/AudioPortConfig;->mSamplingRate:I
+Landroid/media/AudioPortEventHandler;->mJniCallback:J
+Landroid/media/AudioPortEventHandler;->postEventFromNative(Ljava/lang/Object;IIILjava/lang/Object;)V
+Landroid/media/AudioPort;-><init>(Landroid/media/AudioHandle;ILjava/lang/String;[I[I[I[I[Landroid/media/AudioGain;)V
+Landroid/media/AudioPort;->mActiveConfig:Landroid/media/AudioPortConfig;
+Landroid/media/AudioPort;->mGains:[Landroid/media/AudioGain;
+Landroid/media/AudioPort;->mHandle:Landroid/media/AudioHandle;
+Landroid/media/AudioPort;->mRole:I
+Landroid/media/AudioRecord;->mNativeCallbackCookie:J
+Landroid/media/AudioRecord;->mNativeDeviceCallback:J
+Landroid/media/AudioRecord;->mNativeRecorderInJavaObj:J
+Landroid/media/AudioRecord;->postEventFromNative(Ljava/lang/Object;IIILjava/lang/Object;)V
+Landroid/media/AudioSystem;->dynamicPolicyCallbackFromNative(ILjava/lang/String;I)V
+Landroid/media/AudioSystem;->errorCallbackFromNative(I)V
+Landroid/media/AudioSystem;->getPrimaryOutputFrameCount()I
+Landroid/media/AudioSystem;->getPrimaryOutputSamplingRate()I
+Landroid/media/AudioSystem;->recordingCallbackFromNative(IIII[I)V
Landroid/media/AudioSystem;->setDeviceConnectionState(IILjava/lang/String;Ljava/lang/String;)I
Landroid/media/AudioTrack;->getLatency()I
+Landroid/media/AudioTrack;->mJniData:J
+Landroid/media/AudioTrack;->mNativeTrackInJavaObj:J
+Landroid/media/AudioTrack;->mStreamType:I
+Landroid/media/AudioTrack;->postEventFromNative(Ljava/lang/Object;IIILjava/lang/Object;)V
Landroid/media/IAudioService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/media/IAudioService;
+Landroid/media/JetPlayer;->mNativePlayerInJavaObj:J
+Landroid/media/JetPlayer;->postEventFromNative(Ljava/lang/Object;III)V
Landroid/media/MediaCodec;->releaseOutputBuffer(IZZJ)V
+Landroid/media/MediaFile;->FIRST_AUDIO_FILE_TYPE:I
Landroid/media/MediaFile;->getFileType(Ljava/lang/String;)Landroid/media/MediaFile$MediaFileType;
Landroid/media/MediaFile;->getMimeTypeForFile(Ljava/lang/String;)Ljava/lang/String;
+Landroid/media/MediaFile;-><init>()V
+Landroid/media/MediaFile;->isAudioFileType(I)Z
+Landroid/media/MediaFile;->isImageFileType(I)Z
Landroid/media/MediaFile;->isVideoFileType(I)Z
+Landroid/media/MediaFile;->LAST_AUDIO_FILE_TYPE:I
Landroid/media/MediaFile$MediaFileType;->fileType:I
+Landroid/media/MediaFile$MediaFileType;->mimeType:Ljava/lang/String;
Landroid/media/MediaFile;->sFileTypeMap:Ljava/util/HashMap;
Landroid/media/MediaMetadataRetriever;->getEmbeddedPicture(I)[B
Landroid/media/MediaPlayer;->getMetadata(ZZ)Landroid/media/Metadata;
Landroid/media/MediaPlayer;->invoke(Landroid/os/Parcel;Landroid/os/Parcel;)V
+Landroid/media/MediaPlayer;->mEventHandler:Landroid/media/MediaPlayer$EventHandler;
Landroid/media/MediaPlayer;->newRequest()Landroid/os/Parcel;
Landroid/media/MediaPlayer;->setDataSource(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;Ljava/util/List;)V
Landroid/media/MediaPlayer;->setDataSource(Ljava/lang/String;Ljava/util/Map;Ljava/util/List;)V
@@ -482,12 +917,47 @@
Landroid/media/MediaRouter;->selectRouteInt(ILandroid/media/MediaRouter$RouteInfo;Z)V
Landroid/media/MediaScanner;->mClient:Landroid/media/MediaScanner$MyMediaScannerClient;
Landroid/media/MediaScanner;->scanSingleFile(Ljava/lang/String;Ljava/lang/String;)Landroid/net/Uri;
+Landroid/media/Metadata;->getBoolean(I)Z
+Landroid/media/Metadata;->has(I)Z
+Landroid/media/Metadata;->PAUSE_AVAILABLE:I
+Landroid/media/Metadata;->SEEK_BACKWARD_AVAILABLE:I
+Landroid/media/Metadata;->SEEK_FORWARD_AVAILABLE:I
+Landroid/media/MicrophoneInfo;-><init>(Ljava/lang/String;ILjava/lang/String;IIILandroid/media/MicrophoneInfo$Coordinate3F;Landroid/media/MicrophoneInfo$Coordinate3F;Ljava/util/List;Ljava/util/List;FFFI)V
Landroid/media/MiniThumbFile;->reset()V
+Landroid/media/PlaybackParams;->mAudioFallbackMode:I
+Landroid/media/PlaybackParams;->mAudioStretchMode:I
+Landroid/media/PlaybackParams;->mPitch:F
+Landroid/media/PlaybackParams;->mSet:I
+Landroid/media/PlaybackParams;->mSpeed:F
+Landroid/media/PlaybackParams;->SET_AUDIO_FALLBACK_MODE:I
+Landroid/media/PlaybackParams;->SET_AUDIO_STRETCH_MODE:I
+Landroid/media/PlaybackParams;->SET_PITCH:I
+Landroid/media/PlaybackParams;->SET_SPEED:I
+Landroid/media/RemoteDisplay;->notifyDisplayConnected(Landroid/view/Surface;IIII)V
+Landroid/media/RemoteDisplay;->notifyDisplayDisconnected()V
+Landroid/media/RemoteDisplay;->notifyDisplayError(I)V
Landroid/media/RingtoneManager;->getRingtone(Landroid/content/Context;Landroid/net/Uri;I)Landroid/media/Ringtone;
Landroid/media/Ringtone;->setLooping(Z)V
Landroid/media/Ringtone;->setVolume(F)V
+Landroid/media/session/MediaSessionLegacyHelper;->getHelper(Landroid/content/Context;)Landroid/media/session/MediaSessionLegacyHelper;
Landroid/media/SubtitleController;->mHandler:Landroid/os/Handler;
Landroid/media/ThumbnailUtils;->createImageThumbnail(Ljava/lang/String;I)Landroid/graphics/Bitmap;
+Landroid/media/ToneGenerator;->mNativeContext:J
+Landroid/media/VolumeShaper$Configuration;-><init>(IIIDI[F[F)V
+Landroid/media/VolumeShaper$Configuration;->mDurationMs:D
+Landroid/media/VolumeShaper$Configuration;->mId:I
+Landroid/media/VolumeShaper$Configuration;->mInterpolatorType:I
+Landroid/media/VolumeShaper$Configuration;->mOptionFlags:I
+Landroid/media/VolumeShaper$Configuration;->mTimes:[F
+Landroid/media/VolumeShaper$Configuration;->mType:I
+Landroid/media/VolumeShaper$Configuration;->mVolumes:[F
+Landroid/media/VolumeShaper$Operation;-><init>(IIF)V
+Landroid/media/VolumeShaper$Operation;->mFlags:I
+Landroid/media/VolumeShaper$Operation;->mReplaceId:I
+Landroid/media/VolumeShaper$Operation;->mXOffset:F
+Landroid/media/VolumeShaper$State;-><init>(FF)V
+Landroid/media/VolumeShaper$State;->mVolume:F
+Landroid/media/VolumeShaper$State;->mXOffset:F
Landroid/metrics/LogMaker;->getCategory()I
Landroid/metrics/LogMaker;->getCounterBucket()J
Landroid/metrics/LogMaker;->getCounterName()Ljava/lang/String;
@@ -519,8 +989,23 @@
Landroid/net/ConnectivityManager;->startTethering(IZLandroid/net/ConnectivityManager$OnStartTetheringCallback;Landroid/os/Handler;)V
Landroid/net/ConnectivityManager;->startTethering(IZLandroid/net/ConnectivityManager$OnStartTetheringCallback;)V
Landroid/net/ConnectivityManager;->stopTethering(I)V
+Landroid/net/ConnectivityManager;->TYPE_MOBILE_CBS:I
+Landroid/net/ConnectivityManager;->TYPE_MOBILE_EMERGENCY:I
+Landroid/net/ConnectivityManager;->TYPE_MOBILE_FOTA:I
+Landroid/net/ConnectivityManager;->TYPE_MOBILE_IA:I
+Landroid/net/ConnectivityManager;->TYPE_MOBILE_IMS:I
+Landroid/net/ConnectivityManager;->TYPE_NONE:I
+Landroid/net/ConnectivityManager;->TYPE_PROXY:I
+Landroid/net/ConnectivityManager;->TYPE_WIFI_P2P:I
+Landroid/net/IConnectivityManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/IConnectivityManager;
+Landroid/net/IConnectivityManager$Stub$Proxy;->getAllNetworks()[Landroid/net/Network;
+Landroid/net/IConnectivityManager$Stub$Proxy;->getTetherableIfaces()[Ljava/lang/String;
+Landroid/net/IConnectivityManager$Stub$Proxy;->getTetherableUsbRegexs()[Ljava/lang/String;
+Landroid/net/IConnectivityManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/net/INetworkStatsService$Stub$Proxy;->getMobileIfaces()[Ljava/lang/String;
Landroid/net/LinkProperties;->setHttpProxy(Landroid/net/ProxyInfo;)V
+Landroid/net/LocalSocketImpl;->inboundFileDescriptors:[Ljava/io/FileDescriptor;
+Landroid/net/LocalSocketImpl;->outboundFileDescriptors:[Ljava/io/FileDescriptor;
Landroid/net/NetworkKey;-><init>(Landroid/net/WifiKey;)V
Landroid/net/NetworkPolicyManager;->mService:Landroid/net/INetworkPolicyManager;
Landroid/net/NetworkRecommendationProvider;-><init>(Landroid/content/Context;Ljava/util/concurrent/Executor;)V
@@ -541,6 +1026,7 @@
Landroid/net/NetworkStats;->txBytes:[J
Landroid/net/NetworkStats;->txPackets:[J
Landroid/net/NetworkStats;->uid:[I
+Landroid/net/ProxyInfo;-><init>(Ljava/lang/String;ILjava/lang/String;)V
Landroid/net/RssiCurve;-><init>(II[BI)V
Landroid/net/RssiCurve;-><init>(II[B)V
Landroid/net/RssiCurve;->lookupScore(IZ)B
@@ -571,11 +1057,17 @@
Landroid/net/SSLCertificateSocketFactory;->TAG:Ljava/lang/String;
Landroid/net/SSLCertificateSocketFactory;->toLengthPrefixedList([[[B)[B
Landroid/net/SSLCertificateSocketFactory;->verifyHostname(Ljava/net/Socket;Ljava/lang/String;)V
+Landroid/net/SSLSessionCache;->mSessionCache:Lcom/android/org/conscrypt/SSLClientSessionCache;
+Landroid/net/TrafficStats;->getRxBytes(Ljava/lang/String;)J
Landroid/net/TrafficStats;->getStatsService()Landroid/net/INetworkStatsService;
+Landroid/net/TrafficStats;->getTxBytes(Ljava/lang/String;)J
Landroid/net/TrafficStats;->setThreadStatsTagBackup()V
Landroid/net/TrafficStats;->setThreadStatsTagRestore()V
Landroid/net/TrafficStats;->setThreadStatsUid(I)V
+Landroid/net/Uri;-><init>()V
Landroid/net/WebAddress;-><init>(Ljava/lang/String;)V
+Landroid/net/wifi/IWifiManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/wifi/IWifiManager;
+Landroid/net/wifi/IWifiManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/net/WifiKey;-><init>(Ljava/lang/String;Ljava/lang/String;)V
Landroid/net/wifi/p2p/WifiP2pGroup;->getNetworkId()I
Landroid/net/wifi/p2p/WifiP2pGroupList;->getGroupList()Ljava/util/Collection;
@@ -585,13 +1077,30 @@
Landroid/net/wifi/RttManager;->getRttCapabilities()Landroid/net/wifi/RttManager$RttCapabilities;
Landroid/net/wifi/RttManager$RttParams;-><init>()V
Landroid/net/wifi/RttManager;->startRanging([Landroid/net/wifi/RttManager$RttParams;Landroid/net/wifi/RttManager$RttListener;)V
+Landroid/net/wifi/ScanResult;->anqpDomainId:I
+Landroid/net/wifi/ScanResult;->anqpLines:Ljava/util/List;
+Landroid/net/wifi/ScanResult;->distanceCm:I
+Landroid/net/wifi/ScanResult;->distanceSdCm:I
+Landroid/net/wifi/ScanResult;->flags:J
+Landroid/net/wifi/ScanResult;->hessid:J
+Landroid/net/wifi/ScanResult;->numUsage:I
+Landroid/net/wifi/ScanResult;->seen:J
+Landroid/net/wifi/ScanResult;->untrusted:Z
+Landroid/net/wifi/ScanResult;->wifiSsid:Landroid/net/wifi/WifiSsid;
Landroid/net/wifi/WifiConfiguration;->apBand:I
Landroid/net/wifi/WifiConfiguration;->apChannel:I
+Landroid/net/wifi/WifiConfiguration;->creatorUid:I
Landroid/net/wifi/WifiConfiguration;->hasNoInternetAccess()Z
Landroid/net/wifi/WifiConfiguration;->isEphemeral()Z
Landroid/net/wifi/WifiConfiguration;->isNoInternetAccessExpected()Z
+Landroid/net/wifi/WifiConfiguration;->lastUpdateUid:I
Landroid/net/wifi/WifiConfiguration;->mIpConfiguration:Landroid/net/IpConfiguration;
+Landroid/net/wifi/WifiConfiguration;->numAssociation:I
Landroid/net/wifi/WifiConfiguration;->validatedInternetAccess:Z
+Landroid/net/wifi/WifiEnterpriseConfig;->getCaCertificateAlias()Ljava/lang/String;
+Landroid/net/wifi/WifiEnterpriseConfig;->getClientCertificateAlias()Ljava/lang/String;
+Landroid/net/wifi/WifiInfo;->getMeteredHint()Z
+Landroid/net/wifi/WifiManager;->cancelLocalOnlyHotspotRequest()V
Landroid/net/wifi/WifiManager;->connect(ILandroid/net/wifi/WifiManager$ActionListener;)V
Landroid/net/wifi/WifiManager;->connect(Landroid/net/wifi/WifiConfiguration;Landroid/net/wifi/WifiManager$ActionListener;)V
Landroid/net/wifi/WifiManager;->EXTRA_WIFI_AP_STATE:Ljava/lang/String;
@@ -636,6 +1145,7 @@
Landroid/os/AsyncTask;->mWorker:Landroid/os/AsyncTask$WorkerRunnable;
Landroid/os/AsyncTask;->sDefaultExecutor:Ljava/util/concurrent/Executor;
Landroid/os/AsyncTask;->setDefaultExecutor(Ljava/util/concurrent/Executor;)V
+Landroid/os/BatteryStats;->getUidStats()Landroid/util/SparseArray;
Landroid/os/BatteryStats$HistoryItem;->states2:I
Landroid/os/BatteryStats;->NUM_DATA_CONNECTION_TYPES:I
Landroid/os/BatteryStats$Timer;->getTotalTimeLocked(JI)J
@@ -650,18 +1160,45 @@
Landroid/os/BatteryStats$Uid$Proc;->getUserTime(I)J
Landroid/os/BatteryStats$Uid$Sensor;->getHandle()I
Landroid/os/BatteryStats$Uid$Sensor;->getSensorTime()Landroid/os/BatteryStats$Timer;
+Landroid/os/Binder;->execTransact(IJJI)Z
+Landroid/os/Binder;->mObject:J
Landroid/os/Build;->getString(Ljava/lang/String;)Ljava/lang/String;
+Landroid/os/Build$VERSION;->ACTIVE_CODENAMES:[Ljava/lang/String;
+Landroid/os/Build$VERSION;->RESOURCES_SDK_INT:I
Landroid/os/Bundle;->getIBinder(Ljava/lang/String;)Landroid/os/IBinder;
Landroid/os/Bundle;->putIBinder(Ljava/lang/String;Landroid/os/IBinder;)V
Landroid/os/Debug;->countInstancesOfClass(Ljava/lang/Class;)J
Landroid/os/Debug;->dumpReferenceTables()V
+Landroid/os/Debug$MemoryInfo;->dalvikPrivateClean:I
+Landroid/os/Debug$MemoryInfo;->dalvikRss:I
+Landroid/os/Debug$MemoryInfo;->dalvikSharedClean:I
+Landroid/os/Debug$MemoryInfo;->dalvikSwappablePss:I
+Landroid/os/Debug$MemoryInfo;->dalvikSwappedOut:I
+Landroid/os/Debug$MemoryInfo;->dalvikSwappedOutPss:I
Landroid/os/Debug$MemoryInfo;->getOtherLabel(I)Ljava/lang/String;
Landroid/os/Debug$MemoryInfo;->getOtherPrivateDirty(I)I
+Landroid/os/Debug$MemoryInfo;->getOtherPrivate(I)I
Landroid/os/Debug$MemoryInfo;->getOtherPss(I)I
Landroid/os/Debug$MemoryInfo;->getOtherSharedDirty(I)I
+Landroid/os/Debug$MemoryInfo;->getTotalUss()I
+Landroid/os/Debug$MemoryInfo;->hasSwappedOutPss:Z
+Landroid/os/Debug$MemoryInfo;->nativePrivateClean:I
+Landroid/os/Debug$MemoryInfo;->nativeRss:I
+Landroid/os/Debug$MemoryInfo;->nativeSharedClean:I
+Landroid/os/Debug$MemoryInfo;->nativeSwappablePss:I
+Landroid/os/Debug$MemoryInfo;->nativeSwappedOut:I
+Landroid/os/Debug$MemoryInfo;->nativeSwappedOutPss:I
Landroid/os/Debug$MemoryInfo;->NUM_DVK_STATS:I
Landroid/os/Debug$MemoryInfo;->NUM_OTHER_STATS:I
+Landroid/os/Debug$MemoryInfo;->otherPrivateClean:I
+Landroid/os/Debug$MemoryInfo;->otherRss:I
+Landroid/os/Debug$MemoryInfo;->otherSharedClean:I
+Landroid/os/Debug$MemoryInfo;->otherStats:[I
+Landroid/os/Debug$MemoryInfo;->otherSwappablePss:I
+Landroid/os/Debug$MemoryInfo;->otherSwappedOut:I
+Landroid/os/Debug$MemoryInfo;->otherSwappedOutPss:I
Landroid/os/Environment;->buildExternalStorageAppDataDirs(Ljava/lang/String;)[Ljava/io/File;
+Landroid/os/FileObserver$ObserverThread;->onEvent(IILjava/lang/String;)V
Landroid/os/FileUtils;->checksumCrc32(Ljava/io/File;)J
Landroid/os/FileUtils;->copyFile(Ljava/io/File;Ljava/io/File;)Z
Landroid/os/FileUtils;->copyToFile(Ljava/io/InputStream;Ljava/io/File;)Z
@@ -676,21 +1213,40 @@
Landroid/os/Handler;->hasCallbacks(Ljava/lang/Runnable;)Z
Landroid/os/Handler;->mCallback:Landroid/os/Handler$Callback;
Landroid/os/Handler;->mMessenger:Landroid/os/IMessenger;
+Landroid/os/HwParcel;-><init>(Z)V
+Landroid/os/IPermissionController$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/IPermissionController;
+Landroid/os/IPermissionController$Stub$Proxy;->checkPermission(Ljava/lang/String;II)Z
Landroid/os/IPowerManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/IPowerManager;
+Landroid/os/IPowerManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
+Landroid/os/IPowerManager$Stub$Proxy;->isLightDeviceIdleMode()Z
Landroid/os/IPowerManager;->userActivity(JII)V
+Landroid/os/IServiceManager;->getService(Ljava/lang/String;)Landroid/os/IBinder;
+Landroid/os/IUserManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/os/Looper;->mQueue:Landroid/os/MessageQueue;
+Landroid/os/Looper;->setTraceTag(J)V
+Landroid/os/Looper;->sThreadLocal:Ljava/lang/ThreadLocal;
Landroid/os/MemoryFile;->getFileDescriptor()Ljava/io/FileDescriptor;
Landroid/os/Message;->callback:Ljava/lang/Runnable;
Landroid/os/Message;->flags:I
+Landroid/os/Message;->markInUse()V
Landroid/os/Message;->next:Landroid/os/Message;
+Landroid/os/MessageQueue;->dispatchEvents(II)I
Landroid/os/MessageQueue;->mIdleHandlers:Ljava/util/ArrayList;
Landroid/os/MessageQueue;->mMessages:Landroid/os/Message;
+Landroid/os/MessageQueue;->mPtr:J
Landroid/os/MessageQueue;->mQuitAllowed:Z
+Landroid/os/MessageQueue;->nativePollOnce(JI)V
Landroid/os/MessageQueue;->next()Landroid/os/Message;
+Landroid/os/Message;->recycleUnchecked()V
Landroid/os/Message;->target:Landroid/os/Handler;
+Landroid/os/Message;->when:J
+Landroid/os/ParcelFileDescriptor;-><init>(Ljava/io/FileDescriptor;)V
+Landroid/os/Parcel;->mNativePtr:J
+Landroid/os/Parcel$ReadWriteHelper;-><init>()V
Landroid/os/PowerManager;->getMaximumScreenBrightnessSetting()I
Landroid/os/PowerManager;->getMinimumScreenBrightnessSetting()I
Landroid/os/PowerManager;->isLightDeviceIdleMode()Z
+Landroid/os/PowerManager;->mService:Landroid/os/IPowerManager;
Landroid/os/PowerManager;->userActivity(JII)V
Landroid/os/PowerManager;->userActivity(JZ)V
Landroid/os/PowerManager;->validateWakeLockParameters(ILjava/lang/String;)V
@@ -698,6 +1254,7 @@
Landroid/os/PowerManager;->wakeUp(J)V
Landroid/os/Process;->getParentPid(I)I
Landroid/os/Process;->getPids(Ljava/lang/String;[I)[I
+Landroid/os/Process;->getTotalMemory()J
Landroid/os/Process;->getUidForPid(I)I
Landroid/os/Process;->isIsolated(I)Z
Landroid/os/Process;->isIsolated()Z
@@ -711,18 +1268,30 @@
Landroid/os/RecoverySystem;->scheduleUpdateOnBoot(Landroid/content/Context;Ljava/io/File;)V
Landroid/os/SELinux;->isSELinuxEnabled()Z
Landroid/os/SELinux;->isSELinuxEnforced()Z
+Landroid/os/ServiceManager;->addService(Ljava/lang/String;Landroid/os/IBinder;)V
Landroid/os/ServiceManager;->checkService(Ljava/lang/String;)Landroid/os/IBinder;
+Landroid/os/ServiceManager;->getIServiceManager()Landroid/os/IServiceManager;
Landroid/os/ServiceManager;->getService(Ljava/lang/String;)Landroid/os/IBinder;
+Landroid/os/ServiceManager;-><init>()V
+Landroid/os/ServiceManager;->listServices()[Ljava/lang/String;
+Landroid/os/ServiceManagerNative;->asInterface(Landroid/os/IBinder;)Landroid/os/IServiceManager;
+Landroid/os/ServiceManager;->sCache:Ljava/util/HashMap;
+Landroid/os/ServiceManager;->sServiceManager:Landroid/os/IServiceManager;
Landroid/os/storage/DiskInfo;->getDescription()Ljava/lang/String;
+Landroid/os/storage/IStorageManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/storage/IStorageManager;
+Landroid/os/storage/IStorageManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/os/storage/StorageManager;->findVolumeByUuid(Ljava/lang/String;)Landroid/os/storage/VolumeInfo;
Landroid/os/storage/StorageManager;->getBestVolumeDescription(Landroid/os/storage/VolumeInfo;)Ljava/lang/String;
Landroid/os/storage/StorageManager;->getDisks()Ljava/util/List;
Landroid/os/storage/StorageManager;->getStorageBytesUntilLow(Ljava/io/File;)J
+Landroid/os/storage/StorageManager;->getStorageLowBytes(Ljava/io/File;)J
Landroid/os/storage/StorageManager;->getVolumeList(II)[Landroid/os/storage/StorageVolume;
Landroid/os/storage/StorageManager;->getVolumeList()[Landroid/os/storage/StorageVolume;
Landroid/os/storage/StorageManager;->getVolumePaths()[Ljava/lang/String;
Landroid/os/storage/StorageManager;->getVolumes()Ljava/util/List;
Landroid/os/storage/StorageManager;->getVolumeState(Ljava/lang/String;)Ljava/lang/String;
+Landroid/os/storage/StorageVolume;->allowMassStorage()Z
+Landroid/os/storage/StorageVolume;->getMaxFileSize()J
Landroid/os/storage/StorageVolume;->getPathFile()Ljava/io/File;
Landroid/os/storage/StorageVolume;->getPath()Ljava/lang/String;
Landroid/os/storage/StorageVolume;->getUserLabel()Ljava/lang/String;
@@ -733,6 +1302,9 @@
Landroid/os/storage/VolumeInfo;->getType()I
Landroid/os/storage/VolumeInfo;->isPrimary()Z
Landroid/os/storage/VolumeInfo;->isVisible()Z
+Landroid/os/StrictMode;->disableDeathOnFileUriExposure()V
+Landroid/os/StrictMode;->getThreadPolicyMask()I
+Landroid/os/StrictMode;->onBinderStrictModePolicyChange(I)V
Landroid/os/StrictMode;->violationsBeingTimed:Ljava/lang/ThreadLocal;
Landroid/os/SystemProperties;->addChangeCallback(Ljava/lang/Runnable;)V
Landroid/os/SystemProperties;->getBoolean(Ljava/lang/String;Z)Z
@@ -740,6 +1312,8 @@
Landroid/os/SystemProperties;->get(Ljava/lang/String;)Ljava/lang/String;
Landroid/os/SystemProperties;->get(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
Landroid/os/SystemProperties;->getLong(Ljava/lang/String;J)J
+Landroid/os/SystemProperties;-><init>()V
+Landroid/os/SystemProperties;->native_get(Ljava/lang/String;)Ljava/lang/String;
Landroid/os/SystemProperties;->PROP_NAME_MAX:I
Landroid/os/SystemProperties;->set(Ljava/lang/String;Ljava/lang/String;)V
Landroid/os/Trace;->asyncTraceBegin(JLjava/lang/String;I)V
@@ -764,16 +1338,19 @@
Landroid/os/UpdateLock;->isHeld()Z
Landroid/os/UpdateLock;->NOW_IS_CONVENIENT:Ljava/lang/String;
Landroid/os/UpdateLock;->release()V
+Landroid/os/UpdateLock;->TIMESTAMP:Ljava/lang/String;
Landroid/os/UpdateLock;->UPDATE_LOCK_CHANGED:Ljava/lang/String;
Landroid/os/UserHandle;->ALL:Landroid/os/UserHandle;
Landroid/os/UserHandle;->getAppIdFromSharedAppGid(I)I
Landroid/os/UserHandle;->getCallingUserId()I
Landroid/os/UserHandle;->getIdentifier()I
+Landroid/os/UserHandle;->getUid(II)I
Landroid/os/UserHandle;->getUserId(I)I
Landroid/os/UserHandle;-><init>(I)V
Landroid/os/UserHandle;->isOwner()Z
Landroid/os/UserHandle;->myUserId()I
Landroid/os/UserHandle;->of(I)Landroid/os/UserHandle;
+Landroid/os/UserHandle;->PER_USER_RANGE:I
Landroid/os/UserHandle;->USER_OWNER:I
Landroid/os/UserManager;->getBadgedLabelForUser(Ljava/lang/CharSequence;Landroid/os/UserHandle;)Ljava/lang/CharSequence;
Landroid/os/UserManager;->get(Landroid/content/Context;)Landroid/os/UserManager;
@@ -789,10 +1366,14 @@
Landroid/os/UserManager;->isLinkedUser()Z
Landroid/os/UserManager;->isManagedProfile()Z
Landroid/os/UserManager;->isUserUnlocked(I)Z
+Landroid/os/VintfObject;->report()[Ljava/lang/String;
Landroid/os/WorkSource;->add(ILjava/lang/String;)Z
Landroid/os/WorkSource;->add(I)Z
Landroid/os/WorkSource;->get(I)I
Landroid/os/WorkSource;->getName(I)Ljava/lang/String;
+Landroid/os/WorkSource;->mNames:[Ljava/lang/String;
+Landroid/os/WorkSource;->mNum:I
+Landroid/os/WorkSource;->mUids:[I
Landroid/os/WorkSource;->size()I
Landroid/preference/DialogPreference;->mBuilder:Landroid/app/AlertDialog$Builder;
Landroid/preference/DialogPreference;->mDialogIcon:Landroid/graphics/drawable/Drawable;
@@ -812,6 +1393,7 @@
Landroid/preference/PreferenceManager;->getPreferenceScreen()Landroid/preference/PreferenceScreen;
Landroid/preference/PreferenceManager;->inflateFromIntent(Landroid/content/Intent;Landroid/preference/PreferenceScreen;)Landroid/preference/PreferenceScreen;
Landroid/preference/PreferenceManager;->inflateFromResource(Landroid/content/Context;ILandroid/preference/PreferenceScreen;)Landroid/preference/PreferenceScreen;
+Landroid/preference/PreferenceManager;-><init>(Landroid/app/Activity;I)V
Landroid/preference/PreferenceManager;->mActivityDestroyListeners:Ljava/util/List;
Landroid/preference/PreferenceManager;->mOnPreferenceTreeClickListener:Landroid/preference/PreferenceManager$OnPreferenceTreeClickListener;
Landroid/preference/PreferenceManager;->mSharedPreferences:Landroid/content/SharedPreferences;
@@ -828,20 +1410,34 @@
Landroid/print/PrinterId;->getServiceName()Landroid/content/ComponentName;
Landroid/print/PrintJobInfo;->getAdvancedOptions()Landroid/os/Bundle;
Landroid/print/PrintJobInfo;->getDocumentInfo()Landroid/print/PrintDocumentInfo;
+Landroid/provider/Browser;->BOOKMARKS_URI:Landroid/net/Uri;
Landroid/provider/Browser;->canClearHistory(Landroid/content/ContentResolver;)Z
Landroid/provider/Browser;->clearHistory(Landroid/content/ContentResolver;)V
Landroid/provider/Browser;->clearSearches(Landroid/content/ContentResolver;)V
Landroid/provider/Browser;->deleteFromHistory(Landroid/content/ContentResolver;Ljava/lang/String;)V
Landroid/provider/Browser;->getVisitedHistory(Landroid/content/ContentResolver;)[Ljava/lang/String;
Landroid/provider/Browser;->sendString(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)V
+Landroid/provider/Settings$ContentProviderHolder;->mContentProvider:Landroid/content/IContentProvider;
+Landroid/provider/Settings$Global;->ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED:Ljava/lang/String;
Landroid/provider/Settings$Global;->OTA_DISABLE_AUTOMATIC_UPDATE:Ljava/lang/String;
Landroid/provider/Settings$Global;->PACKAGE_VERIFIER_ENABLE:Ljava/lang/String;
+Landroid/provider/Settings$Global;->sNameValueCache:Landroid/provider/Settings$NameValueCache;
+Landroid/provider/Settings$NameValueCache;->mProviderHolder:Landroid/provider/Settings$ContentProviderHolder;
+Landroid/provider/Settings$Secure;->ACCESSIBILITY_AUTOCLICK_ENABLED:Ljava/lang/String;
+Landroid/provider/Settings$Secure;->ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED:Ljava/lang/String;
Landroid/provider/Settings$Secure;->ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED:Ljava/lang/String;
+Landroid/provider/Settings$Secure;->ACCESSIBILITY_LARGE_POINTER_ICON:Ljava/lang/String;
+Landroid/provider/Settings$Secure;->INCALL_POWER_BUTTON_BEHAVIOR:Ljava/lang/String;
+Landroid/provider/Settings$Secure;->LONG_PRESS_TIMEOUT:Ljava/lang/String;
Landroid/provider/Settings$Secure;->PACKAGE_VERIFIER_USER_CONSENT:Ljava/lang/String;
+Landroid/provider/Settings$Secure;->sNameValueCache:Landroid/provider/Settings$NameValueCache;
Landroid/provider/Settings$Secure;->USER_SETUP_COMPLETE:Ljava/lang/String;
Landroid/provider/Settings$System;->AIRPLANE_MODE_TOGGLEABLE_RADIOS:Ljava/lang/String;
Landroid/provider/Settings$System;->getStringForUser(Landroid/content/ContentResolver;Ljava/lang/String;I)Ljava/lang/String;
+Landroid/provider/Settings$System;->HEARING_AID:Ljava/lang/String;
+Landroid/provider/Settings$System;->MASTER_MONO:Ljava/lang/String;
Landroid/provider/Settings$System;->putStringForUser(Landroid/content/ContentResolver;Ljava/lang/String;Ljava/lang/String;I)Z
+Landroid/provider/Settings$System;->sNameValueCache:Landroid/provider/Settings$NameValueCache;
Landroid/provider/Telephony$Sms;->addMessageToUri(ILandroid/content/ContentResolver;Landroid/net/Uri;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Long;ZZJ)Landroid/net/Uri;
Landroid/provider/Telephony$Sms;->addMessageToUri(ILandroid/content/ContentResolver;Landroid/net/Uri;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Long;ZZ)Landroid/net/Uri;
Landroid/provider/Telephony$Sms;->addMessageToUri(Landroid/content/ContentResolver;Landroid/net/Uri;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Long;ZZJ)Landroid/net/Uri;
@@ -850,6 +1446,7 @@
Landroid/provider/Telephony$Sms$Inbox;->addMessage(Landroid/content/ContentResolver;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Long;Z)Landroid/net/Uri;
Landroid/provider/Telephony$Sms$Sent;->addMessage(ILandroid/content/ContentResolver;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Long;)Landroid/net/Uri;
Landroid/provider/Telephony$Sms$Sent;->addMessage(Landroid/content/ContentResolver;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Long;)Landroid/net/Uri;
+Landroid/renderscript/RenderScriptCacheDir;->mCacheDir:Ljava/io/File;
Landroid/renderscript/RenderScript;->create(Landroid/content/Context;I)Landroid/renderscript/RenderScript;
Landroid/renderscript/RenderScript;->create(Landroid/content/Context;ILandroid/renderscript/RenderScript$ContextType;I)Landroid/renderscript/RenderScript;
Landroid/renderscript/RenderScript;->getMinorID()J
@@ -857,14 +1454,17 @@
Landroid/R$styleable;->TextAppearance_textColor:I
Landroid/R$styleable;->TextAppearance_textSize:I
Landroid/security/KeyStore;->getInstance()Landroid/security/KeyStore;
+Landroid/security/net/config/RootTrustManager;->checkServerTrusted([Ljava/security/cert/X509Certificate;Ljava/lang/String;Ljava/lang/String;)Ljava/util/List;
Landroid/service/media/IMediaBrowserServiceCallbacks;->onConnectFailed()V
Landroid/service/media/IMediaBrowserServiceCallbacks;->onConnect(Ljava/lang/String;Landroid/media/session/MediaSession$Token;Landroid/os/Bundle;)V
Landroid/service/media/IMediaBrowserServiceCallbacks;->onLoadChildren(Ljava/lang/String;Landroid/content/pm/ParceledListSlice;)V
Landroid/service/media/IMediaBrowserServiceCallbacks;->onLoadChildrenWithOptions(Ljava/lang/String;Landroid/content/pm/ParceledListSlice;Landroid/os/Bundle;)V
+Landroid/service/media/IMediaBrowserServiceCallbacks$Stub;->asInterface(Landroid/os/IBinder;)Landroid/service/media/IMediaBrowserServiceCallbacks;
Landroid/service/media/MediaBrowserService;->KEY_MEDIA_ITEM:Ljava/lang/String;
Landroid/service/media/MediaBrowserService$Result;->mFlags:I
Landroid/service/notification/NotificationListenerService;->registerAsSystemService(Landroid/content/Context;Landroid/content/ComponentName;I)V
Landroid/service/notification/NotificationListenerService;->unregisterAsSystemService()V
+Landroid/service/persistentdata/PersistentDataBlockManager;->getFlashLockState()I
Landroid/service/persistentdata/PersistentDataBlockManager;->getMaximumDataBlockSize()J
Landroid/service/persistentdata/PersistentDataBlockManager;->read()[B
Landroid/service/persistentdata/PersistentDataBlockManager;->write([B)I
@@ -879,6 +1479,7 @@
Landroid/service/voice/VoiceInteractionService;->isKeyphraseAndLocaleSupportedForHotword(Ljava/lang/String;Ljava/util/Locale;)Z
Landroid/service/wallpaper/WallpaperService$Engine;->setFixedSizeAllowed(Z)V
Landroid/speech/tts/TextToSpeech;->getCurrentEngine()Ljava/lang/String;
+Landroid/system/Int32Ref;->value:I
Landroid/system/StructTimeval;->fromMillis(J)Landroid/system/StructTimeval;
Landroid/telecom/AudioState;->getRoute()I
Landroid/telecom/AudioState;->getSupportedRouteMask()I
@@ -896,16 +1497,32 @@
Landroid/telecom/Phone;->setMuted(Z)V
Landroid/telecom/TelecomManager;->endCall()Z
Landroid/telecom/TelecomManager;->EXTRA_IS_HANDOVER:Ljava/lang/String;
+Landroid/telecom/TelecomManager;->getUserSelectedOutgoingPhoneAccount()Landroid/telecom/PhoneAccountHandle;
+Landroid/telecom/TelecomManager;->setUserSelectedOutgoingPhoneAccount(Landroid/telecom/PhoneAccountHandle;)V
+Landroid/telephony/CellSignalStrengthLte;->mCqi:I
+Landroid/telephony/CellSignalStrengthLte;->mRsrp:I
+Landroid/telephony/CellSignalStrengthLte;->mRsrq:I
+Landroid/telephony/CellSignalStrengthLte;->mRssnr:I
Landroid/telephony/PhoneStateListener;->mSubId:Ljava/lang/Integer;
Landroid/telephony/ServiceState;->newFromBundle(Landroid/os/Bundle;)Landroid/telephony/ServiceState;
+Landroid/telephony/SignalStrength;->getAsuLevel()I
Landroid/telephony/SignalStrength;->getCdmaLevel()I
+Landroid/telephony/SignalStrength;->getDbm()I
Landroid/telephony/SignalStrength;->getLteDbm()I
Landroid/telephony/SignalStrength;->getLteRsrp()I
+Landroid/telephony/SignalStrength;->getLteRsrq()I
Landroid/telephony/SignalStrength;->getLteRssnr()I
Landroid/telephony/SignalStrength;->getLteSignalStrength()I
+Landroid/telephony/SignalStrength;->SIGNAL_STRENGTH_GOOD:I
+Landroid/telephony/SignalStrength;->SIGNAL_STRENGTH_GREAT:I
+Landroid/telephony/SignalStrength;->SIGNAL_STRENGTH_MODERATE:I
+Landroid/telephony/SignalStrength;->SIGNAL_STRENGTH_NONE_OR_UNKNOWN:I
+Landroid/telephony/SignalStrength;->SIGNAL_STRENGTH_POOR:I
Landroid/telephony/SmsManager;->RESULT_ERROR_FDN_CHECK_FAILURE:I
Landroid/telephony/SmsMessage;->getSubId()I
Landroid/telephony/SmsMessage;->mWrappedSmsMessage:Lcom/android/internal/telephony/SmsMessageBase;
+Landroid/telephony/SubscriptionManager;->getAllSubscriptionInfoCount()I
+Landroid/telephony/SubscriptionManager;->getDefaultDataSubscriptionInfo()Landroid/telephony/SubscriptionInfo;
Landroid/telephony/SubscriptionManager;->getDefaultSmsPhoneId()I
Landroid/telephony/SubscriptionManager;->getPhoneId(I)I
Landroid/telephony/SubscriptionManager;->getSlotIndex(I)I
@@ -913,26 +1530,43 @@
Landroid/telephony/SubscriptionManager;->setDefaultSmsSubId(I)V
Landroid/telephony/TelephonyManager;->checkCarrierPrivilegesForPackage(Ljava/lang/String;)I
Landroid/telephony/TelephonyManager;->from(Landroid/content/Context;)Landroid/telephony/TelephonyManager;
+Landroid/telephony/TelephonyManager;->getCallState(I)I
Landroid/telephony/TelephonyManager;->getCarrierPackageNamesForIntent(Landroid/content/Intent;)Ljava/util/List;
Landroid/telephony/TelephonyManager;->getCurrentPhoneType()I
Landroid/telephony/TelephonyManager;->getCurrentPhoneType(I)I
Landroid/telephony/TelephonyManager;->getDataEnabled(I)Z
Landroid/telephony/TelephonyManager;->getDataEnabled()Z
+Landroid/telephony/TelephonyManager;->getDataNetworkType(I)I
Landroid/telephony/TelephonyManager;->getDefault()Landroid/telephony/TelephonyManager;
+Landroid/telephony/TelephonyManager;->getGroupIdLevel1(I)Ljava/lang/String;
Landroid/telephony/TelephonyManager;->getITelephony()Lcom/android/internal/telephony/ITelephony;
Landroid/telephony/TelephonyManager;->getLine1Number(I)Ljava/lang/String;
+Landroid/telephony/TelephonyManager;->getMultiSimConfiguration()Landroid/telephony/TelephonyManager$MultiSimVariants;
Landroid/telephony/TelephonyManager;->getNetworkClass(I)I
Landroid/telephony/TelephonyManager;->getNetworkCountryIso(I)Ljava/lang/String;
+Landroid/telephony/TelephonyManager;->getNetworkOperatorForPhone(I)Ljava/lang/String;
Landroid/telephony/TelephonyManager;->getNetworkOperator(I)Ljava/lang/String;
Landroid/telephony/TelephonyManager;->getNetworkOperatorName(I)Ljava/lang/String;
Landroid/telephony/TelephonyManager;->getNetworkType(I)I
+Landroid/telephony/TelephonyManager;->getNetworkTypeName(I)Ljava/lang/String;
+Landroid/telephony/TelephonyManager;->getPhoneType(I)I
+Landroid/telephony/TelephonyManager;->getSimCount()I
Landroid/telephony/TelephonyManager;->getSimOperator(I)Ljava/lang/String;
+Landroid/telephony/TelephonyManager;->getSimOperatorNameForPhone(I)Ljava/lang/String;
Landroid/telephony/TelephonyManager;->getSimOperatorName(I)Ljava/lang/String;
+Landroid/telephony/TelephonyManager;->getSimOperatorNumericForPhone(I)Ljava/lang/String;
Landroid/telephony/TelephonyManager;->getSimSerialNumber(I)Ljava/lang/String;
+Landroid/telephony/TelephonyManager;->getSubIdForPhoneAccount(Landroid/telecom/PhoneAccount;)I
Landroid/telephony/TelephonyManager;->getSubscriberId(I)Ljava/lang/String;
+Landroid/telephony/TelephonyManager;->getSubscriberInfo()Lcom/android/internal/telephony/IPhoneSubInfo;
+Landroid/telephony/TelephonyManager;->hasIccCard(I)Z
+Landroid/telephony/TelephonyManager;-><init>(Landroid/content/Context;)V
+Landroid/telephony/TelephonyManager;-><init>()V
Landroid/telephony/TelephonyManager;->isMultiSimEnabled()Z
+Landroid/telephony/TelephonyManager;->isNetworkRoaming(I)Z
Landroid/telephony/TelephonyManager;->setDataEnabled(IZ)V
Landroid/text/AndroidBidi;->bidi(I[C[B)I
+Landroid/text/DynamicLayout;-><init>(Ljava/lang/CharSequence;Ljava/lang/CharSequence;Landroid/text/TextPaint;ILandroid/text/Layout$Alignment;Landroid/text/TextDirectionHeuristic;FFZIIILandroid/text/TextUtils$TruncateAt;I)V
Landroid/text/DynamicLayout;->sStaticLayout:Landroid/text/StaticLayout;
Landroid/text/Html;->withinStyle(Ljava/lang/StringBuilder;Ljava/lang/CharSequence;II)V
Landroid/text/Layout;->DIRS_ALL_LEFT_TO_RIGHT:Landroid/text/Layout$Directions;
@@ -975,64 +1609,158 @@
Landroid/text/SpannableStringInternal;->setSpan(Ljava/lang/Object;IIIZ)V
Landroid/text/SpannableStringInternal;->START:I
Landroid/text/StaticLayout;-><init>(Ljava/lang/CharSequence;IILandroid/text/TextPaint;ILandroid/text/Layout$Alignment;Landroid/text/TextDirectionHeuristic;FFZLandroid/text/TextUtils$TruncateAt;II)V
+Landroid/text/StaticLayout$LineBreaks;->ascents:[F
+Landroid/text/StaticLayout$LineBreaks;->breaks:[I
+Landroid/text/StaticLayout$LineBreaks;->descents:[F
+Landroid/text/StaticLayout$LineBreaks;->flags:[I
+Landroid/text/StaticLayout$LineBreaks;->widths:[F
Landroid/text/StaticLayout;->mColumns:I
Landroid/text/StaticLayout;->mLineCount:I
Landroid/text/StaticLayout;->mLines:[I
Landroid/text/TextLine;->obtain()Landroid/text/TextLine;
Landroid/text/TextLine;->sCached:[Landroid/text/TextLine;
Landroid/text/TextPaint;->setUnderlineText(IF)V
+Landroid/transition/ChangeBounds;->BOTTOM_RIGHT_ONLY_PROPERTY:Landroid/util/Property;
+Landroid/transition/ChangeBounds;->POSITION_PROPERTY:Landroid/util/Property;
+Landroid/util/ArrayMap;->mBaseCacheSize:I
+Landroid/util/ArrayMap;->mTwiceBaseCacheSize:I
+Landroid/util/DisplayMetrics;->noncompatHeightPixels:I
+Landroid/util/DisplayMetrics;->noncompatWidthPixels:I
+Landroid/util/EventLog$Event;-><init>([B)V
Landroid/util/Log;->wtf(ILjava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;ZZ)I
Landroid/util/Pools$SynchronizedPool;->acquire()Ljava/lang/Object;
+Landroid/util/Rational;->readObject(Ljava/io/ObjectInputStream;)V
+Landroid/util/Singleton;->mInstance:Ljava/lang/Object;
Landroid/view/accessibility/AccessibilityManager;->getInstance(Landroid/content/Context;)Landroid/view/accessibility/AccessibilityManager;
Landroid/view/accessibility/AccessibilityManager;->isHighTextContrastEnabled()Z
+Landroid/view/accessibility/AccessibilityManager;->mIsHighTextContrastEnabled:Z
Landroid/view/accessibility/AccessibilityManager;->sInstance:Landroid/view/accessibility/AccessibilityManager;
Landroid/view/accessibility/AccessibilityManager;->sInstanceSync:Ljava/lang/Object;
Landroid/view/accessibility/AccessibilityNodeInfo;->refresh(Landroid/os/Bundle;Z)Z
+Landroid/view/accessibility/IAccessibilityManager;->getEnabledAccessibilityServiceList(II)Ljava/util/List;
+Landroid/view/accessibility/IAccessibilityManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/view/accessibility/IAccessibilityManager;
+Landroid/view/accessibility/IAccessibilityManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/view/ActionMode;->isUiFocusable()Z
Landroid/view/animation/Animation;->mListener:Landroid/view/animation/Animation$AnimationListener;
Landroid/view/Choreographer;->doFrame(JI)V
Landroid/view/Choreographer;->getFrameTime()J
Landroid/view/Choreographer;->mCallbackQueues:[Landroid/view/Choreographer$CallbackQueue;
+Landroid/view/Choreographer;->mLastFrameTimeNanos:J
Landroid/view/Choreographer;->postCallback(ILjava/lang/Runnable;Ljava/lang/Object;)V
Landroid/view/Choreographer;->removeCallbacks(ILjava/lang/Runnable;Ljava/lang/Object;)V
Landroid/view/Choreographer;->scheduleVsyncLocked()V
+Landroid/view/Choreographer;->USE_VSYNC:Z
Landroid/view/ContextThemeWrapper;->mResources:Landroid/content/res/Resources;
Landroid/view/ContextThemeWrapper;->mTheme:Landroid/content/res/Resources$Theme;
Landroid/view/ContextThemeWrapper;->mThemeResource:I
+Landroid/view/DisplayEventReceiver;->dispatchHotplug(JIZ)V
+Landroid/view/DisplayEventReceiver;->dispatchVsync(JII)V
+Landroid/view/Display$HdrCapabilities;-><init>([IFFF)V
+Landroid/view/DisplayListCanvas;->callDrawGLFunction2(J)V
+Landroid/view/DisplayListCanvas;->drawGLFunctor2(JLjava/lang/Runnable;)V
+Landroid/view/FrameMetrics;->mTimingData:[J
+Landroid/view/FrameMetricsObserver;->mFrameMetrics:Landroid/view/FrameMetrics;
+Landroid/view/FrameMetricsObserver;->mMessageQueue:Landroid/os/MessageQueue;
+Landroid/view/FrameMetricsObserver;->notifyDataAvailable(I)V
+Landroid/view/GestureDetector;->mMinimumFlingVelocity:I
+Landroid/view/GestureDetector;->mTouchSlopSquare:I
+Landroid/view/GhostView;->addGhost(Landroid/view/View;Landroid/view/ViewGroup;Landroid/graphics/Matrix;)Landroid/view/GhostView;
+Landroid/view/GhostView;->removeGhost(Landroid/view/View;)V
+Landroid/view/IGraphicsStats$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
+Landroid/view/InputChannel;-><init>()V
+Landroid/view/InputChannel;->mPtr:J
+Landroid/view/InputDevice;->addMotionRange(IIFFFFF)V
+Landroid/view/InputDevice;-><init>(IIILjava/lang/String;IILjava/lang/String;ZIILandroid/view/KeyCharacterMap;ZZZ)V
Landroid/view/InputDevice;->isExternal()Z
+Landroid/view/InputEventReceiver;->dispatchBatchedInputEventPending()V
+Landroid/view/InputEventReceiver;->dispatchInputEvent(ILandroid/view/InputEvent;I)V
+Landroid/view/InputEventSender;->dispatchInputEventFinished(IZ)V
Landroid/view/inputmethod/InputMethodManager;->finishInputLocked()V
Landroid/view/inputmethod/InputMethodManager;->focusIn(Landroid/view/View;)V
Landroid/view/inputmethod/InputMethodManager;->getInputMethodWindowVisibleHeight()I
Landroid/view/inputmethod/InputMethodManager;->mCurId:Ljava/lang/String;
Landroid/view/inputmethod/InputMethodManager;->mCurRootView:Landroid/view/View;
+Landroid/view/inputmethod/InputMethodManager;->mH:Landroid/view/inputmethod/InputMethodManager$H;
Landroid/view/inputmethod/InputMethodManager;->mNextServedView:Landroid/view/View;
Landroid/view/inputmethod/InputMethodManager;->mServedView:Landroid/view/View;
+Landroid/view/inputmethod/InputMethodManager;->mService:Lcom/android/internal/view/IInputMethodManager;
Landroid/view/inputmethod/InputMethodManager;->notifyUserAction()V
Landroid/view/inputmethod/InputMethodManager;->showSoftInputUnchecked(ILandroid/os/ResultReceiver;)V
+Landroid/view/inputmethod/InputMethodManager;->sInstance:Landroid/view/inputmethod/InputMethodManager;
Landroid/view/inputmethod/InputMethodManager;->windowDismissed(Landroid/os/IBinder;)V
+Landroid/view/InputQueue;->finishInputEvent(JZ)V
Landroid/view/IWindowManager;->getAnimationScale(I)F
Landroid/view/IWindowManager;->hasNavigationBar()Z
Landroid/view/IWindowManager;->setAnimationScale(IF)V
Landroid/view/IWindowManager;->setStrictModeVisualIndicatorPreference(Ljava/lang/String;)V
Landroid/view/IWindowManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/view/IWindowManager;
+Landroid/view/IWindowManager$Stub$Proxy;->getBaseDisplayDensity(I)I
+Landroid/view/IWindowManager$Stub$Proxy;->getInitialDisplayDensity(I)I
+Landroid/view/IWindowManager$Stub$Proxy;->hasNavigationBar()Z
+Landroid/view/IWindowManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/view/IWindowSession$Stub$Proxy;->relayout(Landroid/view/IWindow;ILandroid/view/WindowManager$LayoutParams;IIIILandroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/view/DisplayCutout$ParcelableWrapper;Landroid/util/MergedConfiguration;Landroid/view/Surface;)I
+Landroid/view/KeyCharacterMap$FallbackAction;->keyCode:I
+Landroid/view/KeyCharacterMap$FallbackAction;->metaState:I
+Landroid/view/KeyCharacterMap;-><init>(J)V
+Landroid/view/KeyEvent;->mAction:I
+Landroid/view/KeyEvent;->mCharacters:Ljava/lang/String;
+Landroid/view/KeyEvent;->mDeviceId:I
+Landroid/view/KeyEvent;->mDownTime:J
+Landroid/view/KeyEvent;->mEventTime:J
+Landroid/view/KeyEvent;->mFlags:I
+Landroid/view/KeyEvent;->mKeyCode:I
+Landroid/view/KeyEvent;->mMetaState:I
+Landroid/view/KeyEvent;->mRepeatCount:I
+Landroid/view/KeyEvent;->mScanCode:I
+Landroid/view/KeyEvent;->mSource:I
+Landroid/view/KeyEvent;->obtain(JJIIIIIIIILjava/lang/String;)Landroid/view/KeyEvent;
+Landroid/view/KeyEvent;->recycle()V
Landroid/view/LayoutInflater;->createViewFromTag(Landroid/view/View;Ljava/lang/String;Landroid/content/Context;Landroid/util/AttributeSet;)Landroid/view/View;
Landroid/view/LayoutInflater;->createViewFromTag(Landroid/view/View;Ljava/lang/String;Landroid/content/Context;Landroid/util/AttributeSet;Z)Landroid/view/View;
Landroid/view/LayoutInflater;->mConstructorArgs:[Ljava/lang/Object;
+Landroid/view/LayoutInflater;->mContext:Landroid/content/Context;
Landroid/view/LayoutInflater;->mFactory2:Landroid/view/LayoutInflater$Factory2;
Landroid/view/LayoutInflater;->mFactory:Landroid/view/LayoutInflater$Factory;
Landroid/view/LayoutInflater;->mFactorySet:Z
+Landroid/view/LayoutInflater;->mPrivateFactory:Landroid/view/LayoutInflater$Factory2;
Landroid/view/LayoutInflater;->sConstructorMap:Ljava/util/HashMap;
Landroid/view/LayoutInflater;->setPrivateFactory(Landroid/view/LayoutInflater$Factory2;)V
Landroid/view/MotionEvent;->HISTORY_CURRENT:I
Landroid/view/MotionEvent;->mNativePtr:J
Landroid/view/MotionEvent;->nativeGetRawAxisValue(JIII)F
+Landroid/view/MotionEvent;->obtain()Landroid/view/MotionEvent;
+Landroid/view/MotionEvent$PointerCoords;->mPackedAxisBits:J
+Landroid/view/MotionEvent$PointerCoords;->mPackedAxisValues:[F
Landroid/view/MotionEvent;->scale(F)V
+Landroid/view/PointerIcon;->load(Landroid/content/Context;)Landroid/view/PointerIcon;
+Landroid/view/PointerIcon;->mBitmapFrames:[Landroid/graphics/Bitmap;
+Landroid/view/PointerIcon;->mBitmap:Landroid/graphics/Bitmap;
+Landroid/view/PointerIcon;->mDurationPerFrame:I
+Landroid/view/PointerIcon;->mHotSpotX:F
+Landroid/view/PointerIcon;->mHotSpotY:F
+Landroid/view/PointerIcon;->mType:I
+Landroid/view/RenderNodeAnimator;->callOnFinished(Landroid/view/RenderNodeAnimator;)V
Landroid/view/ScaleGestureDetector;->mListener:Landroid/view/ScaleGestureDetector$OnScaleGestureListener;
+Landroid/view/SurfaceControl$PhysicalDisplayInfo;->appVsyncOffsetNanos:J
+Landroid/view/SurfaceControl$PhysicalDisplayInfo;->density:F
+Landroid/view/SurfaceControl$PhysicalDisplayInfo;->height:I
+Landroid/view/SurfaceControl$PhysicalDisplayInfo;-><init>()V
+Landroid/view/SurfaceControl$PhysicalDisplayInfo;->presentationDeadlineNanos:J
+Landroid/view/SurfaceControl$PhysicalDisplayInfo;->refreshRate:F
+Landroid/view/SurfaceControl$PhysicalDisplayInfo;->secure:Z
+Landroid/view/SurfaceControl$PhysicalDisplayInfo;->width:I
+Landroid/view/SurfaceControl$PhysicalDisplayInfo;->xDpi:F
+Landroid/view/SurfaceControl$PhysicalDisplayInfo;->yDpi:F
+Landroid/view/Surface;-><init>(J)V
+Landroid/view/Surface;->mLock:Ljava/lang/Object;
+Landroid/view/Surface;->mNativeObject:J
+Landroid/view/SurfaceSession;->mNativeClient:J
Landroid/view/SurfaceView;->mCallbacks:Ljava/util/ArrayList;
Landroid/view/SurfaceView;->mFormat:I
Landroid/view/SurfaceView;->mRequestedFormat:I
Landroid/view/SurfaceView;->mSurfaceHolder:Landroid/view/SurfaceHolder;
+Landroid/view/SurfaceView;->surfacePositionLost_uiRtSync(J)V
+Landroid/view/SurfaceView;->updateSurfacePosition_renderWorker(JIIII)V
Landroid/view/textclassifier/logging/SmartSelectionEventTracker;-><init>(Landroid/content/Context;I)V
Landroid/view/textclassifier/logging/SmartSelectionEventTracker;->logEvent(Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;)V
Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;->selectionAction(III)Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;
@@ -1043,10 +1771,18 @@
Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;->selectionStarted(I)Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;
Landroid/view/textservice/TextServicesManager;->isSpellCheckerEnabled()Z
Landroid/view/TextureView;->mLayer:Landroid/view/HardwareLayer;
+Landroid/view/TextureView;->mNativeWindow:J
Landroid/view/TextureView;->mSurface:Landroid/graphics/SurfaceTexture;
Landroid/view/TextureView;->mUpdateListener:Landroid/graphics/SurfaceTexture$OnFrameAvailableListener;
Landroid/view/TouchDelegate;->mDelegateTargeted:Z
+Landroid/view/VelocityTracker$Estimator;->confidence:F
+Landroid/view/VelocityTracker$Estimator;->degree:I
+Landroid/view/VelocityTracker$Estimator;->xCoeff:[F
+Landroid/view/VelocityTracker$Estimator;->yCoeff:[F
Landroid/view/VelocityTracker;->obtain(Ljava/lang/String;)Landroid/view/VelocityTracker;
+Landroid/view/View;->applyDrawableToTransparentRegion(Landroid/graphics/drawable/Drawable;Landroid/graphics/Region;)V
+Landroid/view/View$AttachInfo;->mDrawingTime:J
+Landroid/view/View$AttachInfo;->mStableInsets:Landroid/graphics/Rect;
Landroid/view/View;->clearAccessibilityFocus()V
Landroid/view/View;->computeFitSystemWindows(Landroid/graphics/Rect;Landroid/graphics/Rect;)Z
Landroid/view/View;->computeOpaqueFlags()V
@@ -1059,28 +1795,37 @@
Landroid/view/View;->dispatchAttachedToWindow(Landroid/view/View$AttachInfo;I)V
Landroid/view/View;->dispatchDetachedFromWindow()V
Landroid/view/View;->fitsSystemWindows()Z
+Landroid/view/View;->getAccessibilityDelegate()Landroid/view/View$AccessibilityDelegate;
Landroid/view/View;->getListenerInfo()Landroid/view/View$ListenerInfo;
+Landroid/view/View;->getTransitionAlpha()F
Landroid/view/View;->getViewRootImpl()Landroid/view/ViewRootImpl;
+Landroid/view/ViewGroup;->dispatchViewAdded(Landroid/view/View;)V
+Landroid/view/ViewGroup;->dispatchViewRemoved(Landroid/view/View;)V
Landroid/view/ViewGroup;->FLAG_SUPPORT_STATIC_TRANSFORMATIONS:I
Landroid/view/ViewGroup;->FLAG_USE_CHILD_DRAWING_ORDER:I
Landroid/view/ViewGroup;->makeOptionalFitsSystemWindows()V
Landroid/view/ViewGroup$MarginLayoutParams;->endMargin:I
Landroid/view/ViewGroup$MarginLayoutParams;->startMargin:I
+Landroid/view/ViewGroup;->mChildrenCount:I
Landroid/view/ViewGroup;->mChildren:[Landroid/view/View;
Landroid/view/ViewGroup;->mFirstTouchTarget:Landroid/view/ViewGroup$TouchTarget;
Landroid/view/ViewGroup;->mGroupFlags:I
Landroid/view/ViewGroup;->mOnHierarchyChangeListener:Landroid/view/ViewGroup$OnHierarchyChangeListener;
+Landroid/view/ViewGroup;->suppressLayout(Z)V
Landroid/view/View;->initializeScrollbars(Landroid/content/res/TypedArray;)V
+Landroid/view/View;->internalSetPadding(IIII)V
Landroid/view/View;->isPaddingResolved()Z
Landroid/view/View;->isVisibleToUser(Landroid/graphics/Rect;)Z
Landroid/view/View;->isVisibleToUser()Z
Landroid/view/View$ListenerInfo;->mOnClickListener:Landroid/view/View$OnClickListener;
+Landroid/view/View$ListenerInfo;->mOnLongClickListener:Landroid/view/View$OnLongClickListener;
Landroid/view/View$ListenerInfo;->mOnTouchListener:Landroid/view/View$OnTouchListener;
Landroid/view/View;->mAccessibilityDelegate:Landroid/view/View$AccessibilityDelegate;
Landroid/view/View;->mAttachInfo:Landroid/view/View$AttachInfo;
Landroid/view/View;->mBottom:I
Landroid/view/View;->mContext:Landroid/content/Context;
Landroid/view/View;->mDrawingCache:Landroid/graphics/Bitmap;
+Landroid/view/View;->mLayoutParams:Landroid/view/ViewGroup$LayoutParams;
Landroid/view/View;->mLeft:I
Landroid/view/View;->mListenerInfo:Landroid/view/View$ListenerInfo;
Landroid/view/View;->mMinHeight:I
@@ -1099,6 +1844,7 @@
Landroid/view/View;->mTag:Ljava/lang/Object;
Landroid/view/View;->mTop:I
Landroid/view/View;->mUnscaledDrawingCache:Landroid/graphics/Bitmap;
+Landroid/view/View;->mViewFlags:I
Landroid/view/View;->notifySubtreeAccessibilityStateChangedIfNeeded()V
Landroid/view/View;->recomputePadding()V
Landroid/view/View;->requestAccessibilityFocus()Z
@@ -1106,9 +1852,15 @@
Landroid/view/ViewRootImpl;->detachFunctor(J)V
Landroid/view/ViewRootImpl;->invokeFunctor(JZ)V
Landroid/view/ViewRootImpl;->mStopped:Z
+Landroid/view/ViewRootImpl;->mView:Landroid/view/View;
+Landroid/view/View$ScrollabilityCache;->scrollBar:Landroid/widget/ScrollBarDrawable;
+Landroid/view/View;->setAlphaNoInvalidation(F)Z
+Landroid/view/View;->setAnimationMatrix(Landroid/graphics/Matrix;)V
Landroid/view/View;->setAssistBlocked(Z)V
Landroid/view/View;->setFrame(IIII)Z
Landroid/view/View;->setIsRootNamespace(Z)V
+Landroid/view/View;->setLeftTopRightBottom(IIII)V
+Landroid/view/View;->setTransitionAlpha(F)V
Landroid/view/View;->startActivityForResult(Landroid/content/Intent;I)V
Landroid/view/View;->STATUS_BAR_DISABLE_BACK:I
Landroid/view/View;->STATUS_BAR_DISABLE_EXPAND:I
@@ -1116,20 +1868,32 @@
Landroid/view/View;->STATUS_BAR_DISABLE_RECENT:I
Landroid/view/View;->toGlobalMotionEvent(Landroid/view/MotionEvent;)Z
Landroid/view/View;->toLocalMotionEvent(Landroid/view/MotionEvent;)Z
+Landroid/view/View;->transformMatrixToGlobal(Landroid/graphics/Matrix;)V
+Landroid/view/View;->transformMatrixToLocal(Landroid/graphics/Matrix;)V
Landroid/view/ViewTreeObserver;->addOnComputeInternalInsetsListener(Landroid/view/ViewTreeObserver$OnComputeInternalInsetsListener;)V
Landroid/view/ViewTreeObserver$InternalInsetsInfo;->setTouchableInsets(I)V
Landroid/view/ViewTreeObserver$InternalInsetsInfo;->TOUCHABLE_INSETS_REGION:I
Landroid/view/ViewTreeObserver$InternalInsetsInfo;->touchableRegion:Landroid/graphics/Region;
Landroid/view/ViewTreeObserver;->removeOnComputeInternalInsetsListener(Landroid/view/ViewTreeObserver$OnComputeInternalInsetsListener;)V
+Landroid/view/WindowAnimationFrameStats;->init(J[J)V
+Landroid/view/WindowContentFrameStats;->init(J[J[J[J)V
Landroid/view/WindowManagerGlobal;->getInstance()Landroid/view/WindowManagerGlobal;
Landroid/view/WindowManagerGlobal;->getRootView(Ljava/lang/String;)Landroid/view/View;
Landroid/view/WindowManagerGlobal;->getViewRootNames()[Ljava/lang/String;
Landroid/view/WindowManagerGlobal;->getWindowManagerService()Landroid/view/IWindowManager;
Landroid/view/WindowManagerGlobal;->mLock:Ljava/lang/Object;
+Landroid/view/WindowManagerGlobal;->mParams:Ljava/util/ArrayList;
+Landroid/view/WindowManagerGlobal;->mRoots:Ljava/util/ArrayList;
Landroid/view/WindowManagerGlobal;->mViews:Ljava/util/ArrayList;
+Landroid/view/WindowManagerGlobal;->sDefaultWindowManager:Landroid/view/WindowManagerGlobal;
+Landroid/view/WindowManagerGlobal;->sWindowManagerService:Landroid/view/IWindowManager;
+Landroid/view/WindowManagerGlobal;->sWindowSession:Landroid/view/IWindowSession;
Landroid/view/WindowManagerGlobal;->trimMemory(I)V
+Landroid/view/WindowManagerImpl;->mGlobal:Landroid/view/WindowManagerGlobal;
+Landroid/view/WindowManager$LayoutParams;->hideTimeoutMilliseconds:J
Landroid/view/WindowManager$LayoutParams;->needsMenuKey:I
Landroid/view/WindowManager$LayoutParams;->NEEDS_MENU_SET_TRUE:I
+Landroid/view/WindowManager$LayoutParams;->PRIVATE_FLAG_NO_MOVE_ANIMATION:I
Landroid/view/WindowManager$LayoutParams;->privateFlags:I
Landroid/view/WindowManager$LayoutParams;->userActivityTimeout:J
Landroid/view/Window;->mAppName:Ljava/lang/String;
@@ -1142,6 +1906,7 @@
Landroid/webkit/FindActionModeCallback;->showSoftInput()V
Landroid/webkit/GeolocationPermissions;-><init>()V
Landroid/webkit/HttpAuthHandler;-><init>()V
+Landroid/webkit/IWebViewUpdateService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/webkit/JsDialogHelper;-><init>(Landroid/webkit/JsPromptResult;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
Landroid/webkit/JsDialogHelper;->showDialog(Landroid/content/Context;)V
Landroid/webkit/JsPromptResult;->getStringResult()Ljava/lang/String;
@@ -1153,12 +1918,14 @@
Landroid/webkit/WebMessagePort;-><init>()V
Landroid/webkit/WebResourceError;-><init>()V
Landroid/webkit/WebResourceResponse;-><init>(ZLjava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/util/Map;Ljava/io/InputStream;)V
+Landroid/webkit/WebResourceResponse;->mImmutable:Z
Landroid/webkit/WebSettings;->getAcceptThirdPartyCookies()Z
Landroid/webkit/WebSettings;->setAcceptThirdPartyCookies(Z)V
Landroid/webkit/WebSettings;->setNavDump(Z)V
Landroid/webkit/WebSettings;->setPluginsEnabled(Z)V
Landroid/webkit/WebStorage;-><init>()V
Landroid/webkit/WebStorage$Origin;-><init>(Ljava/lang/String;JJ)V
+Landroid/webkit/WebSyncManager;->mHandler:Landroid/os/Handler;
Landroid/webkit/WebView;->debugDump()V
Landroid/webkit/WebViewDelegate;->addWebViewAssetPath(Landroid/content/Context;)V
Landroid/webkit/WebViewDelegate;->callDrawGlFunction(Landroid/graphics/Canvas;JLjava/lang/Runnable;)V
@@ -1178,8 +1945,12 @@
Landroid/webkit/WebView;->enablePlatformNotifications()V
Landroid/webkit/WebViewFactory;->getLoadedPackageInfo()Landroid/content/pm/PackageInfo;
Landroid/webkit/WebViewFactory;->getProvider()Landroid/webkit/WebViewFactoryProvider;
+Landroid/webkit/WebViewFactory;->getWebViewContextAndSetProvider()Landroid/content/Context;
Landroid/webkit/WebViewFactory;->loadWebViewNativeLibraryFromPackage(Ljava/lang/String;Ljava/lang/ClassLoader;)I
+Landroid/webkit/WebViewFactoryProvider;->getStatics()Landroid/webkit/WebViewFactoryProvider$Statics;
+Landroid/webkit/WebViewFactoryProvider$Statics;->getDefaultUserAgent(Landroid/content/Context;)Ljava/lang/String;
Landroid/webkit/WebViewFactory;->sPackageInfo:Landroid/content/pm/PackageInfo;
+Landroid/webkit/WebViewFactory;->sProviderInstance:Landroid/webkit/WebViewFactoryProvider;
Landroid/webkit/WebView;->getVisibleTitleHeight()I
Landroid/webkit/WebView;->getWebViewProvider()Landroid/webkit/WebViewProvider;
Landroid/webkit/WebView$HitTestResult;-><init>()V
@@ -1204,7 +1975,10 @@
Landroid/webkit/WebView;->restorePicture(Landroid/os/Bundle;Ljava/io/File;)Z
Landroid/webkit/WebView;->savePicture(Landroid/os/Bundle;Ljava/io/File;)Z
Landroid/webkit/WebView;->sEnforceThreadChecking:Z
+Landroid/webkit/WebViewUpdateService;->getCurrentWebViewPackageName()Ljava/lang/String;
Landroid/widget/AbsListView$FlingRunnable;->endFling()V
+Landroid/widget/AbsListView$FlingRunnable;->mScroller:Landroid/widget/OverScroller;
+Landroid/widget/AbsListView$FlingRunnable;->start(I)V
Landroid/widget/AbsListView;->invokeOnItemScrollListener()V
Landroid/widget/AbsListView;->isVerticalScrollBarHidden()Z
Landroid/widget/AbsListView;->mAdapter:Landroid/widget/ListAdapter;
@@ -1225,6 +1999,9 @@
Landroid/widget/AbsListView;->mVelocityTracker:Landroid/view/VelocityTracker;
Landroid/widget/AbsListView;->performLongPress(Landroid/view/View;IJFF)Z
Landroid/widget/AbsListView;->performLongPress(Landroid/view/View;IJ)Z
+Landroid/widget/AbsListView$RecycleBin;->clear()V
+Landroid/widget/AbsListView$RecycleBin;->mRecyclerListener:Landroid/widget/AbsListView$RecyclerListener;
+Landroid/widget/AbsListView;->reportScrollStateChange(I)V
Landroid/widget/AbsListView;->smoothScrollBy(IIZZ)V
Landroid/widget/AbsListView;->trackMotionScroll(II)Z
Landroid/widget/AbsSeekBar;->mIsDragging:Z
@@ -1233,6 +2010,7 @@
Landroid/widget/AbsSeekBar;->mTouchProgressOffset:F
Landroid/widget/ActivityChooserView;->setExpandActivityOverflowButtonDrawable(Landroid/graphics/drawable/Drawable;)V
Landroid/widget/AdapterView;->mDataChanged:Z
+Landroid/widget/AdapterView;->mFirstPosition:I
Landroid/widget/AdapterView;->setNextSelectedPositionInt(I)V
Landroid/widget/AdapterView;->setSelectedPositionInt(I)V
Landroid/widget/AutoCompleteTextView;->doAfterTextChanged()V
@@ -1247,23 +2025,41 @@
Landroid/widget/ExpandableListView;->mChildDivider:Landroid/graphics/drawable/Drawable;
Landroid/widget/FastScroller;->mThumbDrawable:Landroid/graphics/drawable/Drawable;
Landroid/widget/FastScroller;->mTrackDrawable:Landroid/graphics/drawable/Drawable;
+Landroid/widget/Gallery;->fillToGalleryLeft()V
+Landroid/widget/Gallery;->fillToGalleryRight()V
+Landroid/widget/Gallery$FlingRunnable;->startUsingVelocity(I)V
+Landroid/widget/Gallery;->makeAndAddView(IIIZ)Landroid/view/View;
+Landroid/widget/Gallery;->mDownTouchPosition:I
Landroid/widget/Gallery;->mDownTouchView:Landroid/view/View;
+Landroid/widget/Gallery;->mFlingRunnable:Landroid/widget/Gallery$FlingRunnable;
+Landroid/widget/Gallery;->moveDirection(I)Z
+Landroid/widget/Gallery;->mSpacing:I
+Landroid/widget/GridView;->fillDown(II)Landroid/view/View;
+Landroid/widget/GridView;->fillUp(II)Landroid/view/View;
Landroid/widget/GridView;->mColumnWidth:I
Landroid/widget/GridView;->mHorizontalSpacing:I
Landroid/widget/GridView;->mNumColumns:I
Landroid/widget/GridView;->mRequestedNumColumns:I
Landroid/widget/GridView;->mVerticalSpacing:I
+Landroid/widget/HorizontalScrollView;->mChildToScrollTo:Landroid/view/View;
Landroid/widget/HorizontalScrollView;->mEdgeGlowLeft:Landroid/widget/EdgeEffect;
Landroid/widget/HorizontalScrollView;->mEdgeGlowRight:Landroid/widget/EdgeEffect;
Landroid/widget/HorizontalScrollView;->mScroller:Landroid/widget/OverScroller;
Landroid/widget/ImageView;->mAdjustViewBounds:Z
Landroid/widget/ImageView;->mAlpha:I
+Landroid/widget/ImageView;->mDrawMatrix:Landroid/graphics/Matrix;
Landroid/widget/ImageView;->mMaxHeight:I
Landroid/widget/ImageView;->mMaxWidth:I
+Landroid/widget/ImageView;->mResource:I
+Landroid/widget/ImageView;->mUri:Landroid/net/Uri;
+Landroid/widget/ImageView;->updateDrawable(Landroid/graphics/drawable/Drawable;)V
Landroid/widget/LinearLayout;->mGravity:I
Landroid/widget/LinearLayout;->mUseLargestChild:Z
Landroid/widget/ListPopupWindow;->mPopup:Landroid/widget/PopupWindow;
Landroid/widget/ListPopupWindow;->setForceIgnoreOutsideTouch(Z)V
+Landroid/widget/ListView;->fillDown(II)Landroid/view/View;
+Landroid/widget/ListView;->fillSpecific(II)Landroid/view/View;
+Landroid/widget/ListView;->fillUp(II)Landroid/view/View;
Landroid/widget/ListView;->mAreAllItemsSelectable:Z
Landroid/widget/ListView;->setSelectionInt(I)V
Landroid/widget/MediaController;->mAnchor:Landroid/view/View;
@@ -1273,6 +2069,8 @@
Landroid/widget/NumberPicker;->mInputText:Landroid/widget/EditText;
Landroid/widget/NumberPicker;->mSelectionDivider:Landroid/graphics/drawable/Drawable;
Landroid/widget/NumberPicker;->mSelectorWheelPaint:Landroid/graphics/Paint;
+Landroid/widget/OverScroller;->mScrollerY:Landroid/widget/OverScroller$SplineOverScroller;
+Landroid/widget/OverScroller$SplineOverScroller;->mCurrVelocity:F
Landroid/widget/PopupMenu;->mPopup:Lcom/android/internal/view/menu/MenuPopupHelper;
Landroid/widget/PopupWindow;->computeAnimationResource()I
Landroid/widget/PopupWindow;->createPopupLayoutParams(Landroid/os/IBinder;)Landroid/view/WindowManager$LayoutParams;
@@ -1288,8 +2086,12 @@
Landroid/widget/PopupWindow;->mLastHeight:I
Landroid/widget/PopupWindow;->mLastWidth:I
Landroid/widget/PopupWindow;->mOnScrollChangedListener:Landroid/view/ViewTreeObserver$OnScrollChangedListener;
+Landroid/widget/PopupWindow;->mOverlapAnchor:Z
Landroid/widget/PopupWindow;->mWidthMode:I
+Landroid/widget/PopupWindow;->mWindowLayoutType:I
Landroid/widget/PopupWindow;->preparePopup(Landroid/view/WindowManager$LayoutParams;)V
+Landroid/widget/PopupWindow;->setClipToScreenEnabled(Z)V
+Landroid/widget/PopupWindow;->setEpicenterBounds(Landroid/graphics/Rect;)V
Landroid/widget/PopupWindow;->setLayoutInScreenEnabled(Z)V
Landroid/widget/PopupWindow;->setLayoutInsetDecor(Z)V
Landroid/widget/PopupWindow;->setTouchModal(Z)V
@@ -1306,9 +2108,16 @@
Landroid/widget/RelativeLayout;->mGravity:I
Landroid/widget/RemoteViews$Action;->mergeBehavior()I
Landroid/widget/RemoteViews$Action;->viewId:I
+Landroid/widget/RemoteViews$BitmapCache;->mBitmaps:Ljava/util/ArrayList;
Landroid/widget/RemoteViews;->mActions:Ljava/util/ArrayList;
Landroid/widget/RemoteViews;->mApplication:Landroid/content/pm/ApplicationInfo;
+Landroid/widget/RemoteViews;->mBitmapCache:Landroid/widget/RemoteViews$BitmapCache;
+Landroid/widget/RemoteViews;->mergeRemoteViews(Landroid/widget/RemoteViews;)V
Landroid/widget/RemoteViews$ReflectionAction;->methodName:Ljava/lang/String;
+Landroid/widget/ScrollBarDrawable;->mVerticalThumb:Landroid/graphics/drawable/Drawable;
+Landroid/widget/ScrollBarDrawable;->setHorizontalThumbDrawable(Landroid/graphics/drawable/Drawable;)V
+Landroid/widget/ScrollBarDrawable;->setVerticalThumbDrawable(Landroid/graphics/drawable/Drawable;)V
+Landroid/widget/ScrollView;->mChildToScrollTo:Landroid/view/View;
Landroid/widget/ScrollView;->mEdgeGlowBottom:Landroid/widget/EdgeEffect;
Landroid/widget/ScrollView;->mEdgeGlowTop:Landroid/widget/EdgeEffect;
Landroid/widget/ScrollView;->mIsBeingDragged:Z
@@ -1324,6 +2133,7 @@
Landroid/widget/Spinner;->mPopup:Landroid/widget/Spinner$SpinnerPopup;
Landroid/widget/Switch;->mThumbDrawable:Landroid/graphics/drawable/Drawable;
Landroid/widget/Switch;->mTrackDrawable:Landroid/graphics/drawable/Drawable;
+Landroid/widget/TabHost$TabSpec;->mContentStrategy:Landroid/widget/TabHost$ContentStrategy;
Landroid/widget/TabWidget;->setTabSelectionListener(Landroid/widget/TabWidget$OnTabSelectionChanged;)V
Landroid/widget/TextView;->assumeLayout()V
Landroid/widget/TextView;->createEditorIfNeeded()V
@@ -1335,14 +2145,21 @@
Landroid/widget/TextView;->mMaximum:I
Landroid/widget/TextView;->mMaxMode:I
Landroid/widget/TextView;->mSingleLine:Z
+Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;Landroid/widget/TextView$BufferType;ZI)V
+Landroid/widget/Toast;->getService()Landroid/app/INotificationManager;
+Landroid/widget/Toast;->sService:Landroid/app/INotificationManager;
Landroid/widget/VideoView;->mCurrentBufferPercentage:I
Landroid/widget/VideoView;->mMediaController:Landroid/widget/MediaController;
Landroid/widget/VideoView;->mSHCallback:Landroid/view/SurfaceHolder$Callback;
Landroid/widget/VideoView;->mUri:Landroid/net/Uri;
Landroid/widget/VideoView;->mVideoHeight:I
Landroid/widget/VideoView;->mVideoWidth:I
+Lcom/android/internal/app/IAppOpsService$Stub$Proxy;->checkOperation(IILjava/lang/String;)I
+Lcom/android/internal/app/IAppOpsService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Lcom/android/internal/app/IBatteryStats;->getStatistics()[B
Lcom/android/internal/app/IBatteryStats$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/app/IBatteryStats;
+Lcom/android/internal/app/IVoiceInteractionManagerService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/app/IVoiceInteractionManagerService;
+Lcom/android/internal/app/IVoiceInteractionManagerService$Stub$Proxy;->showSessionFromSession(Landroid/os/IBinder;Landroid/os/Bundle;I)Z
Lcom/android/internal/os/BatterySipper;->add(Lcom/android/internal/os/BatterySipper;)V
Lcom/android/internal/os/BatterySipper;->drainType:Lcom/android/internal/os/BatterySipper$DrainType;
Lcom/android/internal/os/BatterySipper;->getUid()I
@@ -1387,15 +2204,32 @@
Lcom/android/internal/os/PowerProfile;->getAveragePower(Ljava/lang/String;)D
Lcom/android/internal/os/PowerProfile;->getAveragePower(Ljava/lang/String;I)D
Lcom/android/internal/os/PowerProfile;->getBatteryCapacity()D
+Lcom/android/internal/os/PowerProfile;-><init>(Landroid/content/Context;)V
Lcom/android/internal/R$array;->config_mobile_hotspot_provision_app:I
Lcom/android/internal/R$array;->config_tether_wifi_regexs:I
+Lcom/android/internal/R$array;->maps_starting_lat_lng:I
+Lcom/android/internal/R$array;->maps_starting_zoom:I
+Lcom/android/internal/R$attr;->mapViewStyle:I
+Lcom/android/internal/R$attr;->state_focused:I
+Lcom/android/internal/R$attr;->state_pressed:I
+Lcom/android/internal/R$attr;->state_selected:I
Lcom/android/internal/R$attr;->switchStyle:I
Lcom/android/internal/R$bool;->config_mms_content_disposition_support:I
Lcom/android/internal/R$bool;->config_showNavigationBar:I
+Lcom/android/internal/R$dimen;-><init>()V
Lcom/android/internal/R$dimen;->navigation_bar_height:I
Lcom/android/internal/R$dimen;->navigation_bar_height_landscape:I
Lcom/android/internal/R$dimen;->status_bar_height:I
+Lcom/android/internal/R$dimen;->toast_y_offset:I
+Lcom/android/internal/R$drawable;->btn_check_off:I
+Lcom/android/internal/R$drawable;->compass_arrow:I
+Lcom/android/internal/R$drawable;->compass_base:I
+Lcom/android/internal/R$drawable;->ic_maps_indicator_current_position_anim:I
Lcom/android/internal/R$drawable;->ic_menu_close_clear_cancel:I
+Lcom/android/internal/R$drawable;->loading_tile_android:I
+Lcom/android/internal/R$drawable;->maps_google_logo:I
+Lcom/android/internal/R$drawable;->no_tile_256:I
+Lcom/android/internal/R$drawable;->reticle:I
Lcom/android/internal/R$id;->amPm:I
Lcom/android/internal/R$id;->edittext_container:I
Lcom/android/internal/R$id;->icon:I
@@ -1408,12 +2242,37 @@
Lcom/android/internal/R$id;->title_container:I
Lcom/android/internal/R$id;->title:I
Lcom/android/internal/R$integer;->config_screenBrightnessDim:I
+Lcom/android/internal/R$integer;->config_toastDefaultGravity:I
Lcom/android/internal/R$layout;->screen_title:I
+Lcom/android/internal/R$styleable;->AndroidManifestApplication_enabled:I
+Lcom/android/internal/R$styleable;->AndroidManifestApplication_hardwareAccelerated:I
+Lcom/android/internal/R$styleable;->AndroidManifestApplication:[I
+Lcom/android/internal/R$styleable;->AndroidManifestApplication_label:I
+Lcom/android/internal/R$styleable;->AndroidManifestApplication_largeHeap:I
+Lcom/android/internal/R$styleable;->AndroidManifestApplication_name:I
+Lcom/android/internal/R$styleable;->AndroidManifestApplication_permission:I
+Lcom/android/internal/R$styleable;->AndroidManifestApplication_process:I
+Lcom/android/internal/R$styleable;->AndroidManifestApplication_supportsRtl:I
+Lcom/android/internal/R$styleable;->AndroidManifestApplication_theme:I
+Lcom/android/internal/R$styleable;->AndroidManifestApplication_uiOptions:I
+Lcom/android/internal/R$styleable;->AndroidManifest:[I
+Lcom/android/internal/R$styleable;->AndroidManifest_installLocation:I
+Lcom/android/internal/R$styleable;->AndroidManifest_sharedUserId:I
+Lcom/android/internal/R$styleable;->AndroidManifestUsesPermission:[I
+Lcom/android/internal/R$styleable;->AndroidManifestUsesPermission_name:I
+Lcom/android/internal/R$styleable;->AndroidManifestUsesSdk:[I
+Lcom/android/internal/R$styleable;->AndroidManifestUsesSdk_minSdkVersion:I
+Lcom/android/internal/R$styleable;->AndroidManifestUsesSdk_targetSdkVersion:I
+Lcom/android/internal/R$styleable;->AndroidManifest_versionCode:I
+Lcom/android/internal/R$styleable;->AndroidManifest_versionName:I
Lcom/android/internal/R$styleable;->CompoundButton_button:I
Lcom/android/internal/R$styleable;->CompoundButton:[I
+Lcom/android/internal/R$styleable;->EdgeEffect_colorEdgeEffect:I
+Lcom/android/internal/R$styleable;->EdgeEffect:[I
Lcom/android/internal/R$styleable;->IconMenuView:[I
Lcom/android/internal/R$styleable;->ImageView:[I
Lcom/android/internal/R$styleable;->ImageView_src:I
+Lcom/android/internal/R$styleable;->ScrollView_fillViewport:I
Lcom/android/internal/R$styleable;->ScrollView:[I
Lcom/android/internal/R$styleable;->TabWidget:[I
Lcom/android/internal/R$styleable;->TextView_drawableBottom:I
@@ -1422,31 +2281,56 @@
Lcom/android/internal/R$styleable;->TextView_drawableTop:I
Lcom/android/internal/R$styleable;->TextView:[I
Lcom/android/internal/R$styleable;->View_background:I
+Lcom/android/internal/R$styleable;->ViewGroup_Layout:[I
+Lcom/android/internal/R$styleable;->ViewGroup_Layout_layout_height:I
+Lcom/android/internal/R$styleable;->ViewGroup_Layout_layout_width:I
Lcom/android/internal/R$styleable;->View:[I
Lcom/android/internal/R$styleable;->View_id:I
Lcom/android/internal/R$styleable;->ViewStub:[I
Lcom/android/internal/R$styleable;->ViewStub_inflatedId:I
Lcom/android/internal/R$styleable;->ViewStub_layout:I
Lcom/android/internal/R$styleable;->Window_windowActionBarFullscreenDecorLayout:I
+Lcom/android/internal/R$style;->Theme:I
Lcom/android/internal/R$xml;->power_profile:I
Lcom/android/internal/telephony/IPhoneSubInfo$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/IPhoneSubInfo;
+Lcom/android/internal/telephony/IPhoneSubInfo$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Lcom/android/internal/telephony/ISms$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/ISms;
+Lcom/android/internal/telephony/ISub$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Lcom/android/internal/telephony/ITelephony;->call(Ljava/lang/String;Ljava/lang/String;)V
Lcom/android/internal/telephony/ITelephony;->endCall()Z
Lcom/android/internal/telephony/ITelephony;->isIdle(Ljava/lang/String;)Z
Lcom/android/internal/telephony/ITelephony;->silenceRinger()V
Lcom/android/internal/telephony/ITelephony$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/ITelephony;
+Lcom/android/internal/telephony/ITelephony$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
+Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_getDeviceId:I
Lcom/android/internal/util/XmlUtils;->readMapXml(Ljava/io/InputStream;)Ljava/util/HashMap;
+Lcom/android/internal/view/IInputMethodManager$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/view/IInputMethodManager;
+Lcom/android/internal/view/IInputMethodManager$Stub$Proxy;->getEnabledInputMethodList()Ljava/util/List;
+Lcom/android/internal/view/IInputMethodManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Lcom/android/internal/view/InputBindResult;->CREATOR:Landroid/os/Parcelable$Creator;
Lcom/android/internal/view/menu/MenuBuilder;->mContext:Landroid/content/Context;
Lcom/android/internal/view/menu/MenuBuilder;->setCurrentMenuInfo(Landroid/view/ContextMenu$ContextMenuInfo;)V
Lcom/android/internal/view/menu/MenuBuilder;->setOptionalIconsVisible(Z)V
Lcom/android/internal/view/menu/MenuItemImpl;->mIconResId:I
Lcom/android/internal/view/menu/MenuItemImpl;->setMenuInfo(Landroid/view/ContextMenu$ContextMenuInfo;)V
+Lcom/android/internal/view/menu/MenuView$ItemView;->getItemData()Lcom/android/internal/view/menu/MenuItemImpl;
+Lcom/android/okhttp/ConnectionPool;->keepAliveDurationNs:J
Lcom/android/okhttp/ConnectionPool;->maxIdleConnections:I
Lcom/android/okhttp/ConnectionPool;->systemDefault:Lcom/android/okhttp/ConnectionPool;
+Lcom/android/okhttp/internal/http/HttpEngine;->httpStream:Lcom/android/okhttp/internal/http/HttpStream;
+Lcom/android/okhttp/OkHttpClient;->connectionPool:Lcom/android/okhttp/ConnectionPool;
+Lcom/android/okhttp/OkHttpClient;->DEFAULT_PROTOCOLS:Ljava/util/List;
+Lcom/android/okhttp/OkHttpClient;->dns:Lcom/android/okhttp/Dns;
+Lcom/android/okhttp/OkHttpClient;->setProtocols(Ljava/util/List;)Lcom/android/okhttp/OkHttpClient;
+Lcom/android/okhttp/okio/ByteString;->readObject(Ljava/io/ObjectInputStream;)V
+Lcom/android/okhttp/okio/ByteString;->writeObject(Ljava/io/ObjectOutputStream;)V
Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getAlpnSelectedProtocol()[B
+Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getNpnSelectedProtocol()[B
Lcom/android/org/conscrypt/OpenSSLSocketImpl;->setAlpnProtocols([B)V
+Lcom/android/org/conscrypt/OpenSSLSocketImpl;->setHostname(Ljava/lang/String;)V
+Lcom/android/org/conscrypt/OpenSSLSocketImpl;->setNpnProtocols([B)V
+Lcom/android/org/conscrypt/OpenSSLSocketImpl;->setUseSessionTickets(Z)V
+Lcom/android/org/conscrypt/TrustManagerImpl;-><init>(Ljava/security/KeyStore;)V
Ldalvik/system/BaseDexClassLoader;->getLdLibraryPath()Ljava/lang/String;
Ldalvik/system/BaseDexClassLoader;->pathList:Ldalvik/system/DexPathList;
Ldalvik/system/BlockGuard;->getThreadPolicy()Ldalvik/system/BlockGuard$Policy;
@@ -1459,15 +2343,22 @@
Ldalvik/system/DexFile;->mCookie:Ljava/lang/Object;
Ldalvik/system/DexFile;->mFileName:Ljava/lang/String;
Ldalvik/system/DexFile;->openDexFile(Ljava/lang/String;Ljava/lang/String;ILjava/lang/ClassLoader;[Ldalvik/system/DexPathList$Element;)Ljava/lang/Object;
+Ldalvik/system/DexPathList;->addDexPath(Ljava/lang/String;Ljava/io/File;)V
Ldalvik/system/DexPathList;->dexElements:[Ldalvik/system/DexPathList$Element;
Ldalvik/system/DexPathList$Element;->dexFile:Ldalvik/system/DexFile;
+Ldalvik/system/DexPathList$Element;-><init>(Ldalvik/system/DexFile;Ljava/io/File;)V
+Ldalvik/system/DexPathList$Element;-><init>(Ljava/io/File;ZLjava/io/File;Ldalvik/system/DexFile;)V
+Ldalvik/system/DexPathList;-><init>(Ljava/lang/ClassLoader;Ljava/lang/String;Ljava/lang/String;Ljava/io/File;)V
Ldalvik/system/DexPathList;->makeDexElements(Ljava/util/List;Ljava/io/File;Ljava/util/List;Ljava/lang/ClassLoader;)[Ldalvik/system/DexPathList$Element;
Ldalvik/system/DexPathList;->makePathElements(Ljava/util/List;)[Ldalvik/system/DexPathList$NativeLibraryElement;
Ldalvik/system/DexPathList;->makePathElements(Ljava/util/List;Ljava/io/File;Ljava/util/List;)[Ldalvik/system/DexPathList$Element;
Ldalvik/system/DexPathList;->nativeLibraryDirectories:Ljava/util/List;
+Ldalvik/system/DexPathList$NativeLibraryElement;-><init>(Ljava/io/File;)V
Ldalvik/system/DexPathList;->nativeLibraryPathElements:[Ldalvik/system/DexPathList$NativeLibraryElement;
+Ldalvik/system/DexPathList;->splitPaths(Ljava/lang/String;Z)Ljava/util/List;
Ldalvik/system/DexPathList;->systemNativeLibraryDirectories:Ljava/util/List;
Ldalvik/system/VMDebug;->dumpReferenceTables()V
+Ldalvik/system/VMRuntime;->addressOf(Ljava/lang/Object;)J
Ldalvik/system/VMRuntime;->clearGrowthLimit()V
Ldalvik/system/VMRuntime;->getCurrentInstructionSet()Ljava/lang/String;
Ldalvik/system/VMRuntime;->getRuntime()Ldalvik/system/VMRuntime;
@@ -1480,32 +2371,68 @@
Ldalvik/system/VMRuntime;->setTargetHeapUtilization(F)F
Ldalvik/system/VMRuntime;->trackExternalAllocation(J)Z
Ldalvik/system/VMRuntime;->trackExternalFree(J)V
+Ldalvik/system/VMRuntime;->vmInstructionSet()Ljava/lang/String;
+Ldalvik/system/VMRuntime;->vmLibrary()Ljava/lang/String;
Ldalvik/system/VMStack;->getCallingClassLoader()Ljava/lang/ClassLoader;
Ldalvik/system/VMStack;->getStackClass2()Ljava/lang/Class;
+Ljava/awt/font/NumericShaper;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/beans/PropertyChangeSupport;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/beans/PropertyChangeSupport;->writeObject(Ljava/io/ObjectOutputStream;)V
Ljava/io/FileDescriptor;->descriptor:I
Ljava/io/FileDescriptor;->getInt$()I
Ljava/io/FileDescriptor;->setInt$(I)V
+Ljava/io/FileInputStream;->fd:Ljava/io/FileDescriptor;
+Ljava/io/FileOutputStream;->fd:Ljava/io/FileDescriptor;
+Ljava/io/File;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/io/File;->writeObject(Ljava/io/ObjectOutputStream;)V
Ljava/io/ObjectStreamClass;->getConstructorId(Ljava/lang/Class;)J
Ljava/io/ObjectStreamClass;->newInstance(Ljava/lang/Class;J)Ljava/lang/Object;
Ljava/io/ObjectStreamClass;->newInstance()Ljava/lang/Object;
+Ljava/io/UncheckedIOException;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/lang/AbstractStringBuilder;->value:[C
+Ljava/lang/Boolean;->value:Z
+Ljava/lang/Byte;->value:B
+Ljava/lang/Character;->value:C
Ljava/lang/Class;->dexCache:Ljava/lang/Object;
Ljava/lang/Class;->dexClassDefIndex:I
Ljava/lang/ClassLoader;->parent:Ljava/lang/ClassLoader;
+Ljava/lang/Daemons$Daemon;->isRunning()Z
+Ljava/lang/Daemons$Daemon;->start()V
Ljava/lang/Daemons$Daemon;->stop()V
Ljava/lang/Daemons$Daemon;->thread:Ljava/lang/Thread;
Ljava/lang/Daemons$FinalizerDaemon;->finalizingObject:Ljava/lang/Object;
Ljava/lang/Daemons$FinalizerDaemon;->INSTANCE:Ljava/lang/Daemons$FinalizerDaemon;
Ljava/lang/Daemons$FinalizerWatchdogDaemon;->INSTANCE:Ljava/lang/Daemons$FinalizerWatchdogDaemon;
+Ljava/lang/Daemons;->MAX_FINALIZE_NANOS:J
+Ljava/lang/Daemons$ReferenceQueueDaemon;->INSTANCE:Ljava/lang/Daemons$ReferenceQueueDaemon;
Ljava/lang/Daemons;->requestHeapTrim()V
Ljava/lang/Daemons;->start()V
Ljava/lang/Daemons;->stop()V
+Ljava/lang/Double;->value:D
+Ljava/lang/Enum;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/lang/Float;->value:F
+Ljava/lang/Integer;->value:I
+Ljava/lang/invoke/MethodType;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/lang/invoke/MethodType;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/lang/Long;->value:J
Ljava/lang/ref/FinalizerReference;->add(Ljava/lang/Object;)V
+Ljava/lang/ref/FinalizerReference;->head:Ljava/lang/ref/FinalizerReference;
+Ljava/lang/ref/FinalizerReference;->next:Ljava/lang/ref/FinalizerReference;
+Ljava/lang/ref/FinalizerReference;->queue:Ljava/lang/ref/ReferenceQueue;
+Ljava/lang/ref/FinalizerReference;->remove(Ljava/lang/ref/FinalizerReference;)V
Ljava/lang/reflect/Executable;->artMethod:J
Ljava/lang/reflect/Parameter;-><init>(Ljava/lang/String;ILjava/lang/reflect/Executable;I)V
+Ljava/lang/reflect/Proxy;->invoke(Ljava/lang/reflect/Proxy;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;
Ljava/lang/ref/ReferenceQueue;->add(Ljava/lang/ref/Reference;)V
+Ljava/lang/ref/Reference;->referent:Ljava/lang/Object;
Ljava/lang/Runtime;->loadLibrary(Ljava/lang/String;Ljava/lang/ClassLoader;)V
Ljava/lang/Runtime;->load(Ljava/lang/String;Ljava/lang/ClassLoader;)V
Ljava/lang/Runtime;->nativeLoad(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/String;
+Ljava/lang/Short;->value:S
+Ljava/lang/StringBuffer;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/lang/StringBuffer;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/lang/StringBuilder;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/lang/StringBuilder;->writeObject(Ljava/io/ObjectOutputStream;)V
Ljava/lang/String;-><init>(II[C)V
Ljava/lang/Thread;->daemon:Z
Ljava/lang/Thread;->dispatchUncaughtException(Ljava/lang/Throwable;)V
@@ -1527,37 +2454,245 @@
Ljava/lang/Throwable;->backtrace:Ljava/lang/Object;
Ljava/lang/Throwable;->cause:Ljava/lang/Throwable;
Ljava/lang/Throwable;->detailMessage:Ljava/lang/String;
+Ljava/lang/Throwable;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/lang/Throwable;->stackTrace:[Ljava/lang/StackTraceElement;
Ljava/lang/Throwable;->suppressedExceptions:Ljava/util/List;
+Ljava/lang/Throwable;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/lang/Void;-><init>()V
+Ljava/math/BigDecimal;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/math/BigDecimal;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/math/BigInteger;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/math/BigInteger;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/math/MathContext;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/net/Authenticator;->theAuthenticator:Ljava/net/Authenticator;
Ljava/net/DatagramSocket;->impl:Ljava/net/DatagramSocketImpl;
+Ljava/net/HttpCookie;->httpOnly:Z
+Ljava/net/HttpCookie;->whenCreated:J
+Ljava/net/Inet4Address;-><init>()V
+Ljava/net/Inet6Address;->holder6:Ljava/net/Inet6Address$Inet6AddressHolder;
+Ljava/net/Inet6Address$Inet6AddressHolder;->ipaddress:[B
+Ljava/net/Inet6Address$Inet6AddressHolder;->scope_id:I
+Ljava/net/Inet6Address$Inet6AddressHolder;->scope_id_set:Z
+Ljava/net/Inet6Address$Inet6AddressHolder;->scope_ifname:Ljava/net/NetworkInterface;
+Ljava/net/Inet6Address;-><init>()V
+Ljava/net/Inet6Address;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/net/Inet6Address;->writeObject(Ljava/io/ObjectOutputStream;)V
Ljava/net/InetAddress;->clearDnsCache()V
+Ljava/net/InetAddress;->holder:Ljava/net/InetAddress$InetAddressHolder;
+Ljava/net/InetAddress$InetAddressHolder;->address:I
+Ljava/net/InetAddress$InetAddressHolder;->family:I
+Ljava/net/InetAddress$InetAddressHolder;->hostName:Ljava/lang/String;
+Ljava/net/InetAddress$InetAddressHolder;->originalHostName:Ljava/lang/String;
Ljava/net/InetAddress;->isNumeric(Ljava/lang/String;)Z
Ljava/net/InetAddress;->parseNumericAddress(Ljava/lang/String;)Ljava/net/InetAddress;
+Ljava/net/InetAddress;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/net/InetAddress;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/net/InetSocketAddress;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/net/InetSocketAddress;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/net/Socket;->getFileDescriptor$()Ljava/io/FileDescriptor;
Ljava/net/Socket;->impl:Ljava/net/SocketImpl;
Ljava/net/URI;->host:Ljava/lang/String;
+Ljava/net/URI;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/net/URI;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/net/URL;->handlers:Ljava/util/Hashtable;
+Ljava/net/URL;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/net/URL;->writeObject(Ljava/io/ObjectOutputStream;)V
Ljava/nio/Buffer;->address:J
Ljava/nio/Buffer;->capacity:I
+Ljava/nio/Buffer;->_elementSizeShift:I
Ljava/nio/Buffer;->limit:I
+Ljava/nio/Buffer;->position:I
Ljava/nio/ByteBuffer;->hb:[B
Ljava/nio/ByteBuffer;->isReadOnly:Z
Ljava/nio/ByteBuffer;->offset:I
Ljava/nio/charset/CharsetEncoder;->canEncode(Ljava/nio/CharBuffer;)Z
Ljava/nio/DirectByteBuffer;-><init>(JI)V
+Ljava/nio/file/DirectoryIteratorException;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/nio/NIOAccess;->getBaseArray(Ljava/nio/Buffer;)Ljava/lang/Object;
+Ljava/nio/NIOAccess;->getBaseArrayOffset(Ljava/nio/Buffer;)I
+Ljava/nio/NIOAccess;->getBasePointer(Ljava/nio/Buffer;)J
+Ljava/security/cert/CertificateRevokedException;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/security/cert/CertificateRevokedException;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/security/cert/CertPathValidatorException;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/security/CodeSigner;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/security/GuardedObject;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/security/Provider;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/security/SignedObject;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/security/spec/ECParameterSpec;->getCurveName()Ljava/lang/String;
Ljava/security/spec/ECParameterSpec;->setCurveName(Ljava/lang/String;)V
+Ljava/security/Timestamp;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/text/ChoiceFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/text/DateFormatSymbols;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/text/DateFormatSymbols;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/text/DecimalFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/text/DecimalFormatSymbols;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/text/DecimalFormatSymbols;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/text/DecimalFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/text/MessageFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/text/NumberFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/text/NumberFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/text/SimpleDateFormat;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/chrono/AbstractChronology;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/chrono/HijrahChronology;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/chrono/HijrahDate;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/chrono/IsoChronology;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/chrono/JapaneseChronology;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/chrono/JapaneseDate;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/chrono/JapaneseEra;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/chrono/MinguoChronology;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/chrono/MinguoDate;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/chrono/ThaiBuddhistChronology;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/chrono/ThaiBuddhistDate;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/Duration;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/Instant;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/LocalDate;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/LocalDateTime;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/LocalTime;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/MonthDay;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/OffsetDateTime;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/OffsetTime;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/Period;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/temporal/ValueRange;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/temporal/WeekFields;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/YearMonth;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/Year;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/ZonedDateTime;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/ZoneId;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/ZoneOffset;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/zone/ZoneOffsetTransition;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/zone/ZoneOffsetTransitionRule;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/time/zone/ZoneRules;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/ArrayDeque;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/ArrayDeque;->writeObject(Ljava/io/ObjectOutputStream;)V
Ljava/util/ArrayList;->elementData:[Ljava/lang/Object;
+Ljava/util/ArrayList;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/util/ArrayList;->size:I
Ljava/util/ArrayList$SubList;->parent:Ljava/util/AbstractList;
Ljava/util/ArrayList$SubList;->parentOffset:I
Ljava/util/ArrayList$SubList;->size:I
+Ljava/util/ArrayList;->writeObject(Ljava/io/ObjectOutputStream;)V
Ljava/util/Arrays$ArrayList;->a:[Ljava/lang/Object;
+Ljava/util/BitSet;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/BitSet;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/Calendar;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/Calendar;->writeObject(Ljava/io/ObjectOutputStream;)V
Ljava/util/Calendar;->zone:Ljava/util/TimeZone;
+Ljava/util/Collections$EmptyList;-><init>()V
+Ljava/util/Collections$SetFromMap;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/Collections$SynchronizedCollection;->c:Ljava/util/Collection;
+Ljava/util/Collections$SynchronizedCollection;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/Collections$SynchronizedMap;->m:Ljava/util/Map;
+Ljava/util/Collections$SynchronizedMap;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/Collections$UnmodifiableCollection;->c:Ljava/util/Collection;
+Ljava/util/Collections$UnmodifiableMap;->m:Ljava/util/Map;
+Ljava/util/concurrent/atomic/AtomicReferenceArray;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/concurrent/atomic/DoubleAccumulator;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/concurrent/atomic/DoubleAdder;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/concurrent/atomic/LongAccumulator;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/concurrent/atomic/LongAdder;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/concurrent/ConcurrentHashMap;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/concurrent/ConcurrentHashMap;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/concurrent/ConcurrentLinkedDeque;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/concurrent/ConcurrentLinkedDeque;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/concurrent/ConcurrentLinkedQueue;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/concurrent/ConcurrentLinkedQueue;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/concurrent/ConcurrentSkipListMap;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/concurrent/ConcurrentSkipListMap;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/concurrent/CopyOnWriteArrayList;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/concurrent/CopyOnWriteArrayList;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/concurrent/ForkJoinTask;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/concurrent/ForkJoinTask;->writeObject(Ljava/io/ObjectOutputStream;)V
Ljava/util/concurrent/FutureTask;->callable:Ljava/util/concurrent/Callable;
+Ljava/util/concurrent/LinkedBlockingDeque;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/concurrent/LinkedBlockingDeque;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/concurrent/LinkedBlockingQueue;->capacity:I
+Ljava/util/concurrent/LinkedBlockingQueue;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/concurrent/LinkedBlockingQueue;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/concurrent/LinkedTransferQueue;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/concurrent/LinkedTransferQueue;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/concurrent/locks/ReentrantLock$Sync;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/concurrent/locks/ReentrantReadWriteLock$Sync;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/concurrent/locks/StampedLock;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/concurrent/PriorityBlockingQueue;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/concurrent/PriorityBlockingQueue;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/concurrent/SynchronousQueue;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/concurrent/SynchronousQueue;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/concurrent/ThreadLocalRandom;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/Date;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/Date;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/EnumMap;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/EnumMap;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/EnumSet;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/GregorianCalendar;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/HashMap$HashIterator;->hasNext()Z
+Ljava/util/HashMap;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/HashMap;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/HashSet;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/HashSet;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/Hashtable;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/Hashtable;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/IdentityHashMap;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/IdentityHashMap;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/InvalidPropertiesFormatException;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/InvalidPropertiesFormatException;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/LinkedHashMap;->eldest()Ljava/util/Map$Entry;
+Ljava/util/LinkedList;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/LinkedList;->writeObject(Ljava/io/ObjectOutputStream;)V
Ljava/util/Locale;->createConstant(Ljava/lang/String;Ljava/lang/String;)Ljava/util/Locale;
+Ljava/util/Locale;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/Locale;->readResolve()Ljava/lang/Object;
+Ljava/util/Locale;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/logging/LogRecord;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/logging/LogRecord;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/prefs/NodeChangeEvent;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/prefs/NodeChangeEvent;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/prefs/PreferenceChangeEvent;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/prefs/PreferenceChangeEvent;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/PriorityQueue;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/PriorityQueue;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/Random;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/Random;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/regex/Matcher;->appendPos:I
+Ljava/util/regex/Pattern;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/SimpleTimeZone;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/SimpleTimeZone;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/TreeMap;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/TreeMap;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/TreeSet;->readObject(Ljava/io/ObjectInputStream;)V
+Ljava/util/TreeSet;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/Vector;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/zip/Deflater;->buf:[B
+Ljava/util/zip/Deflater;->finished:Z
+Ljava/util/zip/Deflater;->finish:Z
+Ljava/util/zip/Deflater;->len:I
+Ljava/util/zip/Deflater;->level:I
+Ljava/util/zip/Deflater;->off:I
+Ljava/util/zip/Deflater;->setParams:Z
+Ljava/util/zip/Deflater;->strategy:I
+Ljava/util/zip/Inflater;->buf:[B
+Ljava/util/zip/Inflater;->finished:Z
+Ljava/util/zip/Inflater;->len:I
+Ljava/util/zip/Inflater;->needDict:Z
+Ljava/util/zip/Inflater;->off:I
+Ljava/util/zip/ZipEntry;-><init>(Ljava/lang/String;Ljava/lang/String;JJJII[BJ)V
+Ljava/util/zip/ZipFile;->jzfile:J
+Ljavax/crypto/SealedObject;->readObject(Ljava/io/ObjectInputStream;)V
Ljavax/net/ssl/SSLServerSocketFactory;->defaultServerSocketFactory:Ljavax/net/ssl/SSLServerSocketFactory;
Ljavax/net/ssl/SSLSocketFactory;->defaultSocketFactory:Ljavax/net/ssl/SSLSocketFactory;
+Ljavax/security/auth/Subject;->readObject(Ljava/io/ObjectInputStream;)V
+Ljavax/security/auth/Subject$SecureSet;->readObject(Ljava/io/ObjectInputStream;)V
+Ljavax/security/auth/Subject$SecureSet;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljavax/security/auth/Subject;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljavax/security/auth/x500/X500Principal;->readObject(Ljava/io/ObjectInputStream;)V
+Ljavax/security/auth/x500/X500Principal;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljavax/xml/datatype/DatatypeConfigurationException;->readObject(Ljava/io/ObjectInputStream;)V
+Ljavax/xml/namespace/QName;->readObject(Ljava/io/ObjectInputStream;)V
Llibcore/util/ZoneInfo;->mTransitions:[J
+Llibcore/util/ZoneInfo;->readObject(Ljava/io/ObjectInputStream;)V
Lorg/apache/http/conn/ssl/SSLSocketFactory;-><init>(Ljavax/net/ssl/SSLSocketFactory;)V
+Lorg/apache/http/conn/ssl/SSLSocketFactory;-><init>()V
Lorg/json/JSONArray;->values:Ljava/util/List;
+Lorg/json/JSONObject;->writeTo(Lorg/json/JSONStringer;)V
Lsun/misc/Unsafe;->theUnsafe:Lsun/misc/Unsafe;
+Lsun/security/util/ObjectIdentifier;->readObject(Ljava/io/ObjectInputStream;)V
+Lsun/security/util/ObjectIdentifier;->writeObject(Ljava/io/ObjectOutputStream;)V
diff --git a/core/java/Android.bp b/core/java/Android.bp
index f7c5c57..fb27f74 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -7,33 +7,3 @@
name: "IDropBoxManagerService.aidl",
srcs: ["com/android/internal/os/IDropBoxManagerService.aidl"],
}
-
-// only used by key_store_service
-cc_library_shared {
- name: "libkeystore_aidl",
- srcs: ["android/security/IKeystoreService.aidl",
- "android/security/IConfirmationPromptCallback.aidl"],
- aidl: {
- export_aidl_headers: true,
- include_dirs: [
- "frameworks/base/core/java/",
- "system/security/keystore/",
- ],
- },
- shared_libs: [
- "libbinder",
- "libcutils",
- "libhardware",
- "libhidlbase",
- "libhidltransport",
- "libhwbinder",
- "liblog",
- "libkeystore_parcelables",
- "libselinux",
- "libutils",
- ],
- export_shared_lib_headers: [
- "libbinder",
- "libkeystore_parcelables",
- ],
-}
diff --git a/core/java/android/annotation/OWNERS b/core/java/android/annotation/OWNERS
new file mode 100644
index 0000000..d6bb71b
--- /dev/null
+++ b/core/java/android/annotation/OWNERS
@@ -0,0 +1 @@
+tnorbye@google.com
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 0bc510a..6c3d248 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1733,7 +1733,7 @@
*
* <p>This callback and {@link #onUserInteraction} are intended to help
* activities manage status bar notifications intelligently; specifically,
- * for helping activities determine the proper time to cancel a notfication.
+ * for helping activities determine the proper time to cancel a notification.
*
* @see #onUserInteraction()
*/
@@ -1741,32 +1741,16 @@
}
/**
- * Generate a new thumbnail for this activity. This method is called before
- * pausing the activity, and should draw into <var>outBitmap</var> the
- * imagery for the desired thumbnail in the dimensions of that bitmap. It
- * can use the given <var>canvas</var>, which is configured to draw into the
- * bitmap, for rendering if desired.
- *
- * <p>The default implementation returns fails and does not draw a thumbnail;
- * this will result in the platform creating its own thumbnail if needed.
- *
- * @param outBitmap The bitmap to contain the thumbnail.
- * @param canvas Can be used to render into the bitmap.
- *
- * @return Return true if you have drawn into the bitmap; otherwise after
- * you return it will be filled with a default thumbnail.
- *
- * @see #onCreateDescription
- * @see #onSaveInstanceState
- * @see #onPause
+ * @deprecated Method doesn't do anything and will be removed in the future.
*/
+ @Deprecated
public boolean onCreateThumbnail(Bitmap outBitmap, Canvas canvas) {
return false;
}
/**
* Generate a new description for this activity. This method is called
- * before pausing the activity and can, if desired, return some textual
+ * before stopping the activity and can, if desired, return some textual
* description of its current state to be displayed to the user.
*
* <p>The default implementation returns null, which will cause you to
@@ -1777,9 +1761,8 @@
* @return A description of what the user is doing. It should be short and
* sweet (only a few words).
*
- * @see #onCreateThumbnail
* @see #onSaveInstanceState
- * @see #onPause
+ * @see #onStop
*/
@Nullable
public CharSequence onCreateDescription() {
@@ -7179,8 +7162,8 @@
String appName = getApplicationInfo().loadLabel(getPackageManager())
.toString();
- String warning = "Detected problems with API compatiblity\n"
- + "(please consult log for detail)";
+ String warning = "Detected problems with API compatibility\n"
+ + "(visit g.co/dev/appcompat for more info)";
if (isAppDebuggable) {
new AlertDialog.Builder(this)
.setTitle(appName)
@@ -7768,7 +7751,6 @@
* @param disable {@code true} to disable preview screenshots; {@code false} otherwise.
* @hide
*/
- @SystemApi
public void setDisablePreviewScreenshots(boolean disable) {
try {
ActivityManager.getService().setDisablePreviewScreenshots(mToken, disable);
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index ae47a68..03faeee 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -44,6 +44,7 @@
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
+import android.net.Uri;
import android.os.BatteryStats;
import android.os.Binder;
import android.os.Build;
@@ -2750,6 +2751,30 @@
}
/**
+ * Updates (grants or revokes) a persitable URI permission.
+ *
+ * @param uri URI to be granted or revoked.
+ * @param prefix if {@code false}, permission apply to this specific URI; if {@code true}, it
+ * applies to all URIs that are prefixed by this URI.
+ * @param packageName target package.
+ * @param grant if {@code true} a new permission will be granted, otherwise an existing
+ * permission will be revoked.
+ *
+ * @return whether or not the requested succeeded.
+ *
+ * @hide
+ */
+ public boolean updatePersistableUriPermission(Uri uri, boolean prefix, String packageName,
+ boolean grant) {
+ try {
+ return getService().updatePersistableUriPermission(uri, prefix, packageName, grant,
+ UserHandle.myUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Information you can retrieve about any processes that are in an error condition.
*/
public static class ProcessErrorStateInfo implements Parcelable {
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 4626cb2..b365d52 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -219,6 +219,9 @@
/**
* Start activity {@code intents} as if {@code packageName} on user {@code userId} did it.
*
+ * - DO NOT call it with the calling UID cleared.
+ * - All the necessary caller permission checks must be done at callsites.
+ *
* @return error codes used by {@link IActivityManager#startActivity} and its siblings.
*/
public abstract int startActivitiesAsPackage(String packageName,
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index fee5827..d5430f0 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -1106,6 +1106,11 @@
}
/** @hide */
+ public void setRemoteAnimationAdapter(RemoteAnimationAdapter remoteAnimationAdapter) {
+ mRemoteAnimationAdapter = remoteAnimationAdapter;
+ }
+
+ /** @hide */
public static ActivityOptions fromBundle(Bundle bOptions) {
return bOptions != null ? new ActivityOptions(bOptions) : null;
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 5a63319..a69b0ee 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3904,62 +3904,6 @@
}
}
- private int mThumbnailWidth = -1;
- private int mThumbnailHeight = -1;
- private Bitmap mAvailThumbnailBitmap = null;
- private Canvas mThumbnailCanvas = null;
-
- private Bitmap createThumbnailBitmap(ActivityClientRecord r) {
- Bitmap thumbnail = mAvailThumbnailBitmap;
- try {
- if (thumbnail == null) {
- int w = mThumbnailWidth;
- int h;
- if (w < 0) {
- Resources res = r.activity.getResources();
- int wId = com.android.internal.R.dimen.thumbnail_width;
- int hId = com.android.internal.R.dimen.thumbnail_height;
- mThumbnailWidth = w = res.getDimensionPixelSize(wId);
- mThumbnailHeight = h = res.getDimensionPixelSize(hId);
- } else {
- h = mThumbnailHeight;
- }
-
- // On platforms where we don't want thumbnails, set dims to (0,0)
- if ((w > 0) && (h > 0)) {
- thumbnail = Bitmap.createBitmap(r.activity.getResources().getDisplayMetrics(),
- w, h, THUMBNAIL_FORMAT);
- thumbnail.eraseColor(0);
- }
- }
-
- if (thumbnail != null) {
- Canvas cv = mThumbnailCanvas;
- if (cv == null) {
- mThumbnailCanvas = cv = new Canvas();
- }
-
- cv.setBitmap(thumbnail);
- if (!r.activity.onCreateThumbnail(thumbnail, cv)) {
- mAvailThumbnailBitmap = thumbnail;
- thumbnail = null;
- }
- cv.setBitmap(null);
- }
-
- } catch (Exception e) {
- if (!mInstrumentation.onException(r.activity, e)) {
- throw new RuntimeException(
- "Unable to create thumbnail of "
- + r.intent.getComponent().toShortString()
- + ": " + e.toString(), e);
- }
- thumbnail = null;
- }
-
- return thumbnail;
- }
-
@Override
public void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving,
int configChanges, boolean dontReport, PendingTransactionActions pendingActions) {
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 02be002..f6e5f37 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -68,6 +68,7 @@
import android.service.voice.IVoiceInteractionSession;
import android.view.IRecentsAnimationRunner;
import android.view.RemoteAnimationDefinition;
+import android.view.RemoteAnimationAdapter;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.os.IResultReceiver;
import com.android.internal.policy.IKeyguardDismissCallback;
@@ -423,6 +424,8 @@
void restart();
void performIdleMaintenance();
void takePersistableUriPermission(in Uri uri, int modeFlags, int userId);
+ boolean updatePersistableUriPermission(in Uri uri, boolean prefix, String packageName,
+ boolean grant, int userId);
void releasePersistableUriPermission(in Uri uri, int modeFlags, int userId);
ParceledListSlice getPersistedUriPermissions(in String packageName, boolean incoming);
void appNotRespondingViaProvider(in IBinder connection);
@@ -696,4 +699,11 @@
* Registers remote animations for a specific activity.
*/
void registerRemoteAnimations(in IBinder token, in RemoteAnimationDefinition definition);
+
+ /**
+ * Registers a remote animation to be run for all activity starts from a certain package during
+ * a short predefined amount of time.
+ */
+ void registerRemoteAnimationForNextActivityStart(in String packageName,
+ in RemoteAnimationAdapter adapter);
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index c805658..e80610b 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -8862,6 +8862,7 @@
private static final String EXTRA_CONTENT_INTENT = "content_intent";
private static final String EXTRA_DELETE_INTENT = "delete_intent";
private static final String EXTRA_CHANNEL_ID = "channel_id";
+ private static final String EXTRA_SUPPRESS_SHOW_OVER_APPS = "suppressShowOverApps";
// Flags bitwise-ored to mFlags
private static final int FLAG_AVAILABLE_ON_TV = 0x1;
@@ -8870,6 +8871,7 @@
private String mChannelId;
private PendingIntent mContentIntent;
private PendingIntent mDeleteIntent;
+ private boolean mSuppressShowOverApps;
/**
* Create a {@link TvExtender} with default options.
@@ -8889,6 +8891,7 @@
if (bundle != null) {
mFlags = bundle.getInt(EXTRA_FLAGS);
mChannelId = bundle.getString(EXTRA_CHANNEL_ID);
+ mSuppressShowOverApps = bundle.getBoolean(EXTRA_SUPPRESS_SHOW_OVER_APPS);
mContentIntent = bundle.getParcelable(EXTRA_CONTENT_INTENT);
mDeleteIntent = bundle.getParcelable(EXTRA_DELETE_INTENT);
}
@@ -8905,6 +8908,7 @@
bundle.putInt(EXTRA_FLAGS, mFlags);
bundle.putString(EXTRA_CHANNEL_ID, mChannelId);
+ bundle.putBoolean(EXTRA_SUPPRESS_SHOW_OVER_APPS, mSuppressShowOverApps);
if (mContentIntent != null) {
bundle.putParcelable(EXTRA_CONTENT_INTENT, mContentIntent);
}
@@ -8997,6 +9001,23 @@
public PendingIntent getDeleteIntent() {
return mDeleteIntent;
}
+
+ /**
+ * Specifies whether this notification should suppress showing a message over top of apps
+ * outside of the launcher.
+ */
+ public TvExtender setSuppressShowOverApps(boolean suppress) {
+ mSuppressShowOverApps = suppress;
+ return this;
+ }
+
+ /**
+ * Returns true if this notification should not show messages over top of apps
+ * outside of the launcher.
+ */
+ public boolean getSuppressShowOverApps() {
+ return mSuppressShowOverApps;
+ }
}
/**
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index ea0fd75..256c479 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -471,6 +471,14 @@
* {@link #onStart} and returns either {@link #START_STICKY}
* or {@link #START_STICKY_COMPATIBILITY}.
*
+ * <p>If you need your application to run on platform versions prior to API
+ * level 5, you can use the following model to handle the older {@link #onStart}
+ * callback in that case. The <code>handleCommand</code> method is implemented by
+ * you as appropriate:
+ *
+ * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/ForegroundService.java
+ * start_compatibility}
+ *
* <p class="caution">Note that the system calls this on your
* service's main thread. A service's main thread is the same
* thread where UI operations take place for Activities running in the
@@ -679,10 +687,6 @@
* {@link #startService(Intent)} first to tell the system it should keep the service running,
* and then use this method to tell it to keep it running harder.</p>
*
- * <p>Apps targeting API {@link android.os.Build.VERSION_CODES#P} or later must request
- * the permission {@link android.Manifest.permission#FOREGROUND_SERVICE} in order to use
- * this API.</p>
- *
* @param id The identifier for this notification as per
* {@link NotificationManager#notify(int, Notification)
* NotificationManager.notify(int, Notification)}; must not be 0.
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index 28e845a..8c30fc4 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -19,6 +19,8 @@
import android.accounts.AccountManager;
import android.annotation.BroadcastBehavior;
import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
@@ -34,9 +36,6 @@
import android.os.UserHandle;
import android.security.KeyChain;
-import libcore.util.NonNull;
-import libcore.util.Nullable;
-
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -928,29 +927,29 @@
int networkLogsCount) {
}
- /**
- * Called when a user or profile is created.
- *
- * <p>This callback is only applicable to device owners.
- *
- * @param context The running context as per {@link #onReceive}.
- * @param intent The received intent as per {@link #onReceive}.
- * @param newUser The {@link UserHandle} of the user that has just been added.
- */
- public void onUserAdded(Context context, Intent intent, UserHandle newUser) {
- }
+ /**
+ * Called when a user or profile is created.
+ *
+ * <p>This callback is only applicable to device owners.
+ *
+ * @param context The running context as per {@link #onReceive}.
+ * @param intent The received intent as per {@link #onReceive}.
+ * @param newUser The {@link UserHandle} of the user that has just been added.
+ */
+ public void onUserAdded(Context context, Intent intent, @NonNull UserHandle newUser) {
+ }
- /**
- * Called when a user or profile is removed.
- *
- * <p>This callback is only applicable to device owners.
- *
- * @param context The running context as per {@link #onReceive}.
- * @param intent The received intent as per {@link #onReceive}.
- * @param removedUser The {@link UserHandle} of the user that has just been removed.
- */
- public void onUserRemoved(Context context, Intent intent, UserHandle removedUser) {
- }
+ /**
+ * Called when a user or profile is removed.
+ *
+ * <p>This callback is only applicable to device owners.
+ *
+ * @param context The running context as per {@link #onReceive}.
+ * @param intent The received intent as per {@link #onReceive}.
+ * @param removedUser The {@link UserHandle} of the user that has just been removed.
+ */
+ public void onUserRemoved(Context context, Intent intent, @NonNull UserHandle removedUser) {
+ }
/**
* Called when a user or profile is started.
@@ -961,7 +960,7 @@
* @param intent The received intent as per {@link #onReceive}.
* @param startedUser The {@link UserHandle} of the user that has just been started.
*/
- public void onUserStarted(Context context, Intent intent, UserHandle startedUser) {
+ public void onUserStarted(Context context, Intent intent, @NonNull UserHandle startedUser) {
}
/**
@@ -973,7 +972,7 @@
* @param intent The received intent as per {@link #onReceive}.
* @param stoppedUser The {@link UserHandle} of the user that has just been stopped.
*/
- public void onUserStopped(Context context, Intent intent, UserHandle stoppedUser) {
+ public void onUserStopped(Context context, Intent intent, @NonNull UserHandle stoppedUser) {
}
/**
@@ -985,7 +984,7 @@
* @param intent The received intent as per {@link #onReceive}.
* @param switchedUser The {@link UserHandle} of the user that has just been switched to.
*/
- public void onUserSwitched(Context context, Intent intent, UserHandle switchedUser) {
+ public void onUserSwitched(Context context, Intent intent, @NonNull UserHandle switchedUser) {
}
/**
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 77e118c..b29644b 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3444,9 +3444,6 @@
/**
* Flag for {@link #wipeData(int)}: also erase the device's eUICC data.
- *
- * TODO(b/35851809): make this public.
- * @hide
*/
public static final int WIPE_EUICC = 0x0004;
diff --git a/core/java/android/app/admin/FreezeInterval.java b/core/java/android/app/admin/FreezeInterval.java
index 7acdfc8..de5e21a 100644
--- a/core/java/android/app/admin/FreezeInterval.java
+++ b/core/java/android/app/admin/FreezeInterval.java
@@ -84,6 +84,10 @@
}
}
+ boolean after(LocalDate localDate) {
+ return mStartDay > dayOfYearDisregardLeapYear(localDate);
+ }
+
/**
* Instantiate the current interval to real calendar dates, given a calendar date
* {@code now}. If the interval contains now, the returned calendar dates should be the
@@ -161,7 +165,7 @@
* 3. At most one wrapped Interval remains, and it will be at the end of the list
* @hide
*/
- private static List<FreezeInterval> canonicalizeIntervals(List<FreezeInterval> intervals) {
+ protected static List<FreezeInterval> canonicalizeIntervals(List<FreezeInterval> intervals) {
boolean[] taken = new boolean[DAYS_IN_YEAR];
// First convert the intervals into flat array
for (FreezeInterval interval : intervals) {
diff --git a/core/java/android/app/admin/SecurityLog.java b/core/java/android/app/admin/SecurityLog.java
index 202b894..faaa004 100644
--- a/core/java/android/app/admin/SecurityLog.java
+++ b/core/java/android/app/admin/SecurityLog.java
@@ -78,6 +78,8 @@
TAG_CERT_AUTHORITY_INSTALLED,
TAG_CERT_AUTHORITY_REMOVED,
TAG_CRYPTO_SELF_TEST_COMPLETED,
+ TAG_KEY_INTEGRITY_VIOLATION,
+ TAG_CERT_VALIDATION_FAILURE,
})
public @interface SecurityLogTag {}
@@ -317,6 +319,7 @@
* {@link SecurityEvent#getData()}:
* <li> [0] admin package name ({@code String}),
* <li> [1] admin user ID ({@code Integer}).
+ * <li> [2] target user ID ({@code Integer})
*/
public static final int TAG_REMOTE_LOCK = SecurityLogTags.SECURITY_REMOTE_LOCK;
@@ -409,6 +412,23 @@
SecurityLogTags.SECURITY_CRYPTO_SELF_TEST_COMPLETED;
/**
+ * Indicates a failed cryptographic key integrity check. The log entry contains the following
+ * information about the event, encapsulated in an {@link Object} array and accessible via
+ * {@link SecurityEvent#getData()}:
+ * <li> [0] alias of the key ({@code String})
+ * <li> [1] owner application uid ({@code Integer}).
+ */
+ public static final int TAG_KEY_INTEGRITY_VIOLATION =
+ SecurityLogTags.SECURITY_KEY_INTEGRITY_VIOLATION;
+
+ /**
+ * Indicates a failure to validate X.509v3 certificate. The log entry contains a {@code String}
+ * payload indicating the failure reason, accessible via {@link SecurityEvent#getData()}.
+ */
+ public static final int TAG_CERT_VALIDATION_FAILURE =
+ SecurityLogTags.SECURITY_CERT_VALIDATION_FAILURE;
+
+ /**
* Event severity level indicating that the event corresponds to normal workflow.
*/
public static final int LEVEL_INFO = 1;
@@ -548,7 +568,10 @@
return getSuccess() ? LEVEL_INFO : LEVEL_WARNING;
case TAG_LOG_BUFFER_SIZE_CRITICAL:
case TAG_WIPE_FAILURE:
+ case TAG_KEY_INTEGRITY_VIOLATION:
return LEVEL_ERROR;
+ case TAG_CERT_VALIDATION_FAILURE:
+ return LEVEL_WARNING;
default:
return LEVEL_INFO;
}
diff --git a/core/java/android/app/admin/SecurityLogTags.logtags b/core/java/android/app/admin/SecurityLogTags.logtags
index b64b7e3..fe2519d 100644
--- a/core/java/android/app/admin/SecurityLogTags.logtags
+++ b/core/java/android/app/admin/SecurityLogTags.logtags
@@ -35,4 +35,6 @@
210028 security_user_restriction_removed (package|3),(admin_user|1),(restriction|3)
210029 security_cert_authority_installed (success|1),(subject|3)
210030 security_cert_authority_removed (success|1),(subject|3)
-210031 security_crypto_self_test_completed (success|1)
\ No newline at end of file
+210031 security_crypto_self_test_completed (success|1)
+210032 security_key_integrity_violation (key_id|3),(uid|1)
+210033 security_cert_validation_failure (reason|3)
diff --git a/core/java/android/app/admin/SystemUpdatePolicy.java b/core/java/android/app/admin/SystemUpdatePolicy.java
index 05d3fd9..47b3a81 100644
--- a/core/java/android/app/admin/SystemUpdatePolicy.java
+++ b/core/java/android/app/admin/SystemUpdatePolicy.java
@@ -21,6 +21,7 @@
import static org.xmlpull.v1.XmlPullParser.TEXT;
import android.annotation.IntDef;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
@@ -33,9 +34,15 @@
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.time.Instant;
import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneId;
import java.util.ArrayList;
+import java.util.Calendar;
import java.util.List;
+import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
@@ -103,6 +110,19 @@
*/
public static final int TYPE_POSTPONE = 3;
+ /**
+ * Incoming system updates (including security updates) should be blocked. This flag is not
+ * exposed to third-party apps (and any attempt to set it will raise exceptions). This is used
+ * to represent the current installation option type to the privileged system update clients,
+ * for example to indicate OTA freeze is currently in place or when system is outside a daily
+ * maintenance window.
+ *
+ * @see InstallationOption
+ * @hide
+ */
+ @SystemApi
+ public static final int TYPE_PAUSE = 4;
+
private static final String KEY_POLICY_TYPE = "policy_type";
private static final String KEY_INSTALL_WINDOW_START = "install_window_start";
private static final String KEY_INSTALL_WINDOW_END = "install_window_end";
@@ -460,6 +480,30 @@
return null;
}
+ /**
+ * Returns time (in milliseconds) until the start of the next freeze period, assuming now
+ * is not within a freeze period.
+ */
+ private long timeUntilNextFreezePeriod(long now) {
+ List<FreezeInterval> sortedPeriods = FreezeInterval.canonicalizeIntervals(mFreezePeriods);
+ LocalDate nowDate = millisToDate(now);
+ LocalDate nextFreezeStart = null;
+ for (FreezeInterval interval : sortedPeriods) {
+ if (interval.after(nowDate)) {
+ nextFreezeStart = interval.toCurrentOrFutureRealDates(nowDate).first;
+ break;
+ } else if (interval.contains(nowDate)) {
+ throw new IllegalArgumentException("Given date is inside a freeze period");
+ }
+ }
+ if (nextFreezeStart == null) {
+ // If no interval is after now, then it must be the one that starts at the beginning
+ // of next year
+ nextFreezeStart = sortedPeriods.get(0).toCurrentOrFutureRealDates(nowDate).first;
+ }
+ return dateToMillis(nextFreezeStart) - now;
+ }
+
/** @hide */
public void validateFreezePeriods() {
FreezeInterval.validatePeriods(mFreezePeriods);
@@ -472,6 +516,134 @@
prevPeriodEnd, now);
}
+ /**
+ * An installation option represents how system update clients should act on incoming system
+ * updates and how long this action is valid for, given the current system update policy. Its
+ * action could be one of the following
+ * <ul>
+ * <li> {@code TYPE_INSTALL_AUTOMATIC} system updates should be installed immedately and without
+ * user intervention as soon as they become available.
+ * <li> {@code TYPE_POSTPONE} system updates should be postponed for a maximum of 30 days
+ * <li> {@code TYPE_PAUSE} system updates should be postponed indefinitely until further notice
+ * </ul>
+ *
+ * The effective time measures how long this installation option is valid for from the queried
+ * time, in milliseconds.
+ *
+ * This is an internal API for system update clients.
+ * @hide
+ */
+ @SystemApi
+ public static class InstallationOption {
+ private final int mType;
+ private long mEffectiveTime;
+
+ InstallationOption(int type, long effectiveTime) {
+ this.mType = type;
+ this.mEffectiveTime = effectiveTime;
+ }
+
+ public int getType() {
+ return mType;
+ }
+
+ public long getEffectiveTime() {
+ return mEffectiveTime;
+ }
+
+ /** @hide */
+ protected void limitEffectiveTime(long otherTime) {
+ mEffectiveTime = Long.min(mEffectiveTime, otherTime);
+ }
+ }
+
+ /**
+ * Returns the installation option at the specified time, under the current
+ * {@code SystemUpdatePolicy} object. This is a convenience method for system update clients
+ * so they can instantiate this policy at any given time and find out what to do with incoming
+ * system updates, without the need of examining the overall policy structure.
+ *
+ * Normally the system update clients will query the current installation option by calling this
+ * method with the current timestamp, and act on the returned option until its effective time
+ * lapses. It can then query the latest option using a new timestamp. It should also listen
+ * for {@code DevicePolicyManager#ACTION_SYSTEM_UPDATE_POLICY_CHANGED} broadcast, in case the
+ * whole policy is updated.
+ *
+ * @param when At what time the intallation option is being queried, specified in number of
+ milliseonds since the epoch.
+ * @see InstallationOption
+ * @hide
+ */
+ @SystemApi
+ public InstallationOption getInstallationOptionAt(long when) {
+ LocalDate whenDate = millisToDate(when);
+ Pair<LocalDate, LocalDate> current = getCurrentFreezePeriod(whenDate);
+ if (current != null) {
+ return new InstallationOption(TYPE_PAUSE,
+ dateToMillis(roundUpLeapDay(current.second).plusDays(1)) - when);
+ }
+ // We are not within a freeze period, query the underlying policy.
+ // But also consider the start of the next freeze period, which might
+ // reduce the effective time of the current installation option
+ InstallationOption option = getInstallationOptionRegardlessFreezeAt(when);
+ if (mFreezePeriods.size() > 0) {
+ option.limitEffectiveTime(timeUntilNextFreezePeriod(when));
+ }
+ return option;
+ }
+
+ private InstallationOption getInstallationOptionRegardlessFreezeAt(long when) {
+ if (mPolicyType == TYPE_INSTALL_AUTOMATIC || mPolicyType == TYPE_POSTPONE) {
+ return new InstallationOption(mPolicyType, Long.MAX_VALUE);
+ } else if (mPolicyType == TYPE_INSTALL_WINDOWED) {
+ Calendar query = Calendar.getInstance();
+ query.setTimeInMillis(when);
+ // Calculate the number of milliseconds since midnight of the time specified by when
+ long whenMillis = TimeUnit.HOURS.toMillis(query.get(Calendar.HOUR_OF_DAY))
+ + TimeUnit.MINUTES.toMillis(query.get(Calendar.MINUTE))
+ + TimeUnit.SECONDS.toMillis(query.get(Calendar.SECOND))
+ + query.get(Calendar.MILLISECOND);
+ long windowStartMillis = TimeUnit.MINUTES.toMillis(mMaintenanceWindowStart);
+ long windowEndMillis = TimeUnit.MINUTES.toMillis(mMaintenanceWindowEnd);
+ final long dayInMillis = TimeUnit.DAYS.toMillis(1);
+
+ if ((windowStartMillis <= whenMillis && whenMillis <= windowEndMillis)
+ || ((windowStartMillis > windowEndMillis)
+ && (windowStartMillis <= whenMillis || whenMillis <= windowEndMillis))) {
+ return new InstallationOption(TYPE_INSTALL_AUTOMATIC,
+ (windowEndMillis - whenMillis + dayInMillis) % dayInMillis);
+ } else {
+ return new InstallationOption(TYPE_PAUSE,
+ (windowStartMillis - whenMillis + dayInMillis) % dayInMillis);
+ }
+ } else {
+ throw new RuntimeException("Unknown policy type");
+ }
+ }
+
+ private static LocalDate roundUpLeapDay(LocalDate date) {
+ if (date.isLeapYear() && date.getMonthValue() == 2 && date.getDayOfMonth() == 28) {
+ return date.plusDays(1);
+ } else {
+ return date;
+ }
+ }
+
+ /** Convert a timestamp since epoch to a LocalDate using default timezone, truncating
+ * the hour/min/seconds part.
+ */
+ private static LocalDate millisToDate(long when) {
+ return Instant.ofEpochMilli(when).atZone(ZoneId.systemDefault()).toLocalDate();
+ }
+
+ /**
+ * Returns the timestamp since epoch of a LocalDate, assuming the time is 00:00:00.
+ */
+ private static long dateToMillis(LocalDate when) {
+ return LocalDateTime.of(when, LocalTime.MIN).atZone(ZoneId.systemDefault()).toInstant()
+ .toEpochMilli();
+ }
+
@Override
public String toString() {
return String.format("SystemUpdatePolicy (type: %d, windowStart: %d, windowEnd: %d, "
@@ -480,11 +652,13 @@
mFreezePeriods.stream().map(n -> n.toString()).collect(Collectors.joining(",")));
}
+ @SystemApi
@Override
public int describeContents() {
return 0;
}
+ @SystemApi
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mPolicyType);
@@ -499,6 +673,7 @@
}
}
+ @SystemApi
public static final Parcelable.Creator<SystemUpdatePolicy> CREATOR =
new Parcelable.Creator<SystemUpdatePolicy>() {
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 0f1c249..1312a2e 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -1303,6 +1303,17 @@
}
/**
+ * @hide
+ */
+ public void setWebDomain(@Nullable String domain) {
+ if (domain == null) return;
+
+ final Uri uri = Uri.parse(domain);
+ mWebScheme = uri.getScheme();
+ mWebDomain = uri.getHost();
+ }
+
+ /**
* Returns the scheme of the HTML document represented by this view.
*
* <p>Typically used when the view associated with the view is a container for an HTML
@@ -1889,14 +1900,7 @@
@Override
public void setWebDomain(@Nullable String domain) {
- if (domain == null) {
- mNode.mWebScheme = null;
- mNode.mWebDomain = null;
- return;
- }
- Uri uri = Uri.parse(domain);
- mNode.mWebScheme = uri.getScheme();
- mNode.mWebDomain = uri.getHost();
+ mNode.setWebDomain(domain);
}
@Override
diff --git a/core/java/android/app/backup/OWNERS b/core/java/android/app/backup/OWNERS
new file mode 100644
index 0000000..1c9a43a
--- /dev/null
+++ b/core/java/android/app/backup/OWNERS
@@ -0,0 +1,7 @@
+artikz@google.com
+brufino@google.com
+bryanmawhinney@google.com
+ctate@google.com
+jorlow@google.com
+mkarpinski@google.com
+
diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java
index a1ad825c..ee13880 100644
--- a/core/java/android/app/job/JobInfo.java
+++ b/core/java/android/app/job/JobInfo.java
@@ -365,9 +365,7 @@
/** @hide */
public boolean isExemptedFromAppStandby() {
- return ((flags & FLAG_EXEMPT_FROM_APP_STANDBY) != 0)
- && !hasEarlyConstraint()
- && !hasLateConstraint();
+ return ((flags & FLAG_EXEMPT_FROM_APP_STANDBY) != 0) && !isPeriodic();
}
/**
diff --git a/core/java/android/app/servertransaction/ActivityLifecycleItem.java b/core/java/android/app/servertransaction/ActivityLifecycleItem.java
index 9a50a00..7f8c50c 100644
--- a/core/java/android/app/servertransaction/ActivityLifecycleItem.java
+++ b/core/java/android/app/servertransaction/ActivityLifecycleItem.java
@@ -91,4 +91,9 @@
pw.println(prefix + "target state:" + getTargetState());
pw.println(prefix + "description: " + mDescription);
}
+
+ @Override
+ public void recycle() {
+ setDescription(null);
+ }
}
diff --git a/core/java/android/app/servertransaction/DestroyActivityItem.java b/core/java/android/app/servertransaction/DestroyActivityItem.java
index 48a79f7..0edcf18 100644
--- a/core/java/android/app/servertransaction/DestroyActivityItem.java
+++ b/core/java/android/app/servertransaction/DestroyActivityItem.java
@@ -65,6 +65,7 @@
@Override
public void recycle() {
+ super.recycle();
mFinished = false;
mConfigChanges = 0;
ObjectPool.recycle(this);
diff --git a/core/java/android/app/servertransaction/PauseActivityItem.java b/core/java/android/app/servertransaction/PauseActivityItem.java
index 70a4755..91e73cd 100644
--- a/core/java/android/app/servertransaction/PauseActivityItem.java
+++ b/core/java/android/app/servertransaction/PauseActivityItem.java
@@ -102,6 +102,7 @@
@Override
public void recycle() {
+ super.recycle();
mFinished = false;
mUserLeaving = false;
mConfigChanges = 0;
diff --git a/core/java/android/app/servertransaction/ResumeActivityItem.java b/core/java/android/app/servertransaction/ResumeActivityItem.java
index ed90f2c..af2fb71 100644
--- a/core/java/android/app/servertransaction/ResumeActivityItem.java
+++ b/core/java/android/app/servertransaction/ResumeActivityItem.java
@@ -101,6 +101,7 @@
@Override
public void recycle() {
+ super.recycle();
mProcState = ActivityManager.PROCESS_STATE_UNKNOWN;
mUpdateProcState = false;
mIsForward = false;
diff --git a/core/java/android/app/servertransaction/StopActivityItem.java b/core/java/android/app/servertransaction/StopActivityItem.java
index b814d1a..f955a90 100644
--- a/core/java/android/app/servertransaction/StopActivityItem.java
+++ b/core/java/android/app/servertransaction/StopActivityItem.java
@@ -72,6 +72,7 @@
@Override
public void recycle() {
+ super.recycle();
mShowWindow = false;
mConfigChanges = 0;
ObjectPool.recycle(this);
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index bc7823b..1dc7549 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -2307,6 +2307,9 @@
} else if (profile == BluetoothProfile.HID_DEVICE) {
BluetoothHidDevice hidDevice = new BluetoothHidDevice(context, listener);
return true;
+ } else if (profile == BluetoothProfile.HEARING_AID) {
+ BluetoothHearingAid hearingAid = new BluetoothHearingAid(context, listener);
+ return true;
} else {
return false;
}
@@ -2389,6 +2392,9 @@
BluetoothHidDevice hidDevice = (BluetoothHidDevice) proxy;
hidDevice.close();
break;
+ case BluetoothProfile.HEARING_AID:
+ BluetoothHearingAid hearingAid = (BluetoothHearingAid) proxy;
+ hearingAid.close();
}
}
diff --git a/core/java/android/bluetooth/BluetoothHearingAid.java b/core/java/android/bluetooth/BluetoothHearingAid.java
new file mode 100644
index 0000000..647e0d0
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothHearingAid.java
@@ -0,0 +1,693 @@
+/*
+ * 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.bluetooth;
+
+import android.Manifest;
+import android.annotation.RequiresPermission;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * This class provides the public APIs to control the Bluetooth Hearing Aid
+ * profile.
+ *
+ * <p>BluetoothHearingAid is a proxy object for controlling the Bluetooth Hearing Aid
+ * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
+ * the BluetoothHearingAid proxy object.
+ *
+ * <p> Each method is protected with its appropriate permission.
+ * @hide
+ */
+public final class BluetoothHearingAid implements BluetoothProfile {
+ private static final String TAG = "BluetoothHearingAid";
+ private static final boolean DBG = false;
+ private static final boolean VDBG = false;
+
+ /**
+ * Intent used to broadcast the change in connection state of the Hearing Aid
+ * profile.
+ *
+ * <p>This intent will have 3 extras:
+ * <ul>
+ * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
+ * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
+ * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
+ * </ul>
+ *
+ * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
+ * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
+ * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
+ * receive.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_CONNECTION_STATE_CHANGED =
+ "android.bluetooth.hearingaid.profile.action.CONNECTION_STATE_CHANGED";
+
+ /**
+ * Intent used to broadcast the change in the Playing state of the Hearing Aid
+ * profile.
+ *
+ * <p>This intent will have 3 extras:
+ * <ul>
+ * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
+ * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile. </li>
+ * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
+ * </ul>
+ *
+ * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
+ * {@link #STATE_PLAYING}, {@link #STATE_NOT_PLAYING},
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
+ * receive.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_PLAYING_STATE_CHANGED =
+ "android.bluetooth.hearingaid.profile.action.PLAYING_STATE_CHANGED";
+
+ /**
+ * Intent used to broadcast the selection of a connected device as active.
+ *
+ * <p>This intent will have one extra:
+ * <ul>
+ * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. It can
+ * be null if no device is active. </li>
+ * </ul>
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
+ * receive.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_ACTIVE_DEVICE_CHANGED =
+ "android.bluetooth.hearingaid.profile.action.ACTIVE_DEVICE_CHANGED";
+
+ /**
+ * Hearing Aid device is streaming music. This state can be one of
+ * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
+ * {@link #ACTION_PLAYING_STATE_CHANGED} intent.
+ */
+ public static final int STATE_PLAYING = 10;
+
+ /**
+ * Hearing Aid device is NOT streaming music. This state can be one of
+ * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
+ * {@link #ACTION_PLAYING_STATE_CHANGED} intent.
+ */
+ public static final int STATE_NOT_PLAYING = 11;
+
+ /** This device represents Left Hearing Aid. */
+ public static final int SIDE_LEFT = IBluetoothHearingAid.SIDE_LEFT;
+
+ /** This device represents Right Hearing Aid. */
+ public static final int SIDE_RIGHT = IBluetoothHearingAid.SIDE_RIGHT;
+
+ /** This device is Monaural. */
+ public static final int MODE_MONAURAL = IBluetoothHearingAid.MODE_MONAURAL;
+
+ /** This device is Binaural (should receive only left or right audio). */
+ public static final int MODE_BINAURAL = IBluetoothHearingAid.MODE_BINAURAL;
+
+ /** Can't read ClientID for this device */
+ public static final long HI_SYNC_ID_INVALID = IBluetoothHearingAid.HI_SYNC_ID_INVALID;
+
+ private Context mContext;
+ private ServiceListener mServiceListener;
+ private final ReentrantReadWriteLock mServiceLock = new ReentrantReadWriteLock();
+ @GuardedBy("mServiceLock")
+ private IBluetoothHearingAid mService;
+ private BluetoothAdapter mAdapter;
+
+ private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
+ new IBluetoothStateChangeCallback.Stub() {
+ public void onBluetoothStateChange(boolean up) {
+ if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
+ if (!up) {
+ if (VDBG) Log.d(TAG, "Unbinding service...");
+ try {
+ mServiceLock.writeLock().lock();
+ mService = null;
+ mContext.unbindService(mConnection);
+ } catch (Exception re) {
+ Log.e(TAG, "", re);
+ } finally {
+ mServiceLock.writeLock().unlock();
+ }
+ } else {
+ try {
+ mServiceLock.readLock().lock();
+ if (mService == null) {
+ if (VDBG) Log.d(TAG, "Binding service...");
+ doBind();
+ }
+ } catch (Exception re) {
+ Log.e(TAG, "", re);
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+ }
+ };
+
+ /**
+ * Create a BluetoothHearingAid proxy object for interacting with the local
+ * Bluetooth Hearing Aid service.
+ */
+ /*package*/ BluetoothHearingAid(Context context, ServiceListener l) {
+ mContext = context;
+ mServiceListener = l;
+ mAdapter = BluetoothAdapter.getDefaultAdapter();
+ IBluetoothManager mgr = mAdapter.getBluetoothManager();
+ if (mgr != null) {
+ try {
+ mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ }
+ }
+
+ doBind();
+ }
+
+ void doBind() {
+ Intent intent = new Intent(IBluetoothHearingAid.class.getName());
+ ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
+ intent.setComponent(comp);
+ if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
+ android.os.Process.myUserHandle())) {
+ Log.e(TAG, "Could not bind to Bluetooth Hearing Aid Service with " + intent);
+ return;
+ }
+ }
+
+ /*package*/ void close() {
+ mServiceListener = null;
+ IBluetoothManager mgr = mAdapter.getBluetoothManager();
+ if (mgr != null) {
+ try {
+ mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
+ } catch (Exception e) {
+ Log.e(TAG, "", e);
+ }
+ }
+
+ try {
+ mServiceLock.writeLock().lock();
+ if (mService != null) {
+ mService = null;
+ mContext.unbindService(mConnection);
+ }
+ } catch (Exception re) {
+ Log.e(TAG, "", re);
+ } finally {
+ mServiceLock.writeLock().unlock();
+ }
+ }
+
+ @Override
+ public void finalize() {
+ // The empty finalize needs to be kept or the
+ // cts signature tests would fail.
+ }
+
+ /**
+ * Initiate connection to a profile of the remote bluetooth device.
+ *
+ * <p> This API returns false in scenarios like the profile on the
+ * device is already connected or Bluetooth is not turned on.
+ * When this API returns true, it is guaranteed that
+ * connection state intent for the profile will be broadcasted with
+ * the state. Users can get the connection state of the profile
+ * from this intent.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
+ * permission.
+ *
+ * @param device Remote Bluetooth Device
+ * @return false on immediate error, true otherwise
+ * @hide
+ */
+ public boolean connect(BluetoothDevice device) {
+ if (DBG) log("connect(" + device + ")");
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled() && isValidDevice(device)) {
+ return mService.connect(device);
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Initiate disconnection from a profile
+ *
+ * <p> This API will return false in scenarios like the profile on the
+ * Bluetooth device is not in connected state etc. When this API returns,
+ * true, it is guaranteed that the connection state change
+ * intent will be broadcasted with the state. Users can get the
+ * disconnection state of the profile from this intent.
+ *
+ * <p> If the disconnection is initiated by a remote device, the state
+ * will transition from {@link #STATE_CONNECTED} to
+ * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
+ * host (local) device the state will transition from
+ * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
+ * state {@link #STATE_DISCONNECTED}. The transition to
+ * {@link #STATE_DISCONNECTING} can be used to distinguish between the
+ * two scenarios.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
+ * permission.
+ *
+ * @param device Remote Bluetooth Device
+ * @return false on immediate error, true otherwise
+ * @hide
+ */
+ public boolean disconnect(BluetoothDevice device) {
+ if (DBG) log("disconnect(" + device + ")");
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled() && isValidDevice(device)) {
+ return mService.disconnect(device);
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<BluetoothDevice> getConnectedDevices() {
+ if (VDBG) log("getConnectedDevices()");
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()) {
+ return mService.getConnectedDevices();
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<BluetoothDevice>();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
+ if (VDBG) log("getDevicesMatchingStates()");
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()) {
+ return mService.getDevicesMatchingConnectionStates(states);
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<BluetoothDevice>();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int getConnectionState(BluetoothDevice device) {
+ if (VDBG) log("getState(" + device + ")");
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()
+ && isValidDevice(device)) {
+ return mService.getConnectionState(device);
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return BluetoothProfile.STATE_DISCONNECTED;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return BluetoothProfile.STATE_DISCONNECTED;
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Set priority of the profile
+ *
+ * <p> The device should already be paired.
+ * Priority can be one of {@link #PRIORITY_ON} orgetBluetoothManager
+ * {@link #PRIORITY_OFF},
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
+ * permission.
+ *
+ * @param device Paired bluetooth device
+ * @param priority
+ * @return true if priority is set, false on error
+ * @hide
+ */
+ public boolean setPriority(BluetoothDevice device, int priority) {
+ if (DBG) log("setPriority(" + device + ", " + priority + ")");
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()
+ && isValidDevice(device)) {
+ if (priority != BluetoothProfile.PRIORITY_OFF
+ && priority != BluetoothProfile.PRIORITY_ON) {
+ return false;
+ }
+ return mService.setPriority(device, priority);
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Get the priority of the profile.
+ *
+ * <p> The priority can be any of:
+ * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
+ * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
+ *
+ * @param device Bluetooth device
+ * @return priority of the device
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
+ public int getPriority(BluetoothDevice device) {
+ if (VDBG) log("getPriority(" + device + ")");
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()
+ && isValidDevice(device)) {
+ return mService.getPriority(device);
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return BluetoothProfile.PRIORITY_OFF;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return BluetoothProfile.PRIORITY_OFF;
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Helper for converting a state to a string.
+ *
+ * For debug use only - strings are not internationalized.
+ *
+ * @hide
+ */
+ public static String stateToString(int state) {
+ switch (state) {
+ case STATE_DISCONNECTED:
+ return "disconnected";
+ case STATE_CONNECTING:
+ return "connecting";
+ case STATE_CONNECTED:
+ return "connected";
+ case STATE_DISCONNECTING:
+ return "disconnecting";
+ case STATE_PLAYING:
+ return "playing";
+ case STATE_NOT_PLAYING:
+ return "not playing";
+ default:
+ return "<unknown state " + state + ">";
+ }
+ }
+
+ /**
+ * Get the volume of the device.
+ *
+ * <p> The volume is between -128 dB (mute) to 0 dB.
+ *
+ * @return volume of the hearing aid device.
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
+ public int getVolume() {
+ if (VDBG) {
+ log("getVolume()");
+ }
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()) {
+ return mService.getVolume();
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return 0;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return 0;
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Tells remote device to adjust volume. Uses the following values:
+ * <ul>
+ * <li>{@link AudioManager#ADJUST_LOWER}</li>
+ * <li>{@link AudioManager#ADJUST_RAISE}</li>
+ * <li>{@link AudioManager#ADJUST_MUTE}</li>
+ * <li>{@link AudioManager#ADJUST_UNMUTE}</li>
+ * </ul>
+ *
+ * @param direction One of the supported adjust values.
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
+ public void adjustVolume(int direction) {
+ if (DBG) log("adjustVolume(" + direction + ")");
+
+ try {
+ mServiceLock.readLock().lock();
+
+ if (mService == null) {
+ Log.w(TAG, "Proxy not attached to service");
+ return;
+ }
+
+ if (!isEnabled()) return;
+
+ mService.adjustVolume(direction);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Tells remote device to set an absolute volume.
+ *
+ * @param volume Absolute volume to be set on remote
+ * @hide
+ */
+ public void setVolume(int volume) {
+ if (DBG) Log.d(TAG, "setVolume(" + volume + ")");
+
+ try {
+ mServiceLock.readLock().lock();
+ if (mService == null) {
+ Log.w(TAG, "Proxy not attached to service");
+ return;
+ }
+
+ if (!isEnabled()) return;
+
+ mService.setVolume(volume);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Get the CustomerId of the device.
+ *
+ * @param device Bluetooth device
+ * @return the CustomerId of the device
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
+ public long getHiSyncId(BluetoothDevice device) {
+ if (VDBG) {
+ log("getCustomerId(" + device + ")");
+ }
+ try {
+ mServiceLock.readLock().lock();
+ if (mService == null) {
+ Log.w(TAG, "Proxy not attached to service");
+ return HI_SYNC_ID_INVALID;
+ }
+
+ if (!isEnabled() || !isValidDevice(device)) return HI_SYNC_ID_INVALID;
+
+ return mService.getHiSyncId(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return HI_SYNC_ID_INVALID;
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Get the side of the device.
+ *
+ * @param device Bluetooth device.
+ * @return SIDE_LEFT or SIDE_RIGHT
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
+ public int getDeviceSide(BluetoothDevice device) {
+ if (VDBG) {
+ log("getDeviceSide(" + device + ")");
+ }
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()
+ && isValidDevice(device)) {
+ return mService.getDeviceSide(device);
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return SIDE_LEFT;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return SIDE_LEFT;
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Get the mode of the device.
+ *
+ * @param device Bluetooth device
+ * @return MODE_MONAURAL or MODE_BINAURAL
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
+ public int getDeviceMode(BluetoothDevice device) {
+ if (VDBG) {
+ log("getDeviceMode(" + device + ")");
+ }
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()
+ && isValidDevice(device)) {
+ return mService.getDeviceMode(device);
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return MODE_MONAURAL;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return MODE_MONAURAL;
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ }
+
+ private final ServiceConnection mConnection = new ServiceConnection() {
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ if (DBG) Log.d(TAG, "Proxy object connected");
+ try {
+ mServiceLock.writeLock().lock();
+ mService = IBluetoothHearingAid.Stub.asInterface(Binder.allowBlocking(service));
+ } finally {
+ mServiceLock.writeLock().unlock();
+ }
+
+ if (mServiceListener != null) {
+ mServiceListener.onServiceConnected(BluetoothProfile.HEARING_AID,
+ BluetoothHearingAid.this);
+ }
+ }
+
+ public void onServiceDisconnected(ComponentName className) {
+ if (DBG) Log.d(TAG, "Proxy object disconnected");
+ try {
+ mServiceLock.writeLock().lock();
+ mService = null;
+ } finally {
+ mServiceLock.writeLock().unlock();
+ }
+ if (mServiceListener != null) {
+ mServiceListener.onServiceDisconnected(BluetoothProfile.HEARING_AID);
+ }
+ }
+ };
+
+ private boolean isEnabled() {
+ if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
+ return false;
+ }
+
+ private boolean isValidDevice(BluetoothDevice device) {
+ if (device == null) return false;
+
+ if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
+ return false;
+ }
+
+ private static void log(String msg) {
+ Log.d(TAG, msg);
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index 0e2263f..656188f 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -165,12 +165,19 @@
public static final int OPP = 20;
/**
+ * Hearing Aid Device
+ *
+ * @hide
+ */
+ int HEARING_AID = 21;
+
+ /**
* Max profile ID. This value should be updated whenever a new profile is added to match
* the largest value assigned to a profile.
*
* @hide
*/
- public static final int MAX_PROFILE_ID = 20;
+ int MAX_PROFILE_ID = 21;
/**
* Default priority for devices that we try to auto-connect to and
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index 76cb3f5..0a0d214 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -79,6 +79,9 @@
ParcelUuid.fromString("00001132-0000-1000-8000-00805F9B34FB");
public static final ParcelUuid SAP =
ParcelUuid.fromString("0000112D-0000-1000-8000-00805F9B34FB");
+ /* TODO: b/69623109 update this value. It will change to 16bit UUID!! */
+ public static final ParcelUuid HearingAid =
+ ParcelUuid.fromString("7312C48F-22CC-497F-85FD-A0616A3B9E05");
public static final ParcelUuid BASE_UUID =
ParcelUuid.fromString("00000000-0000-1000-8000-00805F9B34FB");
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 15f3777..a738312 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3671,10 +3671,8 @@
*
* @see #getSystemService(String)
* @see android.telephony.euicc.EuiccManager
- * TODO(b/35851809): Unhide this API.
- * @hide
*/
- public static final String EUICC_SERVICE = "euicc_service";
+ public static final String EUICC_SERVICE = "euicc";
/**
* Use with {@link #getSystemService(String)} to retrieve a
@@ -3682,10 +3680,10 @@
*
* @see #getSystemService(String)
* @see android.telephony.euicc.EuiccCardManager
- * TODO(b/35851809): Make this a SystemApi.
* @hide
*/
- public static final String EUICC_CARD_SERVICE = "euicc_card_service";
+ @SystemApi
+ public static final String EUICC_CARD_SERVICE = "euicc_card";
/**
* Use with {@link #getSystemService(String)} to retrieve a
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 12d4079..e7aead1 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2498,6 +2498,9 @@
* off, not sleeping). Once the broadcast is complete, the final shutdown
* will proceed and all unsaved data lost. Apps will not normally need
* to handle this, since the foreground activity will be paused as well.
+ * <p>As of {@link Build.VERSION_CODES#P} this broadcast is only sent to receivers registered
+ * through {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
+ * Context.registerReceiver}.
*
* <p class="note">This is a protected intent that can only be sent
* by the system.
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 486c86c..07a9911 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2070,6 +2070,15 @@
"android.hardware.sensor.hifi_sensors";
/**
+ * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
+ * The device supports a hardware mechanism for invoking an assist gesture.
+ * @see android.provider.Settings.Secure#ASSIST_GESTURE_ENABLED
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_ASSIST_GESTURE = "android.hardware.sensor.assist";
+
+ /**
* Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: The device has a telephony radio with data
* communication support.
@@ -2108,8 +2117,6 @@
/**
* Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device
* supports embedded subscriptions on eUICCs.
- * TODO(b/35851809): Make this public.
- * @hide
*/
@SdkConstant(SdkConstantType.FEATURE)
public static final String FEATURE_TELEPHONY_EUICC = "android.hardware.telephony.euicc";
@@ -5067,6 +5074,7 @@
* which market the package came from.
*
* @param packageName The name of the package to query
+ * @throws IllegalArgumentException if the given package name is not installed
*/
public abstract String getInstallerPackageName(String packageName);
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index 91dd7ee..cf01451 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -912,7 +912,7 @@
* first try to load CSL from the cache. If not found, try to get from the constant state.
* Last, parse the XML and generate the CSL.
*/
- @NonNull
+ @Nullable
private ComplexColor loadComplexColorFromName(Resources wrapper, Resources.Theme theme,
TypedValue value, int id) {
final long key = (((long) value.assetCookie) << 32) | value.data;
@@ -932,15 +932,17 @@
complexColor = loadComplexColorForCookie(wrapper, value, id, theme);
}
- complexColor.setBaseChangingConfigurations(value.changingConfigurations);
+ if (complexColor != null) {
+ complexColor.setBaseChangingConfigurations(value.changingConfigurations);
- if (mPreloading) {
- if (verifyPreloadConfig(complexColor.getChangingConfigurations(),
- 0, value.resourceId, "color")) {
- sPreloadedComplexColors.put(key, complexColor.getConstantState());
+ if (mPreloading) {
+ if (verifyPreloadConfig(complexColor.getChangingConfigurations(),
+ 0, value.resourceId, "color")) {
+ sPreloadedComplexColors.put(key, complexColor.getConstantState());
+ }
+ } else {
+ cache.put(key, theme, complexColor.getConstantState());
}
- } else {
- cache.put(key, theme, complexColor.getConstantState());
}
return complexColor;
}
@@ -1044,7 +1046,8 @@
* We deferred the parser creation to this function b/c we need to differentiate b/t gradient
* and selector tag.
*
- * @return a ComplexColor (GradientColor or ColorStateList) based on the XML file content.
+ * @return a ComplexColor (GradientColor or ColorStateList) based on the XML file content, or
+ * {@code null} if the XML file is neither.
*/
@NonNull
private ComplexColor loadComplexColorForCookie(Resources wrapper, TypedValue value, int id,
diff --git a/core/java/android/database/sqlite/SQLiteOpenHelper.java b/core/java/android/database/sqlite/SQLiteOpenHelper.java
index a2991e6..64e9e5d 100644
--- a/core/java/android/database/sqlite/SQLiteOpenHelper.java
+++ b/core/java/android/database/sqlite/SQLiteOpenHelper.java
@@ -58,7 +58,7 @@
private SQLiteDatabase mDatabase;
private boolean mIsInitializing;
- private final SQLiteDatabase.OpenParams.Builder mOpenParamsBuilder;
+ private SQLiteDatabase.OpenParams.Builder mOpenParamsBuilder;
/**
* Create a helper object to create, open, and/or manage a database.
@@ -163,8 +163,7 @@
mName = name;
mNewVersion = version;
mMinimumSupportedVersion = Math.max(0, minimumSupportedVersion);
- mOpenParamsBuilder = openParamsBuilder;
- mOpenParamsBuilder.addOpenFlags(SQLiteDatabase.CREATE_IF_NECESSARY);
+ setOpenParamsBuilder(openParamsBuilder);
}
/**
@@ -230,6 +229,30 @@
}
/**
+ * Sets configuration parameters that are used for opening {@link SQLiteDatabase}.
+ * <p>Please note that {@link SQLiteDatabase#CREATE_IF_NECESSARY} flag will always be set when
+ * opening the database
+ *
+ * @param openParams configuration parameters that are used for opening {@link SQLiteDatabase}.
+ * @throws IllegalStateException if the database is already open
+ */
+ public void setOpenParams(@NonNull SQLiteDatabase.OpenParams openParams) {
+ Preconditions.checkNotNull(openParams);
+ synchronized (this) {
+ if (mDatabase != null && mDatabase.isOpen()) {
+ throw new IllegalStateException(
+ "OpenParams cannot be set after opening the database");
+ }
+ setOpenParamsBuilder(new SQLiteDatabase.OpenParams.Builder(openParams));
+ }
+ }
+
+ private void setOpenParamsBuilder(SQLiteDatabase.OpenParams.Builder openParamsBuilder) {
+ mOpenParamsBuilder = openParamsBuilder;
+ mOpenParamsBuilder.addOpenFlags(SQLiteDatabase.CREATE_IF_NECESSARY);
+ }
+
+ /**
* Sets the maximum number of milliseconds that SQLite connection is allowed to be idle
* before it is closed and removed from the pool.
*
diff --git a/core/java/android/hardware/OWNERS b/core/java/android/hardware/OWNERS
new file mode 100644
index 0000000..b8fea55
--- /dev/null
+++ b/core/java/android/hardware/OWNERS
@@ -0,0 +1,7 @@
+# Camera
+per-file *Camera* = cychen@google.com
+per-file *Camera* = epeev@google.com
+per-file *Camera* = etalvala@google.com
+per-file *Camera* = shuzhenwang@google.com
+per-file *Camera* = yinchiayeh@google.com
+per-file *Camera* = zhijunhe@google.com
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 96d043c..8502fc4 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -341,7 +341,7 @@
*/
@SuppressWarnings({"unchecked"})
public List<CaptureRequest.Key<?>> getAvailablePhysicalCameraRequestKeys() {
- if (mAvailableSessionKeys == null) {
+ if (mAvailablePhysicalRequestKeys == null) {
Object crKey = CaptureRequest.Key.class;
Class<CaptureRequest.Key<?>> crKeyTyped = (Class<CaptureRequest.Key<?>>)crKey;
@@ -1372,9 +1372,6 @@
* <p>The origin for {@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation}.</p>
* <p>Different calibration methods and use cases can produce better or worse results
* depending on the selected coordinate origin.</p>
- * <p>For devices designed to support the MOTION_TRACKING capability, the GYROSCOPE origin
- * makes device calibration and later usage by applications combining camera and gyroscope
- * information together simpler.</p>
* <p><b>Possible values:</b>
* <ul>
* <li>{@link #LENS_POSE_REFERENCE_PRIMARY_CAMERA PRIMARY_CAMERA}</li>
@@ -1793,11 +1790,7 @@
* The respective value of such request key can be obtained by calling
* {@link CaptureRequest.Builder#getPhysicalCameraKey }. Capture requests that contain
* individual physical device requests must be built via
- * {@link android.hardware.camera2.CameraDevice#createCaptureRequest(int, Set)}.
- * Such extended capture requests can be passed only to
- * {@link CameraCaptureSession#capture } or {@link CameraCaptureSession#captureBurst } and
- * not to {@link CameraCaptureSession#setRepeatingRequest } or
- * {@link CameraCaptureSession#setRepeatingBurst }.</p>
+ * {@link android.hardware.camera2.CameraDevice#createCaptureRequest(int, Set)}.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
* <p><b>Limited capability</b> -
* Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index df64401..72db33f 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -145,37 +145,6 @@
*/
public static final int TEMPLATE_MANUAL = 6;
- /**
- * A template for selecting camera parameters that match TEMPLATE_PREVIEW as closely as
- * possible while improving the camera output for motion tracking use cases.
- *
- * <p>This template is best used by applications that are frequently switching between motion
- * tracking use cases and regular still capture use cases, to minimize the IQ changes
- * when swapping use cases.</p>
- *
- * <p>This template is guaranteed to be supported on camera devices that support the
- * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING MOTION_TRACKING}
- * capability.</p>
- *
- * @see #createCaptureRequest
- */
- public static final int TEMPLATE_MOTION_TRACKING_PREVIEW = 7;
-
- /**
- * A template for selecting camera parameters that maximize the quality of camera output for
- * motion tracking use cases.
- *
- * <p>This template is best used by applications dedicated to motion tracking applications,
- * which aren't concerned about fast switches between motion tracking and other use cases.</p>
- *
- * <p>This template is guaranteed to be supported on camera devices that support the
- * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING MOTION_TRACKING}
- * capability.</p>
- *
- * @see #createCaptureRequest
- */
- public static final int TEMPLATE_MOTION_TRACKING_BEST = 8;
-
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = {"TEMPLATE_"}, value =
@@ -184,9 +153,7 @@
TEMPLATE_RECORD,
TEMPLATE_VIDEO_SNAPSHOT,
TEMPLATE_ZERO_SHUTTER_LAG,
- TEMPLATE_MANUAL,
- TEMPLATE_MOTION_TRACKING_PREVIEW,
- TEMPLATE_MOTION_TRACKING_BEST})
+ TEMPLATE_MANUAL})
public @interface RequestTemplate {};
/**
@@ -420,27 +387,6 @@
* </table><br>
* </p>
*
- * <p>MOTION_TRACKING-capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES}
- * includes
- * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING MOTION_TRACKING})
- * devices support at least the below stream combinations in addition to those for
- * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED} devices. The
- * {@code FULL FOV 640} entry means that the device will support a resolution that's 640 pixels
- * wide, with the height set so that the resolution aspect ratio matches the MAXIMUM output
- * aspect ratio, rounded down. So for a device with a 4:3 image sensor, this will be 640x480,
- * and for a device with a 16:9 sensor, this will be 640x360, and so on. And the
- * {@code MAX 30FPS} entry means the largest JPEG resolution on the device for which
- * {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputMinFrameDuration}
- * returns a value less than or equal to 1/30s.
- *
- * <table>
- * <tr><th colspan="7">MOTION_TRACKING-capability additional guaranteed configurations</th></tr>
- * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th><th rowspan="2">Sample use case(s)</th> </tr>
- * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th></tr>
- * <tr> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV }</td><td id="rb">{@code FULL FOV 640}</td> <td>{@code JPEG}</td><td id="rb">{@code MAX 30FPS}</td> <td>Preview with a tracking YUV output and a as-large-as-possible JPEG for still captures.</td> </tr>
- * </table><br>
- * </p>
- *
* <p>BURST-capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES} includes
* {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE BURST_CAPTURE}) devices
* support at least the below stream combinations in addition to those for
@@ -917,11 +863,8 @@
* request for a specific physical camera. The settings are chosen
* to be the best options for the specific logical camera device. If
* additional physical camera ids are passed, then they will also use the
- * same settings template. Requests containing individual physical camera
- * settings can be passed only to {@link CameraCaptureSession#capture} or
- * {@link CameraCaptureSession#captureBurst} and not to
- * {@link CameraCaptureSession#setRepeatingRequest} or
- * {@link CameraCaptureSession#setRepeatingBurst}</p>
+ * same settings template. Clients can further modify individual camera
+ * settings by calling {@link CaptureRequest.Builder#setPhysicalCameraKey}.</p>
*
* <p>Individual physical camera settings will only be honored for camera session
* that was initialiazed with corresponding physical camera id output configuration
@@ -950,8 +893,8 @@
* @see #TEMPLATE_STILL_CAPTURE
* @see #TEMPLATE_VIDEO_SNAPSHOT
* @see #TEMPLATE_MANUAL
- * @see CaptureRequest.Builder#setKey
- * @see CaptureRequest.Builder#getKey
+ * @see CaptureRequest.Builder#setPhysicalCameraKey
+ * @see CaptureRequest.Builder#getPhysicalCameraKey
*/
@NonNull
public CaptureRequest.Builder createCaptureRequest(@RequestTemplate int templateType,
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index e7c8961..732f6a5 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -342,7 +342,7 @@
/**
* <p>The value of {@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation} is relative to the optical center of
* the largest camera device facing the same direction as this camera.</p>
- * <p>This default value for API levels before Android P.</p>
+ * <p>This is the default value for API levels before Android P.</p>
*
* @see CameraCharacteristics#LENS_POSE_TRANSLATION
* @see CameraCharacteristics#LENS_POSE_REFERENCE
@@ -352,7 +352,6 @@
/**
* <p>The value of {@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation} is relative to the position of the
* primary gyroscope of this Android device.</p>
- * <p>This is the value reported by all devices that support the MOTION_TRACKING capability.</p>
*
* @see CameraCharacteristics#LENS_POSE_TRANSLATION
* @see CameraCharacteristics#LENS_POSE_REFERENCE
@@ -801,46 +800,12 @@
public static final int REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO = 9;
/**
- * <p>The device supports controls and metadata required for accurate motion tracking for
- * use cases such as augmented reality, electronic image stabilization, and so on.</p>
- * <p>This means this camera device has accurate optical calibration and timestamps relative
- * to the inertial sensors.</p>
- * <p>This capability requires the camera device to support the following:</p>
- * <ul>
- * <li>Capture request templates {@link android.hardware.camera2.CameraDevice#TEMPLATE_MOTION_TRACKING_PREVIEW } and {@link android.hardware.camera2.CameraDevice#TEMPLATE_MOTION_TRACKING_BEST } are defined.</li>
- * <li>The stream configurations listed in {@link android.hardware.camera2.CameraDevice#createCaptureSession } for MOTION_TRACKING are
- * supported, either at 30 or 60fps maximum frame rate.</li>
- * <li>The following camera characteristics and capture result metadata are provided:<ul>
- * <li>{@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration}</li>
- * <li>{@link CameraCharacteristics#LENS_RADIAL_DISTORTION android.lens.radialDistortion}</li>
- * <li>{@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation}</li>
- * <li>{@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation}</li>
- * <li>{@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference} with value GYROSCOPE</li>
- * </ul>
- * </li>
- * <li>The {@link CameraCharacteristics#SENSOR_INFO_TIMESTAMP_SOURCE android.sensor.info.timestampSource} field has value <code>REALTIME</code>. When compared to
- * timestamps from the device's gyroscopes, the clock difference for events occuring at
- * the same actual time instant will be less than 1 ms.</li>
- * <li>The value of the {@link CaptureResult#SENSOR_ROLLING_SHUTTER_SKEW android.sensor.rollingShutterSkew} field is accurate to within 1 ms.</li>
- * <li>The value of {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime} is guaranteed to be available in the
- * capture result.</li>
- * <li>The {@link CaptureRequest#CONTROL_CAPTURE_INTENT android.control.captureIntent} control supports MOTION_TRACKING to limit maximum
- * exposure to 20 milliseconds.</li>
- * <li>The stream configurations required for MOTION_TRACKING (listed at {@link android.hardware.camera2.CameraDevice#createCaptureSession }) can operate at least at
- * 30fps; optionally, they can operate at 60fps, and '[60, 60]' is listed in
- * {@link CameraCharacteristics#CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES android.control.aeAvailableTargetFpsRanges}.</li>
- * </ul>
+ * <p>The camera device supports the MOTION_TRACKING value for
+ * {@link CaptureRequest#CONTROL_CAPTURE_INTENT android.control.captureIntent}, which limits maximum exposure time to 20 ms.</p>
+ * <p>This limits the motion blur of capture images, resulting in better image tracking
+ * results for use cases such as image stabilization or augmented reality.</p>
*
- * @see CameraCharacteristics#CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES
* @see CaptureRequest#CONTROL_CAPTURE_INTENT
- * @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
- * @see CameraCharacteristics#LENS_POSE_REFERENCE
- * @see CameraCharacteristics#LENS_POSE_ROTATION
- * @see CameraCharacteristics#LENS_POSE_TRANSLATION
- * @see CameraCharacteristics#LENS_RADIAL_DISTORTION
- * @see CaptureRequest#SENSOR_EXPOSURE_TIME
- * @see CameraCharacteristics#SENSOR_INFO_TIMESTAMP_SOURCE
- * @see CaptureResult#SENSOR_ROLLING_SHUTTER_SKEW
* @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
*/
public static final int REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING = 10;
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 481b764..3ed533a 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -2757,11 +2757,11 @@
new Key<Integer>("android.statistics.lensShadingMapMode", int.class);
/**
- * <p>Whether the camera device outputs the OIS data in output
+ * <p>A control for selecting whether OIS position information is included in output
* result metadata.</p>
* <p>When set to ON,
* {@link CaptureResult#STATISTICS_OIS_TIMESTAMPS android.statistics.oisTimestamps}, android.statistics.oisShiftPixelX,
- * android.statistics.oisShiftPixelY will provide OIS data in the output result metadata.</p>
+ * and android.statistics.oisShiftPixelY provide OIS data in the output result metadata.</p>
* <p><b>Possible values:</b>
* <ul>
* <li>{@link #STATISTICS_OIS_DATA_MODE_OFF OFF}</li>
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index d730fa8..c332d30 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -3909,11 +3909,11 @@
new Key<Integer>("android.statistics.lensShadingMapMode", int.class);
/**
- * <p>Whether the camera device outputs the OIS data in output
+ * <p>A control for selecting whether OIS position information is included in output
* result metadata.</p>
* <p>When set to ON,
* {@link CaptureResult#STATISTICS_OIS_TIMESTAMPS android.statistics.oisTimestamps}, android.statistics.oisShiftPixelX,
- * android.statistics.oisShiftPixelY will provide OIS data in the output result metadata.</p>
+ * and android.statistics.oisShiftPixelY provide OIS data in the output result metadata.</p>
* <p><b>Possible values:</b>
* <ul>
* <li>{@link #STATISTICS_OIS_DATA_MODE_OFF OFF}</li>
diff --git a/core/java/android/hardware/camera2/OWNERS b/core/java/android/hardware/camera2/OWNERS
new file mode 100644
index 0000000..18acfee
--- /dev/null
+++ b/core/java/android/hardware/camera2/OWNERS
@@ -0,0 +1,6 @@
+cychen@google.com
+epeev@google.com
+etalvala@google.com
+shuzhenwang@google.com
+yinchiayeh@google.com
+zhijunhe@google.com
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 166342d..7dde2ed 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -112,8 +112,14 @@
* <p/>
* For a disconnect event, the boolean extra EXTRA_NO_CONNECTIVITY
* is set to {@code true} if there are no connected networks at all.
+ *
+ * @deprecated apps should use the more versatile {@link #requestNetwork},
+ * {@link #registerNetworkCallback} or {@link #registerDefaultNetworkCallback}
+ * functions instead for faster and more detailed updates about the network
+ * changes they care about.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @Deprecated
public static final String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
/**
@@ -2685,6 +2691,32 @@
* satisfying the request changes.
*
* @param network The {@link Network} of the satisfying network.
+ * @param networkCapabilities The {@link NetworkCapabilities} of the satisfying network.
+ * @param linkProperties The {@link LinkProperties} of the satisfying network.
+ * @hide
+ */
+ public void onAvailable(Network network, NetworkCapabilities networkCapabilities,
+ LinkProperties linkProperties) {
+ // Internally only this method is called when a new network is available, and
+ // it calls the callback in the same way and order that older versions used
+ // to call so as not to change the behavior.
+ onAvailable(network);
+ if (!networkCapabilities.hasCapability(
+ NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)) {
+ onNetworkSuspended(network);
+ }
+ onCapabilitiesChanged(network, networkCapabilities);
+ onLinkPropertiesChanged(network, linkProperties);
+ }
+
+ /**
+ * Called when the framework connects and has declared a new network ready for use.
+ * This callback may be called more than once if the {@link Network} that is
+ * satisfying the request changes. This will always immediately be followed by a
+ * call to {@link #onCapabilitiesChanged(Network, NetworkCapabilities)} then by a
+ * call to {@link #onLinkPropertiesChanged(Network, LinkProperties)}.
+ *
+ * @param network The {@link Network} of the satisfying network.
*/
public void onAvailable(Network network) {}
@@ -2727,7 +2759,8 @@
* changes capabilities but still satisfies the stated need.
*
* @param network The {@link Network} whose capabilities have changed.
- * @param networkCapabilities The new {@link android.net.NetworkCapabilities} for this network.
+ * @param networkCapabilities The new {@link android.net.NetworkCapabilities} for this
+ * network.
*/
public void onCapabilitiesChanged(Network network,
NetworkCapabilities networkCapabilities) {}
@@ -2743,7 +2776,7 @@
/**
* Called when the network the framework connected to for this request
- * goes into {@link NetworkInfo.DetailedState.SUSPENDED}.
+ * goes into {@link NetworkInfo.State#SUSPENDED}.
* This generally means that while the TCP connections are still live,
* temporarily network data fails to transfer. Specifically this is used
* on cellular networks to mask temporary outages when driving through
@@ -2754,9 +2787,8 @@
/**
* Called when the network the framework connected to for this request
- * returns from a {@link NetworkInfo.DetailedState.SUSPENDED} state.
- * This should always be preceeded by a matching {@code onNetworkSuspended}
- * call.
+ * returns from a {@link NetworkInfo.State#SUSPENDED} state. This should always be
+ * preceded by a matching {@link NetworkCallback#onNetworkSuspended} call.
* @hide
*/
public void onNetworkResumed(Network network) {}
@@ -2865,7 +2897,9 @@
break;
}
case CALLBACK_AVAILABLE: {
- callback.onAvailable(network);
+ NetworkCapabilities cap = getObject(message, NetworkCapabilities.class);
+ LinkProperties lp = getObject(message, LinkProperties.class);
+ callback.onAvailable(network, cap, lp);
break;
}
case CALLBACK_LOSING: {
diff --git a/core/java/android/net/IpSecConfig.java b/core/java/android/net/IpSecConfig.java
index 6a262e2..8599f47 100644
--- a/core/java/android/net/IpSecConfig.java
+++ b/core/java/android/net/IpSecConfig.java
@@ -218,6 +218,25 @@
@VisibleForTesting
public IpSecConfig() {}
+ /** Copy constructor */
+ @VisibleForTesting
+ public IpSecConfig(IpSecConfig c) {
+ mMode = c.mMode;
+ mSourceAddress = c.mSourceAddress;
+ mDestinationAddress = c.mDestinationAddress;
+ mNetwork = c.mNetwork;
+ mSpiResourceId = c.mSpiResourceId;
+ mEncryption = c.mEncryption;
+ mAuthentication = c.mAuthentication;
+ mAuthenticatedEncryption = c.mAuthenticatedEncryption;
+ mEncapType = c.mEncapType;
+ mEncapSocketResourceId = c.mEncapSocketResourceId;
+ mEncapRemotePort = c.mEncapRemotePort;
+ mNattKeepaliveInterval = c.mNattKeepaliveInterval;
+ mMarkValue = c.mMarkValue;
+ mMarkMask = c.mMarkMask;
+ }
+
private IpSecConfig(Parcel in) {
mMode = in.readInt();
mSourceAddress = in.readString();
diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java
index 38759a9..60e96f9 100644
--- a/core/java/android/net/IpSecTransform.java
+++ b/core/java/android/net/IpSecTransform.java
@@ -84,9 +84,11 @@
@Retention(RetentionPolicy.SOURCE)
public @interface EncapType {}
- private IpSecTransform(Context context, IpSecConfig config) {
+ /** @hide */
+ @VisibleForTesting
+ public IpSecTransform(Context context, IpSecConfig config) {
mContext = context;
- mConfig = config;
+ mConfig = new IpSecConfig(config);
mResourceId = INVALID_RESOURCE_ID;
}
@@ -143,6 +145,18 @@
}
/**
+ * Equals method used for testing
+ *
+ * @hide
+ */
+ @VisibleForTesting
+ public static boolean equals(IpSecTransform lhs, IpSecTransform rhs) {
+ if (lhs == null || rhs == null) return (lhs == rhs);
+ return IpSecConfig.equals(lhs.getConfig(), rhs.getConfig())
+ && lhs.mResourceId == rhs.mResourceId;
+ }
+
+ /**
* Deactivate this {@code IpSecTransform} and free allocated resources.
*
* <p>Deactivating a transform while it is still applied to a socket will result in errors on
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 8e05cfa..bae373d 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -116,6 +116,7 @@
NET_CAPABILITY_NOT_ROAMING,
NET_CAPABILITY_FOREGROUND,
NET_CAPABILITY_NOT_CONGESTED,
+ NET_CAPABILITY_NOT_SUSPENDED,
})
public @interface NetCapability { }
@@ -239,7 +240,6 @@
/**
* Indicates that this network is available for use by apps, and not a network that is being
* kept up in the background to facilitate fast network switching.
- * @hide
*/
public static final int NET_CAPABILITY_FOREGROUND = 19;
@@ -252,8 +252,20 @@
*/
public static final int NET_CAPABILITY_NOT_CONGESTED = 20;
+ /**
+ * Indicates that this network is not currently suspended.
+ * <p>
+ * When a network is suspended, the network's IP addresses and any connections
+ * established on the network remain valid, but the network is temporarily unable
+ * to transfer data. This can happen, for example, if a cellular network experiences
+ * a temporary loss of signal, such as when driving through a tunnel, etc.
+ * A network with this capability is not suspended, so is expected to be able to
+ * transfer data.
+ */
+ public static final int NET_CAPABILITY_NOT_SUSPENDED = 21;
+
private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS;
- private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_NOT_CONGESTED;
+ private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_NOT_SUSPENDED;
/**
* Network capabilities that are expected to be mutable, i.e., can change while a particular
@@ -262,12 +274,13 @@
private static final long MUTABLE_CAPABILITIES =
// TRUSTED can change when user explicitly connects to an untrusted network in Settings.
// http://b/18206275
- (1 << NET_CAPABILITY_TRUSTED) |
- (1 << NET_CAPABILITY_VALIDATED) |
- (1 << NET_CAPABILITY_CAPTIVE_PORTAL) |
- (1 << NET_CAPABILITY_NOT_ROAMING) |
- (1 << NET_CAPABILITY_FOREGROUND) |
- (1 << NET_CAPABILITY_NOT_CONGESTED);
+ (1 << NET_CAPABILITY_TRUSTED)
+ | (1 << NET_CAPABILITY_VALIDATED)
+ | (1 << NET_CAPABILITY_CAPTIVE_PORTAL)
+ | (1 << NET_CAPABILITY_NOT_ROAMING)
+ | (1 << NET_CAPABILITY_FOREGROUND)
+ | (1 << NET_CAPABILITY_NOT_CONGESTED)
+ | (1 << NET_CAPABILITY_NOT_SUSPENDED);
/**
* Network capabilities that are not allowed in NetworkRequests. This exists because the
@@ -1299,6 +1312,7 @@
case NET_CAPABILITY_NOT_ROAMING: return "NOT_ROAMING";
case NET_CAPABILITY_FOREGROUND: return "FOREGROUND";
case NET_CAPABILITY_NOT_CONGESTED: return "NOT_CONGESTED";
+ case NET_CAPABILITY_NOT_SUSPENDED: return "NOT_SUSPENDED";
default: return Integer.toString(capability);
}
}
diff --git a/core/java/android/net/OWNERS b/core/java/android/net/OWNERS
index 3a40cf4..3cd37bf 100644
--- a/core/java/android/net/OWNERS
+++ b/core/java/android/net/OWNERS
@@ -1,3 +1,5 @@
+set noparent
+
ek@google.com
jsharkey@android.com
jchalard@google.com
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 5d7cf1e..7cd58e8 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -2240,12 +2240,16 @@
public static final int DATA_CONNECTION_LTE = 13;
public static final int DATA_CONNECTION_EHRPD = 14;
public static final int DATA_CONNECTION_HSPAP = 15;
- public static final int DATA_CONNECTION_OTHER = 16;
+ public static final int DATA_CONNECTION_GSM = 16;
+ public static final int DATA_CONNECTION_TD_SCDMA = 17;
+ public static final int DATA_CONNECTION_IWLAN = 18;
+ public static final int DATA_CONNECTION_LTE_CA = 19;
+ public static final int DATA_CONNECTION_OTHER = 20;
static final String[] DATA_CONNECTION_NAMES = {
"none", "gprs", "edge", "umts", "cdma", "evdo_0", "evdo_A",
"1xrtt", "hsdpa", "hsupa", "hspa", "iden", "evdo_b", "lte",
- "ehrpd", "hspap", "other"
+ "ehrpd", "hspap", "gsm", "td_scdma", "iwlan", "lte_ca", "other"
};
public static final int NUM_DATA_CONNECTION_TYPES = DATA_CONNECTION_OTHER+1;
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index fc78861..48f5684 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -894,14 +894,6 @@
/**
* P.
- *
- * <p>Applications targeting this or a later release will get these
- * new changes in behavior:</p>
- * <ul>
- * <li>{@link android.app.Service#startForeground Service.startForeground} requires
- * that apps hold the permission
- * {@link android.Manifest.permission#FOREGROUND_SERVICE}.</li>
- * </ul>
*/
public static final int P = CUR_DEVELOPMENT; // STOPSHIP Replace with the real version.
}
diff --git a/core/java/android/os/HwBinder.java b/core/java/android/os/HwBinder.java
index cdee110..228fe7a 100644
--- a/core/java/android/os/HwBinder.java
+++ b/core/java/android/os/HwBinder.java
@@ -29,7 +29,13 @@
private static final NativeAllocationRegistry sNativeRegistry;
- /** @hide */
+ /**
+ * Create and initialize a HwBinder object and the native objects
+ * used to allow this to participate in hwbinder transactions.
+ *
+ * @hide
+ */
+ @SystemApi
public HwBinder() {
native_setup();
@@ -44,12 +50,28 @@
int code, HwParcel request, HwParcel reply, int flags)
throws RemoteException;
- /** @hide */
+ /**
+ * Process a hwbinder transaction.
+ *
+ * @param code interface specific code for interface.
+ * @param request parceled transaction
+ * @param reply object to parcel reply into
+ * @param flags transaction flags to be chosen by wire protocol
+ *
+ * @hide
+ */
+ @SystemApi
public abstract void onTransact(
int code, HwParcel request, HwParcel reply, int flags)
throws RemoteException;
- /** @hide */
+ /**
+ * Registers this service with the hwservicemanager.
+ *
+ * @param serviceName instance name of the service
+ * @hide
+ */
+ @SystemApi
public native final void registerService(String serviceName)
throws RemoteException;
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 65e9473..5e23932 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -71,6 +71,7 @@
Bundle getUserRestrictions(int userHandle);
boolean hasBaseUserRestriction(String restrictionKey, int userHandle);
boolean hasUserRestriction(in String restrictionKey, int userHandle);
+ boolean hasUserRestrictionOnAnyUser(in String restrictionKey);
void setUserRestriction(String key, boolean value, int userHandle);
void setApplicationRestrictions(in String packageName, in Bundle restrictions,
int userHandle);
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 7e7af1a..1856200 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1678,6 +1678,18 @@
}
/**
+ * @hide
+ * Returns whether any user on the device has the given user restriction set.
+ */
+ public boolean hasUserRestrictionOnAnyUser(String restrictionKey) {
+ try {
+ return mService.hasUserRestrictionOnAnyUser(restrictionKey);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Return the serial number for a user. This is a device-unique
* number assigned to that user; if the user is deleted and then a new
* user created, the new users will not be given the same serial number.
diff --git a/core/java/android/preference/OWNERS b/core/java/android/preference/OWNERS
new file mode 100644
index 0000000..d20511f
--- /dev/null
+++ b/core/java/android/preference/OWNERS
@@ -0,0 +1,2 @@
+pavlis@google.com
+clarabayarri@google.com
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index a183895..05ab486 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5385,6 +5385,17 @@
"autofill_user_data_max_field_classification_size";
/**
+ * Defines value returned by
+ * {@link android.service.autofill.UserData#getMaxCategoryCount()}.
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ public static final String AUTOFILL_USER_DATA_MAX_CATEGORY_COUNT =
+ "autofill_user_data_max_category_count";
+
+ /**
* Defines value returned by {@link android.service.autofill.UserData#getMaxValueLength()}.
*
* @hide
@@ -5443,32 +5454,6 @@
*/
public static final String ENABLED_INPUT_METHODS = "enabled_input_methods";
- private static final Validator ENABLED_INPUT_METHODS_VALIDATOR = new Validator() {
- @Override
- public boolean validate(String value) {
- if (value == null) {
- return false;
- }
- String[] inputMethods = value.split(":");
- boolean valid = true;
- for (String inputMethod : inputMethods) {
- if (inputMethod.length() == 0) {
- return false;
- }
- String[] subparts = inputMethod.split(";");
- for (String subpart : subparts) {
- // allow either a non negative integer or a ComponentName
- valid |= (NON_NEGATIVE_INTEGER_VALIDATOR.validate(subpart)
- || COMPONENT_NAME_VALIDATOR.validate(subpart));
- }
- if (!valid) {
- return false;
- }
- }
- return valid;
- }
- };
-
/**
* List of system input methods that are currently disabled. This is a string
* containing the IDs of all disabled input methods, each ID separated
@@ -7709,7 +7694,6 @@
ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE,
ENABLED_ACCESSIBILITY_SERVICES,
ENABLED_VR_LISTENERS,
- ENABLED_INPUT_METHODS,
TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
TOUCH_EXPLORATION_ENABLED,
ACCESSIBILITY_ENABLED,
@@ -7815,7 +7799,6 @@
VALIDATORS.put(ENABLED_ACCESSIBILITY_SERVICES,
ENABLED_ACCESSIBILITY_SERVICES_VALIDATOR);
VALIDATORS.put(ENABLED_VR_LISTENERS, ENABLED_VR_LISTENERS_VALIDATOR);
- VALIDATORS.put(ENABLED_INPUT_METHODS, ENABLED_INPUT_METHODS_VALIDATOR);
VALIDATORS.put(TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES_VALIDATOR);
VALIDATORS.put(TOUCH_EXPLORATION_ENABLED, TOUCH_EXPLORATION_ENABLED_VALIDATOR);
@@ -8563,9 +8546,8 @@
*
* @see android.service.euicc.EuiccService
* @hide
- *
- * TODO(b/35851809): Make this a SystemApi.
*/
+ @SystemApi
public static final String DEFAULT_SM_DP_PLUS = "default_sm_dp_plus";
/**
@@ -10506,6 +10488,16 @@
public static final String BATTERY_STATS_CONSTANTS = "battery_stats_constants";
/**
+ * SyncManager specific settings.
+ *
+ * <p>
+ * Type: string
+ * @hide
+ * @see com.android.server.content.SyncManagerConstants
+ */
+ public static final String SYNC_MANAGER_CONSTANTS = "sync_manager_constants";
+
+ /**
* Whether or not App Standby feature is enabled. This controls throttling of apps
* based on usage patterns and predictions.
* Type: int (0 for false, 1 for true)
@@ -11373,7 +11365,8 @@
"chained_battery_attribution_enabled";
/**
- * The packages whitelisted to be run in autofill compatibility mode.
+ * The packages whitelisted to be run in autofill compatibility mode. The list
+ * of packages is ":" colon delimited.
*
* @hide
*/
@@ -11382,6 +11375,14 @@
"autofill_compat_allowed_packages";
/**
+ * Exemptions to the hidden API blacklist.
+ *
+ * @hide
+ */
+ public static final String HIDDEN_API_BLACKLIST_EXEMPTIONS =
+ "hidden_api_blacklist_exemptions";
+
+ /**
* Settings to backup. This is here so that it's in the same place as the settings
* keys and easy to update.
*
@@ -12080,6 +12081,28 @@
"enable_gnss_raw_meas_full_tracking";
/**
+ * Whether the notification should be ongoing (persistent) when a carrier app install is
+ * required.
+ *
+ * The value is a boolean (1 or 0).
+ * @hide
+ */
+ @SystemApi
+ public static final String INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT =
+ "install_carrier_app_notification_persistent";
+
+ /**
+ * The amount of time (ms) to hide the install carrier app notification after the user has
+ * ignored it. After this time passes, the notification will be shown again
+ *
+ * The value is a long
+ * @hide
+ */
+ @SystemApi
+ public static final String INSTALL_CARRIER_APP_NOTIFICATION_SLEEP_MILLIS =
+ "install_carrier_app_notification_sleep_millis";
+
+ /**
* Whether we've enabled zram on this device. Takes effect on
* reboot. The value "1" enables zram; "0" disables it, and
* everything else is unspecified.
@@ -12125,6 +12148,12 @@
* @hide
*/
public static final String SHOW_MUTE_IN_CRASH_DIALOG = "show_mute_in_crash_dialog";
+
+ /**
+ * If nonzero, will show the zen upgrade notification when the user toggles DND on/off.
+ * @hide
+ */
+ public static final String SHOW_ZEN_UPGRADE_NOTIFICATION = "show_zen_upgrade_notification";
}
/**
diff --git a/core/java/android/security/IConfirmationPromptCallback.aidl b/core/java/android/security/IConfirmationPromptCallback.aidl
deleted file mode 100644
index 96a1a04..0000000
--- a/core/java/android/security/IConfirmationPromptCallback.aidl
+++ /dev/null
@@ -1,27 +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 android.security;
-
-/**
- * This must be kept manually in sync with system/security/keystore until AIDL
- * can generate both Java and C++ bindings.
- *
- * @hide
- */
-interface IConfirmationPromptCallback {
- oneway void onConfirmationPromptCompleted(in int result, in byte[] dataThatWasConfirmed);
-}
diff --git a/core/java/android/security/IKeystoreService.aidl b/core/java/android/security/IKeystoreService.aidl
deleted file mode 100644
index 738eb68..0000000
--- a/core/java/android/security/IKeystoreService.aidl
+++ /dev/null
@@ -1,87 +0,0 @@
-/**
- * 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.security;
-
-import android.security.keymaster.ExportResult;
-import android.security.keymaster.KeyCharacteristics;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterCertificateChain;
-import android.security.keymaster.KeymasterBlob;
-import android.security.keymaster.OperationResult;
-import android.security.KeystoreArguments;
-
-/**
- * This must be kept manually in sync with system/security/keystore until AIDL
- * can generate both Java and C++ bindings.
- *
- * @hide
- */
-interface IKeystoreService {
- int getState(int userId);
- byte[] get(String name, int uid);
- int insert(String name, in byte[] item, int uid, int flags);
- int del(String name, int uid);
- int exist(String name, int uid);
- String[] list(String namePrefix, int uid);
- int reset();
- int onUserPasswordChanged(int userId, String newPassword);
- int lock(int userId);
- int unlock(int userId, String userPassword);
- int isEmpty(int userId);
- int generate(String name, int uid, int keyType, int keySize, int flags,
- in KeystoreArguments args);
- int import_key(String name, in byte[] data, int uid, int flags);
- byte[] sign(String name, in byte[] data);
- int verify(String name, in byte[] data, in byte[] signature);
- byte[] get_pubkey(String name);
- String grant(String name, int granteeUid);
- int ungrant(String name, int granteeUid);
- long getmtime(String name, int uid);
- int is_hardware_backed(String string);
- int clear_uid(long uid);
-
- // Keymaster 0.4 methods
- int addRngEntropy(in byte[] data, int flags);
- int generateKey(String alias, in KeymasterArguments arguments, in byte[] entropy, int uid,
- int flags, out KeyCharacteristics characteristics);
- int getKeyCharacteristics(String alias, in KeymasterBlob clientId, in KeymasterBlob appId,
- int uid, out KeyCharacteristics characteristics);
- int importKey(String alias, in KeymasterArguments arguments, int format,
- in byte[] keyData, int uid, int flags, out KeyCharacteristics characteristics);
- ExportResult exportKey(String alias, int format, in KeymasterBlob clientId,
- in KeymasterBlob appId, int uid);
- OperationResult begin(IBinder appToken, String alias, int purpose, boolean pruneable,
- in KeymasterArguments params, in byte[] entropy, int uid);
- OperationResult update(IBinder token, in KeymasterArguments params, in byte[] input);
- OperationResult finish(IBinder token, in KeymasterArguments params, in byte[] signature,
- in byte[] entropy);
- int abort(IBinder handle);
- boolean isOperationAuthorized(IBinder token);
- int addAuthToken(in byte[] authToken);
- int onUserAdded(int userId, int parentId);
- int onUserRemoved(int userId);
- int attestKey(String alias, in KeymasterArguments params, out KeymasterCertificateChain chain);
- int attestDeviceIds(in KeymasterArguments params, out KeymasterCertificateChain chain);
- int onDeviceOffBody();
- int importWrappedKey(in String wrappedKeyAlias, in byte[] wrappedKey,
- in String wrappingKeyAlias, in byte[] maskingKey, in KeymasterArguments arguments,
- in long rootSid, in long fingerprintSid,
- out KeyCharacteristics characteristics);
- int presentConfirmationPrompt(IBinder listener, String promptText, in byte[] extraData,
- in String locale, in int uiOptionsAsFlags);
- int cancelConfirmationPrompt(IBinder listener);
-}
diff --git a/core/java/android/security/KeystoreArguments.aidl b/core/java/android/security/KeystoreArguments.aidl
deleted file mode 100644
index dc8ed50..0000000
--- a/core/java/android/security/KeystoreArguments.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/**
- * 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.security;
-
-/* @hide */
-parcelable KeystoreArguments cpp_header "keystore/KeystoreArguments.h";
diff --git a/core/java/android/security/keymaster/ExportResult.aidl b/core/java/android/security/keymaster/ExportResult.aidl
deleted file mode 100644
index 1748653..0000000
--- a/core/java/android/security/keymaster/ExportResult.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * 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.security.keymaster;
-
-/* @hide */
-parcelable ExportResult cpp_header "keystore/ExportResult.h";
diff --git a/core/java/android/security/keymaster/KeyCharacteristics.aidl b/core/java/android/security/keymaster/KeyCharacteristics.aidl
deleted file mode 100644
index 32e75ad..0000000
--- a/core/java/android/security/keymaster/KeyCharacteristics.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * 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.security.keymaster;
-
-/* @hide */
-parcelable KeyCharacteristics cpp_header "keystore/KeyCharacteristics.h";
diff --git a/core/java/android/security/keymaster/KeymasterBlob.aidl b/core/java/android/security/keymaster/KeymasterBlob.aidl
deleted file mode 100644
index 5c5db9e..0000000
--- a/core/java/android/security/keymaster/KeymasterBlob.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * 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.security.keymaster;
-
-/* @hide */
-parcelable KeymasterBlob cpp_header "keystore/KeymasterBlob.h";
diff --git a/core/java/android/security/keymaster/KeymasterCertificateChain.aidl b/core/java/android/security/keymaster/KeymasterCertificateChain.aidl
deleted file mode 100644
index ddb5cae..0000000
--- a/core/java/android/security/keymaster/KeymasterCertificateChain.aidl
+++ /dev/null
@@ -1,20 +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 android.security.keymaster;
-
-/* @hide */
-parcelable KeymasterCertificateChain cpp_header "keystore/KeymasterCertificateChain.h";
diff --git a/core/java/android/security/keymaster/OperationResult.aidl b/core/java/android/security/keymaster/OperationResult.aidl
deleted file mode 100644
index db689d4..0000000
--- a/core/java/android/security/keymaster/OperationResult.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * 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.security.keymaster;
-
-/* @hide */
-parcelable OperationResult cpp_header "keystore/OperationResult.h";
diff --git a/core/java/android/security/keystore/OWNERS b/core/java/android/security/keystore/OWNERS
new file mode 100644
index 0000000..bb487fb
--- /dev/null
+++ b/core/java/android/security/keystore/OWNERS
@@ -0,0 +1,4 @@
+aseemk@google.com
+bozhu@google.com
+dementyev@google.com
+robertberry@google.com
diff --git a/core/java/android/service/autofill/AutofillServiceInfo.java b/core/java/android/service/autofill/AutofillServiceInfo.java
index 7383de7..70c4ec0 100644
--- a/core/java/android/service/autofill/AutofillServiceInfo.java
+++ b/core/java/android/service/autofill/AutofillServiceInfo.java
@@ -32,12 +32,12 @@
import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.Log;
+import android.util.Pair;
import android.util.Xml;
import com.android.internal.R;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
@@ -45,7 +45,6 @@
import java.io.IOException;
import java.io.PrintWriter;
-import java.util.Map;
/**
* {@link ServiceInfo} and meta-data about an {@link AutofillService}.
@@ -80,7 +79,7 @@
private final String mSettingsActivity;
@Nullable
- private final Map<String, Long> mCompatibilityPackages;
+ private final ArrayMap<String, Pair<Long, String>> mCompatibilityPackages;
public AutofillServiceInfo(Context context, ComponentName comp, int userHandle)
throws PackageManager.NameNotFoundException {
@@ -118,7 +117,7 @@
}
String settingsActivity = null;
- Map<String, Long> compatibilityPackages = null;
+ ArrayMap<String, Pair<Long, String>> compatibilityPackages = null;
try {
final Resources resources = context.getPackageManager().getResourcesForApplication(
@@ -154,9 +153,10 @@
mCompatibilityPackages = compatibilityPackages;
}
- private Map<String, Long> parseCompatibilityPackages(XmlPullParser parser, Resources resources)
+ private ArrayMap<String, Pair<Long, String>> parseCompatibilityPackages(XmlPullParser parser,
+ Resources resources)
throws IOException, XmlPullParserException {
- Map<String, Long> compatibilityPackages = null;
+ ArrayMap<String, Pair<Long, String>> compatibilityPackages = null;
final int outerDepth = parser.getDepth();
int type;
@@ -200,11 +200,13 @@
} else {
maxVersionCode = Long.MAX_VALUE;
}
+ final String urlBarResourceId = cpAttributes.getString(
+ R.styleable.AutofillService_CompatibilityPackage_urlBarResourceId);
if (compatibilityPackages == null) {
compatibilityPackages = new ArrayMap<>();
}
- compatibilityPackages.put(name, maxVersionCode);
+ compatibilityPackages.put(name, new Pair<>(maxVersionCode, urlBarResourceId));
} finally {
XmlUtils.skipCurrentTag(parser);
if (cpAttributes != null) {
@@ -226,16 +228,21 @@
return mSettingsActivity;
}
+ public ArrayMap<String, Pair<Long, String>> getCompatibilityPackages() {
+ return mCompatibilityPackages;
+ }
+
+ /**
+ * Gets the resource id of the URL bar for a package. Used in compat mode
+ */
+ // TODO: return a list of strings instead
@Nullable
- public boolean isCompatibilityModeRequested(String packageName, long versionCode) {
+ public String getUrlBarResourceId(String packageName) {
if (mCompatibilityPackages == null) {
- return false;
+ return null;
}
- final Long maxVersionCode = mCompatibilityPackages.get(packageName);
- if (maxVersionCode == null) {
- return false;
- }
- return versionCode <= maxVersionCode;
+ final Pair<Long, String> pair = mCompatibilityPackages.get(packageName);
+ return pair == null ? null : pair.second;
}
@Override
diff --git a/core/java/android/service/autofill/DateTransformation.java b/core/java/android/service/autofill/DateTransformation.java
index 4e1425d..ec24a09 100644
--- a/core/java/android/service/autofill/DateTransformation.java
+++ b/core/java/android/service/autofill/DateTransformation.java
@@ -20,6 +20,7 @@
import android.annotation.NonNull;
import android.annotation.TestApi;
+import android.icu.text.DateFormat;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
@@ -30,7 +31,6 @@
import com.android.internal.util.Preconditions;
-import java.text.DateFormat;
import java.util.Date;
/**
diff --git a/core/java/android/service/autofill/DateValueSanitizer.java b/core/java/android/service/autofill/DateValueSanitizer.java
index 0f7b540..4f797f4 100644
--- a/core/java/android/service/autofill/DateValueSanitizer.java
+++ b/core/java/android/service/autofill/DateValueSanitizer.java
@@ -21,6 +21,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
+import android.icu.text.DateFormat;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
@@ -28,7 +29,6 @@
import com.android.internal.util.Preconditions;
-import java.text.DateFormat;
import java.util.Date;
/**
diff --git a/core/java/android/service/autofill/FieldClassification.java b/core/java/android/service/autofill/FieldClassification.java
index cd1efd6..5bf56cb9 100644
--- a/core/java/android/service/autofill/FieldClassification.java
+++ b/core/java/android/service/autofill/FieldClassification.java
@@ -108,21 +108,21 @@
*/
public static final class Match {
- private final String mRemoteId;
+ private final String mCategoryId;
private final float mScore;
/** @hide */
- public Match(String remoteId, float score) {
- mRemoteId = Preconditions.checkNotNull(remoteId);
+ public Match(String categoryId, float score) {
+ mCategoryId = Preconditions.checkNotNull(categoryId);
mScore = score;
}
/**
- * Gets the remote id of the {@link UserData} entry.
+ * Gets the category id of the {@link UserData} entry.
*/
@NonNull
- public String getRemoteId() {
- return mRemoteId;
+ public String getCategoryId() {
+ return mCategoryId;
}
/**
@@ -149,13 +149,13 @@
public String toString() {
if (!sDebug) return super.toString();
- final StringBuilder string = new StringBuilder("Match: remoteId=");
- Helper.appendRedacted(string, mRemoteId);
+ final StringBuilder string = new StringBuilder("Match: categoryId=");
+ Helper.appendRedacted(string, mCategoryId);
return string.append(", score=").append(mScore).toString();
}
private void writeToParcel(@NonNull Parcel parcel) {
- parcel.writeString(mRemoteId);
+ parcel.writeString(mCategoryId);
parcel.writeFloat(mScore);
}
diff --git a/core/java/android/service/autofill/FillContext.java b/core/java/android/service/autofill/FillContext.java
index cda2f4a..535c00b 100644
--- a/core/java/android/service/autofill/FillContext.java
+++ b/core/java/android/service/autofill/FillContext.java
@@ -177,30 +177,6 @@
return foundNodes;
}
- /**
- * Finds the {@link ViewNode} that has the requested {@code id}, if any.
- *
- * @hide
- */
- @Nullable public ViewNode findViewNodeByAutofillId(@NonNull AutofillId id) {
- final LinkedList<ViewNode> nodesToProcess = new LinkedList<>();
- final int numWindowNodes = mStructure.getWindowNodeCount();
- for (int i = 0; i < numWindowNodes; i++) {
- nodesToProcess.add(mStructure.getWindowNodeAt(i).getRootViewNode());
- }
- while (!nodesToProcess.isEmpty()) {
- final ViewNode node = nodesToProcess.removeFirst();
- if (id.equals(node.getAutofillId())) {
- return node;
- }
- for (int i = 0; i < node.getChildCount(); i++) {
- nodesToProcess.addLast(node.getChildAt(i));
- }
- }
-
- return null;
- }
-
public static final Parcelable.Creator<FillContext> CREATOR =
new Parcelable.Creator<FillContext>() {
@Override
diff --git a/core/java/android/service/autofill/UserData.java b/core/java/android/service/autofill/UserData.java
index 6bab6aa..a1dd1f8 100644
--- a/core/java/android/service/autofill/UserData.java
+++ b/core/java/android/service/autofill/UserData.java
@@ -15,6 +15,7 @@
*/
package android.service.autofill;
+import static android.provider.Settings.Secure.AUTOFILL_USER_DATA_MAX_CATEGORY_COUNT;
import static android.provider.Settings.Secure.AUTOFILL_USER_DATA_MAX_FIELD_CLASSIFICATION_IDS_SIZE;
import static android.provider.Settings.Secure.AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE;
import static android.provider.Settings.Secure.AUTOFILL_USER_DATA_MAX_VALUE_LENGTH;
@@ -31,6 +32,7 @@
import android.provider.Settings;
import android.service.autofill.FieldClassification.Match;
import android.text.TextUtils;
+import android.util.ArraySet;
import android.util.Log;
import android.view.autofill.AutofillManager;
import android.view.autofill.Helper;
@@ -48,23 +50,24 @@
private static final String TAG = "UserData";
- private static final int DEFAULT_MAX_USER_DATA_SIZE = 10;
+ private static final int DEFAULT_MAX_USER_DATA_SIZE = 50;
+ private static final int DEFAULT_MAX_CATEGORY_COUNT = 10;
private static final int DEFAULT_MAX_FIELD_CLASSIFICATION_IDS_SIZE = 10;
- private static final int DEFAULT_MIN_VALUE_LENGTH = 5;
+ private static final int DEFAULT_MIN_VALUE_LENGTH = 3;
private static final int DEFAULT_MAX_VALUE_LENGTH = 100;
private final String mId;
private final String mAlgorithm;
private final Bundle mAlgorithmArgs;
- private final String[] mRemoteIds;
+ private final String[] mCategoryIds;
private final String[] mValues;
private UserData(Builder builder) {
mId = builder.mId;
mAlgorithm = builder.mAlgorithm;
mAlgorithmArgs = builder.mAlgorithmArgs;
- mRemoteIds = new String[builder.mRemoteIds.size()];
- builder.mRemoteIds.toArray(mRemoteIds);
+ mCategoryIds = new String[builder.mCategoryIds.size()];
+ builder.mCategoryIds.toArray(mCategoryIds);
mValues = new String[builder.mValues.size()];
builder.mValues.toArray(mValues);
}
@@ -91,8 +94,8 @@
}
/** @hide */
- public String[] getRemoteIds() {
- return mRemoteIds;
+ public String[] getCategoryIds() {
+ return mCategoryIds;
}
/** @hide */
@@ -106,11 +109,11 @@
pw.print(prefix); pw.print("Algorithm: "); pw.print(mAlgorithm);
pw.print(" Args: "); pw.println(mAlgorithmArgs);
- // Cannot disclose remote ids or values because they could contain PII
- pw.print(prefix); pw.print("Remote ids size: "); pw.println(mRemoteIds.length);
- for (int i = 0; i < mRemoteIds.length; i++) {
+ // Cannot disclose field ids or values because they could contain PII
+ pw.print(prefix); pw.print("Field ids size: "); pw.println(mCategoryIds.length);
+ for (int i = 0; i < mCategoryIds.length; i++) {
pw.print(prefix); pw.print(prefix); pw.print(i); pw.print(": ");
- pw.println(Helper.getRedacted(mRemoteIds[i]));
+ pw.println(Helper.getRedacted(mCategoryIds[i]));
}
pw.print(prefix); pw.print("Values size: "); pw.println(mValues.length);
for (int i = 0; i < mValues.length; i++) {
@@ -124,6 +127,7 @@
pw.print(prefix); pw.print("maxUserDataSize: "); pw.println(getMaxUserDataSize());
pw.print(prefix); pw.print("maxFieldClassificationIdsSize: ");
pw.println(getMaxFieldClassificationIdsSize());
+ pw.print(prefix); pw.print("maxCategoryCount: "); pw.println(getMaxCategoryCount());
pw.print(prefix); pw.print("minValueLength: "); pw.println(getMinValueLength());
pw.print(prefix); pw.print("maxValueLength: "); pw.println(getMaxValueLength());
}
@@ -133,44 +137,59 @@
*/
public static final class Builder {
private final String mId;
- private final ArrayList<String> mRemoteIds;
+ private final ArrayList<String> mCategoryIds;
private final ArrayList<String> mValues;
private String mAlgorithm;
private Bundle mAlgorithmArgs;
private boolean mDestroyed;
+ // Non-persistent array used to limit the number of unique ids.
+ private final ArraySet<String> mUniqueCategoryIds;
+
/**
* Creates a new builder for the user data used for <a href="#FieldClassification">field
* classification</a>.
*
- * <p>The user data must contain at least one pair of {@code remoteId} -> {@code value}, and
- * more pairs can be added through the {@link #add(String, String)} method.
+ * <p>The user data must contain at least one pair of {@code value} -> {@code categoryId},
+ * and more pairs can be added through the {@link #add(String, String)} method. For example:
+ *
+ * <pre class="prettyprint">
+ * new UserData.Builder("v1", "Bart Simpson", "name")
+ * .add("bart.simpson@example.com", "email")
+ * .add("el_barto@example.com", "email")
+ * .build();
+ * </pre>
*
* @param id id used to identify the whole {@link UserData} object. This id is also returned
* by {@link AutofillManager#getUserDataId()}, which can be used to check if the
* {@link UserData} is up-to-date without fetching the whole object (through
* {@link AutofillManager#getUserData()}).
- * @param remoteId unique string used to identify a user data value.
+ *
* @param value value of the user data.
+ * @param categoryId string used to identify the category the value is associated with.
*
* @throws IllegalArgumentException if any of the following occurs:
* <ol>
- * <li>{@code id} is empty
- * <li>{@code remoteId} is empty
- * <li>{@code value} is empty
- * <li>the length of {@code value} is lower than {@link UserData#getMinValueLength()}
- * <li>the length of {@code value} is higher than {@link UserData#getMaxValueLength()}
+ * <li>{@code id} is empty</li>
+ * <li>{@code categoryId} is empty</li>
+ * <li>{@code value} is empty</li>
+ * <li>the length of {@code value} is lower than {@link UserData#getMinValueLength()}</li>
+ * <li>the length of {@code value} is higher than
+ * {@link UserData#getMaxValueLength()}</li>
* </ol>
+ *
*/
- public Builder(@NonNull String id, @NonNull String remoteId, @NonNull String value) {
+ // TODO(b/70407264): ignore entry instead of throwing exception when settings changed
+ public Builder(@NonNull String id, @NonNull String value, @NonNull String categoryId) {
mId = checkNotEmpty("id", id);
- checkNotEmpty("remoteId", remoteId);
+ checkNotEmpty("categoryId", categoryId);
checkValidValue(value);
- final int capacity = getMaxUserDataSize();
- mRemoteIds = new ArrayList<>(capacity);
- mValues = new ArrayList<>(capacity);
- mRemoteIds.add(remoteId);
- mValues.add(value);
+ final int maxUserDataSize = getMaxUserDataSize();
+ mCategoryIds = new ArrayList<>(maxUserDataSize);
+ mValues = new ArrayList<>(maxUserDataSize);
+ mUniqueCategoryIds = new ArraySet<>(getMaxCategoryCount());
+
+ addMapping(value, categoryId);
}
/**
@@ -190,6 +209,7 @@
*/
public Builder setFieldClassificationAlgorithm(@Nullable String name,
@Nullable Bundle args) {
+ throwIfDestroyed();
mAlgorithm = name;
mAlgorithmArgs = args;
return this;
@@ -198,37 +218,58 @@
/**
* Adds a new value for user data.
*
- * @param remoteId unique string used to identify the user data.
* @param value value of the user data.
+ * @param categoryId string used to identify the category the value is associated with.
*
- * @throws IllegalStateException if {@link #build()} or
- * {@link #add(String, String)} with the same {@code remoteId} has already
- * been called, or if the number of values add (i.e., calls made to this method plus
- * constructor) is more than {@link UserData#getMaxUserDataSize()}.
+ * @throws IllegalStateException if:
+ * <ol>
+ * <li>{@link #build()} already called</li>
+ * <li>the {@code value} has already been added</li>
+ * <li>the number of unique {@code categoryId} values added so far is more than
+ * {@link UserData#getMaxCategoryCount()}</li>
+ * <li>the number of {@code values} added so far is is more than
+ * {@link UserData#getMaxUserDataSize()}</li>
+ * </ol>
*
- * @throws IllegalArgumentException if {@code remoteId} or {@code value} are empty or if the
- * length of {@code value} is lower than {@link UserData#getMinValueLength()}
- * or higher than {@link UserData#getMaxValueLength()}.
+ * @throws IllegalArgumentException if any of the following occurs:
+ * <ol>
+ * <li>{@code id} is empty</li>
+ * <li>{@code categoryId} is empty</li>
+ * <li>{@code value} is empty</li>
+ * <li>the length of {@code value} is lower than {@link UserData#getMinValueLength()}</li>
+ * <li>the length of {@code value} is higher than
+ * {@link UserData#getMaxValueLength()}</li>
+ * </ol>
*/
- public Builder add(@NonNull String remoteId, @NonNull String value) {
+ // TODO(b/70407264): ignore entry instead of throwing exception when settings changed
+ public Builder add(@NonNull String value, @NonNull String categoryId) {
throwIfDestroyed();
- checkNotEmpty("remoteId", remoteId);
+ checkNotEmpty("categoryId", categoryId);
checkValidValue(value);
- Preconditions.checkState(!mRemoteIds.contains(remoteId),
- // Don't include remoteId on message because it could contain PII
- "already has entry with same remoteId");
+ if (!mUniqueCategoryIds.contains(categoryId)) {
+ // New category - check size
+ Preconditions.checkState(mUniqueCategoryIds.size() < getMaxCategoryCount(),
+ "already added " + mUniqueCategoryIds.size() + " unique category ids");
+
+ }
+
Preconditions.checkState(!mValues.contains(value),
- // Don't include remoteId on message because it could contain PII
+ // Don't include value on message because it could contain PII
"already has entry with same value");
- Preconditions.checkState(mRemoteIds.size() < getMaxUserDataSize(),
- "already added " + mRemoteIds.size() + " elements");
- mRemoteIds.add(remoteId);
- mValues.add(value);
+ Preconditions.checkState(mValues.size() < getMaxUserDataSize(),
+ "already added " + mValues.size() + " elements");
+ addMapping(value, categoryId);
return this;
}
+ private void addMapping(@NonNull String value, @NonNull String categoryId) {
+ mCategoryIds.add(categoryId);
+ mValues.add(value);
+ mUniqueCategoryIds.add(categoryId);
+ }
+
private String checkNotEmpty(@NonNull String name, @Nullable String value) {
Preconditions.checkNotNull(value);
Preconditions.checkArgument(!TextUtils.isEmpty(value), "%s cannot be empty", name);
@@ -273,9 +314,9 @@
final StringBuilder builder = new StringBuilder("UserData: [id=").append(mId)
.append(", algorithm=").append(mAlgorithm);
- // Cannot disclose remote ids or values because they could contain PII
- builder.append(", remoteIds=");
- Helper.appendRedacted(builder, mRemoteIds);
+ // Cannot disclose category ids or values because they could contain PII
+ builder.append(", categoryIds=");
+ Helper.appendRedacted(builder, mCategoryIds);
builder.append(", values=");
Helper.appendRedacted(builder, mValues);
return builder.append("]").toString();
@@ -293,7 +334,7 @@
@Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeString(mId);
- parcel.writeStringArray(mRemoteIds);
+ parcel.writeStringArray(mCategoryIds);
parcel.writeStringArray(mValues);
parcel.writeString(mAlgorithm);
parcel.writeBundle(mAlgorithmArgs);
@@ -307,12 +348,12 @@
// the system obeys the contract of the builder to avoid attacks
// using specially crafted parcels.
final String id = parcel.readString();
- final String[] remoteIds = parcel.readStringArray();
+ final String[] categoryIds = parcel.readStringArray();
final String[] values = parcel.readStringArray();
- final Builder builder = new Builder(id, remoteIds[0], values[0])
+ final Builder builder = new Builder(id, values[0], categoryIds[0])
.setFieldClassificationAlgorithm(parcel.readString(), parcel.readBundle());
- for (int i = 1; i < remoteIds.length; i++) {
- builder.add(remoteIds[i], values[i]);
+ for (int i = 1; i < categoryIds.length; i++) {
+ builder.add(values[i], categoryIds[i]);
}
return builder.build();
}
@@ -340,6 +381,14 @@
}
/**
+ * Gets the maximum number of unique category ids that can be passed to
+ * the builder's constructor and {@link Builder#add(String, String)}.
+ */
+ public static int getMaxCategoryCount() {
+ return getInt(AUTOFILL_USER_DATA_MAX_CATEGORY_COUNT, DEFAULT_MAX_CATEGORY_COUNT);
+ }
+
+ /**
* Gets the minimum length of values passed to the builder's constructor or
* or {@link Builder#add(String, String)}.
*/
diff --git a/core/java/android/service/euicc/EuiccProfileInfo.java b/core/java/android/service/euicc/EuiccProfileInfo.java
index 8e752d1..cb4f104 100644
--- a/core/java/android/service/euicc/EuiccProfileInfo.java
+++ b/core/java/android/service/euicc/EuiccProfileInfo.java
@@ -17,6 +17,7 @@
import android.annotation.IntDef;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.service.carrier.CarrierIdentifier;
@@ -26,15 +27,15 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
+import java.util.List;
import java.util.Objects;
/**
* Information about an embedded profile (subscription) on an eUICC.
*
* @hide
- *
- * TODO(b/35851809): Make this a SystemApi.
*/
+@SystemApi
public final class EuiccProfileInfo implements Parcelable {
/** Profile policy rules (bit mask) */
@@ -44,6 +45,7 @@
POLICY_RULE_DO_NOT_DELETE,
POLICY_RULE_DELETE_AFTER_DISABLING
})
+ /** @hide */
public @interface PolicyRule {}
/** Once this profile is enabled, it cannot be disabled. */
public static final int POLICY_RULE_DO_NOT_DISABLE = 1;
@@ -60,6 +62,7 @@
PROFILE_CLASS_OPERATIONAL,
PROFILE_CLASS_UNSET
})
+ /** @hide */
public @interface ProfileClass {}
/** Testing profiles */
public static final int PROFILE_CLASS_TESTING = 0;
@@ -80,6 +83,7 @@
PROFILE_STATE_ENABLED,
PROFILE_STATE_UNSET
})
+ /** @hide */
public @interface ProfileState {}
/** Disabled profiles */
public static final int PROFILE_STATE_DISABLED = 0;
@@ -92,34 +96,34 @@
public static final int PROFILE_STATE_UNSET = -1;
/** The iccid of the subscription. */
- public final String iccid;
+ private final String mIccid;
/** An optional nickname for the subscription. */
- public final @Nullable String nickname;
+ private final @Nullable String mNickname;
/** The service provider name for the subscription. */
- public final String serviceProviderName;
+ private final String mServiceProviderName;
/** The profile name for the subscription. */
- public final String profileName;
+ private final String mProfileName;
/** Profile class for the subscription. */
- @ProfileClass public final int profileClass;
+ @ProfileClass private final int mProfileClass;
/** The profile state of the subscription. */
- @ProfileState public final int state;
+ @ProfileState private final int mState;
/** The operator Id of the subscription. */
- public final CarrierIdentifier carrierIdentifier;
+ private final CarrierIdentifier mCarrierIdentifier;
/** The policy rules of the subscription. */
- @PolicyRule public final int policyRules;
+ @PolicyRule private final int mPolicyRules;
/**
* Optional access rules defining which apps can manage this subscription. If unset, only the
* platform can manage it.
*/
- public final @Nullable UiccAccessRule[] accessRules;
+ private final @Nullable UiccAccessRule[] mAccessRules;
public static final Creator<EuiccProfileInfo> CREATOR = new Creator<EuiccProfileInfo>() {
@Override
@@ -144,51 +148,51 @@
if (!TextUtils.isDigitsOnly(iccid)) {
throw new IllegalArgumentException("iccid contains invalid characters: " + iccid);
}
- this.iccid = iccid;
- this.accessRules = accessRules;
- this.nickname = nickname;
+ this.mIccid = iccid;
+ this.mAccessRules = accessRules;
+ this.mNickname = nickname;
- this.serviceProviderName = null;
- this.profileName = null;
- this.profileClass = PROFILE_CLASS_UNSET;
- this.state = PROFILE_CLASS_UNSET;
- this.carrierIdentifier = null;
- this.policyRules = 0;
+ this.mServiceProviderName = null;
+ this.mProfileName = null;
+ this.mProfileClass = PROFILE_CLASS_UNSET;
+ this.mState = PROFILE_STATE_UNSET;
+ this.mCarrierIdentifier = null;
+ this.mPolicyRules = 0;
}
private EuiccProfileInfo(Parcel in) {
- iccid = in.readString();
- nickname = in.readString();
- serviceProviderName = in.readString();
- profileName = in.readString();
- profileClass = in.readInt();
- state = in.readInt();
+ mIccid = in.readString();
+ mNickname = in.readString();
+ mServiceProviderName = in.readString();
+ mProfileName = in.readString();
+ mProfileClass = in.readInt();
+ mState = in.readInt();
byte exist = in.readByte();
if (exist == (byte) 1) {
- carrierIdentifier = CarrierIdentifier.CREATOR.createFromParcel(in);
+ mCarrierIdentifier = CarrierIdentifier.CREATOR.createFromParcel(in);
} else {
- carrierIdentifier = null;
+ mCarrierIdentifier = null;
}
- policyRules = in.readInt();
- accessRules = in.createTypedArray(UiccAccessRule.CREATOR);
+ mPolicyRules = in.readInt();
+ mAccessRules = in.createTypedArray(UiccAccessRule.CREATOR);
}
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(iccid);
- dest.writeString(nickname);
- dest.writeString(serviceProviderName);
- dest.writeString(profileName);
- dest.writeInt(profileClass);
- dest.writeInt(state);
- if (carrierIdentifier != null) {
+ dest.writeString(mIccid);
+ dest.writeString(mNickname);
+ dest.writeString(mServiceProviderName);
+ dest.writeString(mProfileName);
+ dest.writeInt(mProfileClass);
+ dest.writeInt(mState);
+ if (mCarrierIdentifier != null) {
dest.writeByte((byte) 1);
- carrierIdentifier.writeToParcel(dest, flags);
+ mCarrierIdentifier.writeToParcel(dest, flags);
} else {
dest.writeByte((byte) 0);
}
- dest.writeInt(policyRules);
- dest.writeTypedArray(accessRules, flags);
+ dest.writeInt(mPolicyRules);
+ dest.writeTypedArray(mAccessRules, flags);
}
@Override
@@ -198,45 +202,50 @@
/** The builder to build a new {@link EuiccProfileInfo} instance. */
public static final class Builder {
- public String iccid;
- public UiccAccessRule[] accessRules;
- public String nickname;
- public String serviceProviderName;
- public String profileName;
- @ProfileClass public int profileClass;
- @ProfileState public int state;
- public CarrierIdentifier carrierIdentifier;
- @PolicyRule public int policyRules;
+ private String mIccid;
+ private List<UiccAccessRule> mAccessRules;
+ private String mNickname;
+ private String mServiceProviderName;
+ private String mProfileName;
+ @ProfileClass private int mProfileClass;
+ @ProfileState private int mState;
+ private CarrierIdentifier mCarrierIdentifier;
+ @PolicyRule private int mPolicyRules;
- public Builder() {}
+ public Builder(String value) {
+ if (!TextUtils.isDigitsOnly(value)) {
+ throw new IllegalArgumentException("iccid contains invalid characters: " + value);
+ }
+ mIccid = value;
+ }
public Builder(EuiccProfileInfo baseProfile) {
- iccid = baseProfile.iccid;
- nickname = baseProfile.nickname;
- serviceProviderName = baseProfile.serviceProviderName;
- profileName = baseProfile.profileName;
- profileClass = baseProfile.profileClass;
- state = baseProfile.state;
- carrierIdentifier = baseProfile.carrierIdentifier;
- policyRules = baseProfile.policyRules;
- accessRules = baseProfile.accessRules;
+ mIccid = baseProfile.mIccid;
+ mNickname = baseProfile.mNickname;
+ mServiceProviderName = baseProfile.mServiceProviderName;
+ mProfileName = baseProfile.mProfileName;
+ mProfileClass = baseProfile.mProfileClass;
+ mState = baseProfile.mState;
+ mCarrierIdentifier = baseProfile.mCarrierIdentifier;
+ mPolicyRules = baseProfile.mPolicyRules;
+ mAccessRules = Arrays.asList(baseProfile.mAccessRules);
}
/** Builds the profile instance. */
public EuiccProfileInfo build() {
- if (iccid == null) {
+ if (mIccid == null) {
throw new IllegalStateException("ICCID must be set for a profile.");
}
return new EuiccProfileInfo(
- iccid,
- nickname,
- serviceProviderName,
- profileName,
- profileClass,
- state,
- carrierIdentifier,
- policyRules,
- accessRules);
+ mIccid,
+ mNickname,
+ mServiceProviderName,
+ mProfileName,
+ mProfileClass,
+ mState,
+ mCarrierIdentifier,
+ mPolicyRules,
+ mAccessRules);
}
/** Sets the iccId of the subscription. */
@@ -244,55 +253,55 @@
if (!TextUtils.isDigitsOnly(value)) {
throw new IllegalArgumentException("iccid contains invalid characters: " + value);
}
- iccid = value;
+ mIccid = value;
return this;
}
/** Sets the nickname of the subscription. */
public Builder setNickname(String value) {
- nickname = value;
+ mNickname = value;
return this;
}
/** Sets the service provider name of the subscription. */
public Builder setServiceProviderName(String value) {
- serviceProviderName = value;
+ mServiceProviderName = value;
return this;
}
/** Sets the profile name of the subscription. */
public Builder setProfileName(String value) {
- profileName = value;
+ mProfileName = value;
return this;
}
/** Sets the profile class of the subscription. */
public Builder setProfileClass(@ProfileClass int value) {
- profileClass = value;
+ mProfileClass = value;
return this;
}
/** Sets the state of the subscription. */
public Builder setState(@ProfileState int value) {
- state = value;
+ mState = value;
return this;
}
/** Sets the carrier identifier of the subscription. */
public Builder setCarrierIdentifier(CarrierIdentifier value) {
- carrierIdentifier = value;
+ mCarrierIdentifier = value;
return this;
}
/** Sets the policy rules of the subscription. */
public Builder setPolicyRules(@PolicyRule int value) {
- policyRules = value;
+ mPolicyRules = value;
return this;
}
/** Sets the access rules of the subscription. */
- public Builder setUiccAccessRule(@Nullable UiccAccessRule[] value) {
- accessRules = value;
+ public Builder setUiccAccessRule(@Nullable List<UiccAccessRule> value) {
+ mAccessRules = value;
return this;
}
}
@@ -306,75 +315,81 @@
@ProfileState int state,
CarrierIdentifier carrierIdentifier,
@PolicyRule int policyRules,
- @Nullable UiccAccessRule[] accessRules) {
- this.iccid = iccid;
- this.nickname = nickname;
- this.serviceProviderName = serviceProviderName;
- this.profileName = profileName;
- this.profileClass = profileClass;
- this.state = state;
- this.carrierIdentifier = carrierIdentifier;
- this.policyRules = policyRules;
- this.accessRules = accessRules;
+ @Nullable List<UiccAccessRule> accessRules) {
+ this.mIccid = iccid;
+ this.mNickname = nickname;
+ this.mServiceProviderName = serviceProviderName;
+ this.mProfileName = profileName;
+ this.mProfileClass = profileClass;
+ this.mState = state;
+ this.mCarrierIdentifier = carrierIdentifier;
+ this.mPolicyRules = policyRules;
+ if (accessRules != null && accessRules.size() > 0) {
+ this.mAccessRules = accessRules.toArray(new UiccAccessRule[accessRules.size()]);
+ } else {
+ this.mAccessRules = null;
+ }
}
/** Gets the ICCID string. */
public String getIccid() {
- return iccid;
+ return mIccid;
}
/** Gets the access rules. */
@Nullable
- public UiccAccessRule[] getUiccAccessRules() {
- return accessRules;
+ public List<UiccAccessRule> getUiccAccessRules() {
+ if (mAccessRules == null) return null;
+ return Arrays.asList(mAccessRules);
}
/** Gets the nickname. */
+ @Nullable
public String getNickname() {
- return nickname;
+ return mNickname;
}
/** Gets the service provider name. */
public String getServiceProviderName() {
- return serviceProviderName;
+ return mServiceProviderName;
}
/** Gets the profile name. */
public String getProfileName() {
- return profileName;
+ return mProfileName;
}
/** Gets the profile class. */
@ProfileClass
public int getProfileClass() {
- return profileClass;
+ return mProfileClass;
}
/** Gets the state of the subscription. */
@ProfileState
public int getState() {
- return state;
+ return mState;
}
/** Gets the carrier identifier. */
public CarrierIdentifier getCarrierIdentifier() {
- return carrierIdentifier;
+ return mCarrierIdentifier;
}
/** Gets the policy rules. */
@PolicyRule
public int getPolicyRules() {
- return policyRules;
+ return mPolicyRules;
}
/** Returns whether any policy rule exists. */
public boolean hasPolicyRules() {
- return policyRules != 0;
+ return mPolicyRules != 0;
}
/** Checks whether a certain policy rule exists. */
public boolean hasPolicyRule(@PolicyRule int policy) {
- return (policyRules & policy) != 0;
+ return (mPolicyRules & policy) != 0;
}
@Override
@@ -387,50 +402,50 @@
}
EuiccProfileInfo that = (EuiccProfileInfo) obj;
- return Objects.equals(iccid, that.iccid)
- && Objects.equals(nickname, that.nickname)
- && Objects.equals(serviceProviderName, that.serviceProviderName)
- && Objects.equals(profileName, that.profileName)
- && profileClass == that.profileClass
- && state == that.state
- && Objects.equals(carrierIdentifier, that.carrierIdentifier)
- && policyRules == that.policyRules
- && Arrays.equals(accessRules, that.accessRules);
+ return Objects.equals(mIccid, that.mIccid)
+ && Objects.equals(mNickname, that.mNickname)
+ && Objects.equals(mServiceProviderName, that.mServiceProviderName)
+ && Objects.equals(mProfileName, that.mProfileName)
+ && mProfileClass == that.mProfileClass
+ && mState == that.mState
+ && Objects.equals(mCarrierIdentifier, that.mCarrierIdentifier)
+ && mPolicyRules == that.mPolicyRules
+ && Arrays.equals(mAccessRules, that.mAccessRules);
}
@Override
public int hashCode() {
int result = 1;
- result = 31 * result + Objects.hashCode(iccid);
- result = 31 * result + Objects.hashCode(nickname);
- result = 31 * result + Objects.hashCode(serviceProviderName);
- result = 31 * result + Objects.hashCode(profileName);
- result = 31 * result + profileClass;
- result = 31 * result + state;
- result = 31 * result + Objects.hashCode(carrierIdentifier);
- result = 31 * result + policyRules;
- result = 31 * result + Arrays.hashCode(accessRules);
+ result = 31 * result + Objects.hashCode(mIccid);
+ result = 31 * result + Objects.hashCode(mNickname);
+ result = 31 * result + Objects.hashCode(mServiceProviderName);
+ result = 31 * result + Objects.hashCode(mProfileName);
+ result = 31 * result + mProfileClass;
+ result = 31 * result + mState;
+ result = 31 * result + Objects.hashCode(mCarrierIdentifier);
+ result = 31 * result + mPolicyRules;
+ result = 31 * result + Arrays.hashCode(mAccessRules);
return result;
}
@Override
public String toString() {
return "EuiccProfileInfo (nickname="
- + nickname
+ + mNickname
+ ", serviceProviderName="
- + serviceProviderName
+ + mServiceProviderName
+ ", profileName="
- + profileName
+ + mProfileName
+ ", profileClass="
- + profileClass
+ + mProfileClass
+ ", state="
- + state
+ + mState
+ ", CarrierIdentifier="
- + carrierIdentifier.toString()
+ + mCarrierIdentifier.toString()
+ ", policyRules="
- + policyRules
+ + mPolicyRules
+ ", accessRules="
- + Arrays.toString(accessRules)
+ + Arrays.toString(mAccessRules)
+ ")";
}
}
diff --git a/core/java/android/service/euicc/EuiccService.java b/core/java/android/service/euicc/EuiccService.java
index be85800..b87faef 100644
--- a/core/java/android/service/euicc/EuiccService.java
+++ b/core/java/android/service/euicc/EuiccService.java
@@ -17,6 +17,7 @@
import android.annotation.CallSuper;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
@@ -41,8 +42,11 @@
* <p>To implement the LPA backend, you must extend this class and declare this service in your
* manifest file. The service must require the
* {@link android.Manifest.permission#BIND_EUICC_SERVICE} permission and include an intent filter
- * with the {@link #EUICC_SERVICE_INTERFACE} action. The priority of the intent filter must be set
- * to a non-zero value in case multiple implementations are present on the device. For example:
+ * with the {@link #EUICC_SERVICE_INTERFACE} action. It's suggested that the priority of the intent
+ * filter to be set to a non-zero value in case multiple implementations are present on the device.
+ * See the below example. Note that there will be problem if two LPAs are present and they have the
+ * same priority.
+ * Example:
*
* <pre>{@code
* <service android:name=".MyEuiccService"
@@ -65,9 +69,9 @@
* filter with the appropriate action, the {@link #CATEGORY_EUICC_UI} category, and a non-zero
* priority.
*
- * TODO(b/35851809): Make this a SystemApi.
* @hide
*/
+@SystemApi
public abstract class EuiccService extends Service {
/** Action which must be included in this service's intent filter. */
public static final String EUICC_SERVICE_INTERFACE = "android.service.euicc.EuiccService";
@@ -77,7 +81,10 @@
// LUI actions. These are passthroughs of the corresponding EuiccManager actions.
- /** @see android.telephony.euicc.EuiccManager#ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS */
+ /**
+ * @see android.telephony.euicc.EuiccManager#ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS
+ * The difference is this one is used by system to bring up the LUI.
+ */
public static final String ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS =
"android.service.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS";
/** @see android.telephony.euicc.EuiccManager#ACTION_PROVISION_EMBEDDED_SUBSCRIPTION */
@@ -88,7 +95,10 @@
// require user interaction.
// TODO(b/33075886): Define extras for any input parameters to these dialogs once they are
// more scoped out.
- /** Alert the user that this action will result in an active SIM being deactivated. */
+ /**
+ * Alert the user that this action will result in an active SIM being deactivated.
+ * To implement the LUI triggered by the system, you need to define this in AndroidManifest.xml.
+ */
public static final String ACTION_RESOLVE_DEACTIVATE_SIM =
"android.service.euicc.action.RESOLVE_DEACTIVATE_SIM";
/**
@@ -102,7 +112,11 @@
public static final String ACTION_RESOLVE_CONFIRMATION_CODE =
"android.service.euicc.action.RESOLVE_CONFIRMATION_CODE";
- /** Intent extra set for resolution requests containing the package name of the calling app. */
+ /**
+ * Intent extra set for resolution requests containing the package name of the calling app.
+ * This is used by the above actions including ACTION_RESOLVE_DEACTIVATE_SIM,
+ * ACTION_RESOLVE_NO_PRIVILEGES and ACTION_RESOLVE_CONFIRMATION_CODE.
+ */
public static final String EXTRA_RESOLUTION_CALLING_PACKAGE =
"android.service.euicc.extra.RESOLUTION_CALLING_PACKAGE";
@@ -136,10 +150,18 @@
RESOLUTION_ACTIONS.add(EuiccService.ACTION_RESOLVE_CONFIRMATION_CODE);
}
- /** Boolean extra for resolution actions indicating whether the user granted consent. */
- public static final String RESOLUTION_EXTRA_CONSENT = "consent";
- /** String extra for resolution actions indicating the carrier confirmation code. */
- public static final String RESOLUTION_EXTRA_CONFIRMATION_CODE = "confirmation_code";
+ /**
+ * Boolean extra for resolution actions indicating whether the user granted consent.
+ * This is used and set by the implementation and used in {@code EuiccOperation}.
+ */
+ public static final String EXTRA_RESOLUTION_CONSENT =
+ "android.service.euicc.extra.RESOLUTION_CONSENT";
+ /**
+ * String extra for resolution actions indicating the carrier confirmation code.
+ * This is used and set by the implementation and used in {@code EuiccOperation}.
+ */
+ public static final String EXTRA_RESOLUTION_CONFIRMATION_CODE =
+ "android.service.euicc.extra.RESOLUTION_CONFIRMATION_CODE";
private final IEuiccService.Stub mStubWrapper;
@@ -199,9 +221,9 @@
*
* @see IEuiccService#startOtaIfNecessary
*/
- public interface OtaStatusChangedCallback {
+ public abstract static class OtaStatusChangedCallback {
/** Called when OTA status is changed. */
- void onOtaStatusChanged(int status);
+ public abstract void onOtaStatusChanged(int status);
}
/**
@@ -238,8 +260,7 @@
/**
* Populate {@link DownloadableSubscription} metadata for the given downloadable subscription.
*
- * @param slotId ID of the SIM slot to use for the operation. This is currently not populated
- * but is here to future-proof the APIs.
+ * @param slotId ID of the SIM slot to use for the operation.
* @param subscription A subscription whose metadata needs to be populated.
* @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the
* eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM)}
@@ -267,8 +288,7 @@
/**
* Download the given subscription.
*
- * @param slotId ID of the SIM slot to use for the operation. This is currently not populated
- * but is here to future-proof the APIs.
+ * @param slotId ID of the SIM slot to use for the operation.
* @param subscription The subscription to download.
* @param switchAfterDownload If true, the subscription should be enabled upon successful
* download.
@@ -286,8 +306,7 @@
/**
* Return a list of all @link EuiccProfileInfo}s.
*
- * @param slotId ID of the SIM slot to use for the operation. This is currently not populated
- * but is here to future-proof the APIs.
+ * @param slotId ID of the SIM slot to use for the operation.
* @return The result of the operation.
* @see android.telephony.SubscriptionManager#getAvailableSubscriptionInfoList
* @see android.telephony.SubscriptionManager#getAccessibleSubscriptionInfoList
@@ -297,8 +316,7 @@
/**
* Return info about the eUICC chip/device.
*
- * @param slotId ID of the SIM slot to use for the operation. This is currently not populated
- * but is here to future-proof the APIs.
+ * @param slotId ID of the SIM slot to use for the operation.
* @return the {@link EuiccInfo} for the eUICC chip/device.
* @see android.telephony.euicc.EuiccManager#getEuiccInfo
*/
@@ -310,8 +328,7 @@
* <p>If the subscription is currently active, it should be deactivated first (equivalent to a
* physical SIM being ejected).
*
- * @param slotId ID of the SIM slot to use for the operation. This is currently not populated
- * but is here to future-proof the APIs.
+ * @param slotId ID of the SIM slot to use for the operation.
* @param iccid the ICCID of the subscription to delete.
* @return the result of the delete operation. May be one of the predefined {@code RESULT_}
* constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}.
@@ -322,8 +339,7 @@
/**
* Switch to the given subscription.
*
- * @param slotId ID of the SIM slot to use for the operation. This is currently not populated
- * but is here to future-proof the APIs.
+ * @param slotId ID of the SIM slot to use for the operation.
* @param iccid the ICCID of the subscription to enable. May be null, in which case the current
* profile should be deactivated and no profile should be activated to replace it - this is
* equivalent to a physical SIM being ejected.
@@ -340,8 +356,7 @@
/**
* Update the nickname of the given subscription.
*
- * @param slotId ID of the SIM slot to use for the operation. This is currently not populated
- * but is here to future-proof the APIs.
+ * @param slotId ID of the SIM slot to use for the operation.
* @param iccid the ICCID of the subscription to update.
* @param nickname the new nickname to apply.
* @return the result of the update operation. May be one of the predefined {@code RESULT_}
diff --git a/core/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java b/core/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java
index 5a24492..e2171ae 100644
--- a/core/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java
+++ b/core/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java
@@ -16,16 +16,19 @@
package android.service.euicc;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.telephony.euicc.DownloadableSubscription;
+import java.util.Arrays;
+import java.util.List;
+
/**
* Result of a {@link EuiccService#onGetDefaultDownloadableSubscriptionList} operation.
* @hide
- *
- * TODO(b/35851809): Make this a SystemApi.
*/
+@SystemApi
public final class GetDefaultDownloadableSubscriptionListResult implements Parcelable {
public static final Creator<GetDefaultDownloadableSubscriptionListResult> CREATOR =
@@ -42,20 +45,35 @@
};
/**
- * Result of the operation.
+ * @hide
+ * @deprecated - Do no use. Use getResult() instead.
+ */
+ @Deprecated
+ public final int result;
+
+ @Nullable
+ private final DownloadableSubscription[] mSubscriptions;
+
+ /**
+ * Gets the result of the operation.
*
* <p>May be one of the predefined {@code RESULT_} constants in EuiccService or any
* implementation-specific code starting with {@link EuiccService#RESULT_FIRST_USER}.
*/
- public final int result;
+ public int getResult() {
+ return result;
+ }
/**
- * The available {@link DownloadableSubscription}s (with filled-in metadata).
+ * Gets the available {@link DownloadableSubscription}s (with filled-in metadata).
*
* <p>Only non-null if {@link #result} is {@link EuiccService#RESULT_OK}.
*/
@Nullable
- public final DownloadableSubscription[] subscriptions;
+ public List<DownloadableSubscription> getDownloadableSubscriptions() {
+ if (mSubscriptions == null) return null;
+ return Arrays.asList(mSubscriptions);
+ }
/**
* Construct a new {@link GetDefaultDownloadableSubscriptionListResult}.
@@ -70,25 +88,25 @@
@Nullable DownloadableSubscription[] subscriptions) {
this.result = result;
if (this.result == EuiccService.RESULT_OK) {
- this.subscriptions = subscriptions;
+ this.mSubscriptions = subscriptions;
} else {
if (subscriptions != null) {
throw new IllegalArgumentException(
"Error result with non-null subscriptions: " + result);
}
- this.subscriptions = null;
+ this.mSubscriptions = null;
}
}
private GetDefaultDownloadableSubscriptionListResult(Parcel in) {
this.result = in.readInt();
- this.subscriptions = in.createTypedArray(DownloadableSubscription.CREATOR);
+ this.mSubscriptions = in.createTypedArray(DownloadableSubscription.CREATOR);
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(result);
- dest.writeTypedArray(subscriptions, flags);
+ dest.writeTypedArray(mSubscriptions, flags);
}
@Override
diff --git a/core/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java b/core/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java
index de8a307..1edb539 100644
--- a/core/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java
+++ b/core/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java
@@ -16,6 +16,7 @@
package android.service.euicc;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.telephony.euicc.DownloadableSubscription;
@@ -23,9 +24,8 @@
/**
* Result of a {@link EuiccService#onGetDownloadableSubscriptionMetadata} operation.
* @hide
- *
- * TODO(b/35851809): Make this a SystemApi.
*/
+@SystemApi
public final class GetDownloadableSubscriptionMetadataResult implements Parcelable {
public static final Creator<GetDownloadableSubscriptionMetadataResult> CREATOR =
@@ -42,20 +42,34 @@
};
/**
- * Result of the operation.
+ * @hide
+ * @deprecated - Do no use. Use getResult() instead.
+ */
+ @Deprecated
+ public final int result;
+
+ @Nullable
+ private final DownloadableSubscription mSubscription;
+
+ /**
+ * Gets the result of the operation.
*
* <p>May be one of the predefined {@code RESULT_} constants in EuiccService or any
* implementation-specific code starting with {@link EuiccService#RESULT_FIRST_USER}.
*/
- public final int result;
+ public int getResult() {
+ return result;
+ }
/**
- * The {@link DownloadableSubscription} with filled-in metadata.
+ * Gets the {@link DownloadableSubscription} with filled-in metadata.
*
* <p>Only non-null if {@link #result} is {@link EuiccService#RESULT_OK}.
*/
@Nullable
- public final DownloadableSubscription subscription;
+ public DownloadableSubscription getDownloadableSubscription() {
+ return mSubscription;
+ }
/**
* Construct a new {@link GetDownloadableSubscriptionMetadataResult}.
@@ -70,25 +84,25 @@
@Nullable DownloadableSubscription subscription) {
this.result = result;
if (this.result == EuiccService.RESULT_OK) {
- this.subscription = subscription;
+ this.mSubscription = subscription;
} else {
if (subscription != null) {
throw new IllegalArgumentException(
"Error result with non-null subscription: " + result);
}
- this.subscription = null;
+ this.mSubscription = null;
}
}
private GetDownloadableSubscriptionMetadataResult(Parcel in) {
this.result = in.readInt();
- this.subscription = in.readTypedObject(DownloadableSubscription.CREATOR);
+ this.mSubscription = in.readTypedObject(DownloadableSubscription.CREATOR);
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(result);
- dest.writeTypedObject(this.subscription, flags);
+ dest.writeTypedObject(this.mSubscription, flags);
}
@Override
diff --git a/core/java/android/service/euicc/GetEuiccProfileInfoListResult.java b/core/java/android/service/euicc/GetEuiccProfileInfoListResult.java
index 7ad8488..464d136 100644
--- a/core/java/android/service/euicc/GetEuiccProfileInfoListResult.java
+++ b/core/java/android/service/euicc/GetEuiccProfileInfoListResult.java
@@ -16,15 +16,18 @@
package android.service.euicc;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.Arrays;
+import java.util.List;
+
/**
* Result of a {@link EuiccService#onGetEuiccProfileInfoList} operation.
* @hide
- *
- * TODO(b/35851809): Make this a SystemApi.
*/
+@SystemApi
public final class GetEuiccProfileInfoListResult implements Parcelable {
public static final Creator<GetEuiccProfileInfoListResult> CREATOR =
@@ -41,19 +44,38 @@
};
/**
- * Result of the operation.
+ * @hide
+ * @deprecated - Do no use. Use getResult() instead.
+ */
+ @Deprecated
+ public final int result;
+
+ @Nullable
+ private final EuiccProfileInfo[] mProfiles;
+
+ private final boolean mIsRemovable;
+
+ /**
+ * Gets the result of the operation.
*
* <p>May be one of the predefined {@code RESULT_} constants in EuiccService or any
* implementation-specific code starting with {@link EuiccService#RESULT_FIRST_USER}.
*/
- public final int result;
+ public int getResult() {
+ return result;
+ }
- /** The profile list (only upon success). */
+ /** Gets the profile list (only upon success). */
@Nullable
- public final EuiccProfileInfo[] profiles;
+ public List<EuiccProfileInfo> getProfiles() {
+ if (mProfiles == null) return null;
+ return Arrays.asList(mProfiles);
+ }
- /** Whether the eUICC is removable. */
- public final boolean isRemovable;
+ /** Gets whether the eUICC is removable. */
+ public boolean getIsRemovable() {
+ return mIsRemovable;
+ }
/**
* Construct a new {@link GetEuiccProfileInfoListResult}.
@@ -71,30 +93,29 @@
public GetEuiccProfileInfoListResult(
int result, @Nullable EuiccProfileInfo[] profiles, boolean isRemovable) {
this.result = result;
- this.isRemovable = isRemovable;
+ this.mIsRemovable = isRemovable;
if (this.result == EuiccService.RESULT_OK) {
- this.profiles = profiles;
+ this.mProfiles = profiles;
} else {
if (profiles != null) {
throw new IllegalArgumentException(
"Error result with non-null profiles: " + result);
}
- this.profiles = null;
+ this.mProfiles = null;
}
-
}
private GetEuiccProfileInfoListResult(Parcel in) {
this.result = in.readInt();
- this.profiles = in.createTypedArray(EuiccProfileInfo.CREATOR);
- this.isRemovable = in.readBoolean();
+ this.mProfiles = in.createTypedArray(EuiccProfileInfo.CREATOR);
+ this.mIsRemovable = in.readBoolean();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(result);
- dest.writeTypedArray(profiles, flags);
- dest.writeBoolean(isRemovable);
+ dest.writeTypedArray(mProfiles, flags);
+ dest.writeBoolean(mIsRemovable);
}
@Override
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index d66322c..171d4d9 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -94,7 +94,7 @@
private static final boolean DEFAULT_ALLOW_SCREEN_OFF = true;
private static final boolean DEFAULT_ALLOW_SCREEN_ON = true;
- private static final int XML_VERSION = 2;
+ public static final int XML_VERSION = 3;
public static final String ZEN_TAG = "zen";
private static final String ZEN_ATT_VERSION = "version";
private static final String ZEN_ATT_USER = "user";
@@ -145,6 +145,7 @@
public int user = UserHandle.USER_SYSTEM;
public boolean allowWhenScreenOff = DEFAULT_ALLOW_SCREEN_OFF;
public boolean allowWhenScreenOn = DEFAULT_ALLOW_SCREEN_ON;
+ public int version;
public ZenRule manualRule;
public ArrayMap<String, ZenRule> automaticRules = new ArrayMap<>();
@@ -431,6 +432,7 @@
String tag = parser.getName();
if (!ZEN_TAG.equals(tag)) return null;
final ZenModeConfig rt = new ZenModeConfig();
+ rt.version = safeInt(parser, ZEN_ATT_VERSION, XML_VERSION);
rt.user = safeInt(parser, ZEN_ATT_USER, rt.user);
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
tag = parser.getName();
diff --git a/core/java/android/speech/tts/SynthesisPlaybackQueueItem.java b/core/java/android/speech/tts/SynthesisPlaybackQueueItem.java
index 704a1da..2ed618b 100644
--- a/core/java/android/speech/tts/SynthesisPlaybackQueueItem.java
+++ b/core/java/android/speech/tts/SynthesisPlaybackQueueItem.java
@@ -15,17 +15,17 @@
*/
package android.speech.tts;
+import android.media.AudioTrack;
import android.speech.tts.TextToSpeechService.AudioOutputParams;
import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
-import android.media.AudioTrack;
import android.util.Log;
import java.util.LinkedList;
+import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
-import java.util.concurrent.ConcurrentLinkedQueue;
/**
* Manages the playback of a list of byte arrays representing audio data that are queued by the
@@ -157,9 +157,16 @@
mStopped = true;
mStatusCode = statusCode;
+ // Wake up the synthesis thread if it was waiting on put(). Its
+ // buffers will no longer be copied since mStopped is true. The
+ // PlaybackSynthesisCallback that this synthesis corresponds to
+ // would also have been stopped, and so all calls to
+ // Callback.onDataAvailable( ) will return errors too.
+ mNotFull.signal();
+
if (mRunState.getAndSet(STOP_CALLED) == NOT_RUN) {
- // Dispatch the status code and just finish without signaling
- // if run() has not even started.
+ // Dispatch the status code and just finish. Signaling audio
+ // playback is not necessary because run() hasn't started.
dispatchEndStatus();
return;
}
@@ -168,13 +175,6 @@
// take() will return null since mStopped was true, and will then
// break out of the data write loop.
mReadReady.signal();
-
- // Wake up the synthesis thread if it was waiting on put(). Its
- // buffers will no longer be copied since mStopped is true. The
- // PlaybackSynthesisCallback that this synthesis corresponds to
- // would also have been stopped, and so all calls to
- // Callback.onDataAvailable( ) will return errors too.
- mNotFull.signal();
} finally {
mListLock.unlock();
}
diff --git a/core/java/android/transition/TransitionUtils.java b/core/java/android/transition/TransitionUtils.java
index 60b77bc..46c9e0c 100644
--- a/core/java/android/transition/TransitionUtils.java
+++ b/core/java/android/transition/TransitionUtils.java
@@ -20,14 +20,13 @@
import android.animation.AnimatorSet;
import android.animation.TypeEvaluator;
import android.graphics.Bitmap;
+import android.graphics.Canvas;
import android.graphics.Matrix;
+import android.graphics.Picture;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
-import android.view.DisplayListCanvas;
-import android.view.RenderNode;
-import android.view.ThreadedRenderer;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
@@ -128,10 +127,8 @@
}
int bitmapWidth = (int) (width * scale);
int bitmapHeight = (int) (height * scale);
- final RenderNode node = RenderNode.create("TransitionUtils", hostView);
- node.setLeftTopRightBottom(0, 0, width, height);
- node.setClipToBounds(false);
- final DisplayListCanvas canvas = node.start(width, height);
+ final Picture picture = new Picture();
+ final Canvas canvas = picture.beginRecording(width, height);
// Do stuff with the canvas
Rect existingBounds = drawable.getBounds();
int left = existingBounds.left;
@@ -141,8 +138,8 @@
drawable.setBounds(0, 0, bitmapWidth, bitmapHeight);
drawable.draw(canvas);
drawable.setBounds(left, top, right, bottom);
- node.end(canvas);
- return ThreadedRenderer.createHardwareBitmap(node, width, height);
+ picture.endRecording();
+ return Bitmap.createBitmap(picture);
}
/**
@@ -183,14 +180,12 @@
matrix.postTranslate(-bounds.left, -bounds.top);
matrix.postScale(scale, scale);
- final RenderNode node = RenderNode.create("TransitionUtils", view);
- node.setLeftTopRightBottom(0, 0, bitmapWidth, bitmapHeight);
- node.setClipToBounds(false);
- final DisplayListCanvas canvas = node.start(bitmapWidth, bitmapHeight);
+ final Picture picture = new Picture();
+ final Canvas canvas = picture.beginRecording(bitmapWidth, bitmapHeight);
canvas.concat(matrix);
view.draw(canvas);
- node.end(canvas);
- bitmap = ThreadedRenderer.createHardwareBitmap(node, bitmapWidth, bitmapHeight);
+ picture.endRecording();
+ bitmap = Bitmap.createBitmap(picture);
}
if (addToOverlay) {
sceneRoot.getOverlay().remove(view);
diff --git a/core/java/android/util/ExceptionUtils.java b/core/java/android/util/ExceptionUtils.java
index da7387f..1a397b3 100644
--- a/core/java/android/util/ExceptionUtils.java
+++ b/core/java/android/util/ExceptionUtils.java
@@ -86,4 +86,16 @@
while (t.getCause() != null) t = t.getCause();
return t;
}
-}
+
+ /**
+ * Appends {@code cause} at the end of the causal chain of {@code t}
+ *
+ * @return {@code t} for convenience
+ */
+ public static @NonNull Throwable appendCause(@NonNull Throwable t, @Nullable Throwable cause) {
+ if (cause != null) {
+ getRootCause(t).initCause(cause);
+ }
+ return t;
+ }
+}
\ No newline at end of file
diff --git a/core/java/android/util/MemoryIntArray.java b/core/java/android/util/MemoryIntArray.java
index 5970892..bf33519 100644
--- a/core/java/android/util/MemoryIntArray.java
+++ b/core/java/android/util/MemoryIntArray.java
@@ -16,18 +16,12 @@
package android.util;
-import static android.os.Process.FIRST_APPLICATION_UID;
-
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
-import android.os.Process;
-
-import com.android.internal.annotations.GuardedBy;
-
-import dalvik.system.CloseGuard;
import libcore.io.IoUtils;
+import dalvik.system.CloseGuard;
import java.io.Closeable;
import java.io.IOException;
@@ -55,18 +49,13 @@
*/
public final class MemoryIntArray implements Parcelable, Closeable {
private static final String TAG = "MemoryIntArray";
- private static final boolean DEBUG = Process.myUid() < FIRST_APPLICATION_UID;
private static final int MAX_SIZE = 1024;
- private final Object mLock = new Object();
private final CloseGuard mCloseGuard = CloseGuard.get();
private final boolean mIsOwner;
private final long mMemoryAddr;
-
- /** Fd for the shared memory object, -1 when closed */
- @GuardedBy("mLock")
private int mFd = -1;
/**
@@ -85,7 +74,6 @@
mFd = nativeCreate(name, size);
mMemoryAddr = nativeOpen(mFd, mIsOwner);
mCloseGuard.open("close");
- if (DEBUG) Log.i(TAG, "created " + getString());
}
private MemoryIntArray(Parcel parcel) throws IOException {
@@ -97,8 +85,6 @@
mFd = pfd.detachFd();
mMemoryAddr = nativeOpen(mFd, mIsOwner);
mCloseGuard.open("close");
-
- if (DEBUG) Log.i(TAG, "created from parcel " + getString());
}
/**
@@ -155,33 +141,13 @@
*/
@Override
public void close() throws IOException {
- synchronized (mLock) {
- if (!isClosed()) {
- if (DEBUG) {
- try {
- throw new Exception();
- } catch (Exception here) {
- Log.i(TAG, "closing " + getString(), here);
- }
- }
- nativeClose(mFd, mMemoryAddr, mIsOwner);
- mFd = -1;
- mCloseGuard.close();
- } else {
- try {
- throw new Exception();
- } catch (Exception here) {
- if (DEBUG) Log.i(TAG, getString() + " already closed", here);
- }
- }
+ if (!isClosed()) {
+ nativeClose(mFd, mMemoryAddr, mIsOwner);
+ mFd = -1;
+ mCloseGuard.close();
}
}
- private String getString() {
- return this.getClass().getSimpleName() + "@" + System.identityHashCode(this)
- + " mMemoryAddr=" + mMemoryAddr + " mFd=" + mFd;
- }
-
/**
* @return Whether this array is closed and shouldn't be used.
*/
@@ -196,9 +162,7 @@
mCloseGuard.warnIfOpen();
}
- if (!isClosed()) {
- IoUtils.closeQuietly(this);
- }
+ IoUtils.closeQuietly(this);
} finally {
super.finalize();
}
@@ -242,8 +206,7 @@
private void enforceNotClosed() {
if (isClosed()) {
- throw new IllegalStateException("cannot interact with a closed instance "
- + getString());
+ throw new IllegalStateException("cannot interact with a closed instance");
}
}
diff --git a/core/java/android/util/OWNERS b/core/java/android/util/OWNERS
new file mode 100644
index 0000000..86ed122
--- /dev/null
+++ b/core/java/android/util/OWNERS
@@ -0,0 +1,2 @@
+per-file FeatureFlagUtils.java = sbasi@google.com
+per-file FeatureFlagUtils.java = zhfan@google.com
diff --git a/core/java/android/util/StatsLog.java b/core/java/android/util/StatsLog.java
index 4805318..3350f3e 100644
--- a/core/java/android/util/StatsLog.java
+++ b/core/java/android/util/StatsLog.java
@@ -34,7 +34,7 @@
*/
public static boolean logStart(int label) {
if (label >= 0 && label < 16) {
- StatsLog.write(APP_HOOK, label, APP_HOOK__STATE__START);
+ StatsLog.write(APP_BREADCRUMB_REPORTED, label, APP_BREADCRUMB_REPORTED__STATE__START);
return true;
}
return false;
@@ -48,7 +48,7 @@
*/
public static boolean logStop(int label) {
if (label >= 0 && label < 16) {
- StatsLog.write(APP_HOOK, label, APP_HOOK__STATE__STOP);
+ StatsLog.write(APP_BREADCRUMB_REPORTED, label, APP_BREADCRUMB_REPORTED__STATE__STOP);
return true;
}
return false;
@@ -62,7 +62,8 @@
*/
public static boolean logEvent(int label) {
if (label >= 0 && label < 16) {
- StatsLog.write(APP_HOOK, label, APP_HOOK__STATE__UNSPECIFIED);
+ StatsLog.write(APP_BREADCRUMB_REPORTED, label,
+ APP_BREADCRUMB_REPORTED__STATE__UNSPECIFIED);
return true;
}
return false;
diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java
index c4a7160..d26a2f6 100644
--- a/core/java/android/view/RenderNodeAnimator.java
+++ b/core/java/android/view/RenderNodeAnimator.java
@@ -158,7 +158,7 @@
}
private void applyInterpolator() {
- if (mInterpolator == null) return;
+ if (mInterpolator == null || mNativePtr == null) return;
long ni;
if (isNativeInterpolator(mInterpolator)) {
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index bd7f8e5..fc78211 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -152,6 +152,7 @@
private static native void nativeSeverChildren(long transactionObj, long nativeObject);
private static native void nativeSetOverrideScalingMode(long transactionObj, long nativeObject,
int scalingMode);
+ private static native void nativeDestroy(long transactionObj, long nativeObject);
private static native IBinder nativeGetHandle(long nativeObject);
private static native boolean nativeGetTransformToDisplayInverse(long nativeObject);
@@ -1570,6 +1571,16 @@
return this;
}
+ /**
+ * Same as {@link #destroy()} except this is invoked in a transaction instead of
+ * immediately.
+ */
+ public Transaction destroy(SurfaceControl sc) {
+ sc.checkNotReleased();
+ nativeDestroy(mNativeObject, sc.mNativeObject);
+ return this;
+ }
+
public Transaction setDisplaySurface(IBinder displayToken, Surface surface) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 370c97e..e50d40e 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -331,6 +331,7 @@
private static final int FLAG_DUMP_FRAMESTATS = 1 << 0;
private static final int FLAG_DUMP_RESET = 1 << 1;
+ private static final int FLAG_DUMP_ALL = FLAG_DUMP_FRAMESTATS;
@IntDef(flag = true, prefix = { "FLAG_DUMP_" }, value = {
FLAG_DUMP_FRAMESTATS,
@@ -636,7 +637,10 @@
*/
void dumpGfxInfo(PrintWriter pw, FileDescriptor fd, String[] args) {
pw.flush();
- int flags = 0;
+ // If there's no arguments, eg 'dumpsys gfxinfo', then dump everything.
+ // If there's a targetted package, eg 'dumpsys gfxinfo com.android.systemui', then only
+ // dump the summary information
+ int flags = (args == null || args.length == 0) ? FLAG_DUMP_ALL : 0;
for (int i = 0; i < args.length; i++) {
switch (args[i]) {
case "framestats":
@@ -645,6 +649,9 @@
case "reset":
flags |= FLAG_DUMP_RESET;
break;
+ case "-a": // magic option passed when dumping a bugreport.
+ flags = FLAG_DUMP_ALL;
+ break;
}
}
nDumpProfileInfo(mNativeProxy, fd, flags);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index cf26b2b..790e227 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -7272,7 +7272,7 @@
// becomes true where it should issue notifyViewEntered().
afm.notifyViewEntered(this);
}
- } else if (!isFocused()) {
+ } else if (!enter && !isFocused()) {
afm.notifyViewExited(this);
}
}
@@ -7308,6 +7308,10 @@
return mAccessibilityPaneTitle;
}
+ private boolean isAccessibilityPane() {
+ return !TextUtils.isEmpty(mAccessibilityPaneTitle);
+ }
+
/**
* Sends an accessibility event of the given type. If accessibility is
* not enabled this method has no effect. The default implementation calls
@@ -8367,6 +8371,11 @@
}
}
+ // If the app developer explicitly set hints for it, it's important.
+ if (getAutofillHints() != null) {
+ return true;
+ }
+
// Otherwise, assume it's not important...
return false;
}
@@ -8798,6 +8807,9 @@
/**
* Computes whether this virtual autofill view is visible to the user.
*
+ * <p><b>Note: </b>By default it returns {@code true}, but views providing a virtual hierarchy
+ * view must override it.
+ *
* @return Whether the view is visible on the screen.
*/
public boolean isVisibleToUserForAutofill(int virtualId) {
@@ -8810,7 +8822,7 @@
}
}
}
- return false;
+ return true;
}
/**
@@ -11632,7 +11644,7 @@
return mode == IMPORTANT_FOR_ACCESSIBILITY_YES || isActionableForAccessibility()
|| hasListenersForAccessibility() || getAccessibilityNodeProvider() != null
|| getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE
- || (mAccessibilityPaneTitle != null);
+ || isAccessibilityPane();
}
/**
@@ -11729,18 +11741,26 @@
// Changes to views with a pane title count as window state changes, as the pane title
// marks them as significant parts of the UI.
- if (!TextUtils.isEmpty(getAccessibilityPaneTitle())) {
- final AccessibilityEvent event = AccessibilityEvent.obtain();
- event.setEventType(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
- event.setContentChangeTypes(changeType);
- onPopulateAccessibilityEvent(event);
- if (mParent != null) {
- try {
- mParent.requestSendAccessibilityEvent(this, event);
- } catch (AbstractMethodError e) {
- Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName()
- + " does not fully implement ViewParent", e);
+ if ((changeType != AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE)
+ && isAccessibilityPane()) {
+ // If the pane isn't visible, content changed events are sufficient unless we're
+ // reporting that the view just disappeared
+ if ((getVisibility() == VISIBLE)
+ || (changeType == AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED)) {
+ final AccessibilityEvent event = AccessibilityEvent.obtain();
+ event.setEventType(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+ event.setContentChangeTypes(changeType);
+ event.setSource(this);
+ onPopulateAccessibilityEvent(event);
+ if (mParent != null) {
+ try {
+ mParent.requestSendAccessibilityEvent(this, event);
+ } catch (AbstractMethodError e) {
+ Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName()
+ + " does not fully implement ViewParent", e);
+ }
}
+ return;
}
}
@@ -14030,6 +14050,11 @@
}
if (accessibilityEnabled) {
+ // If we're an accessibility pane and the visibility changed, we already have sent
+ // a state change, so we really don't need to report other changes.
+ if (isAccessibilityPane()) {
+ changed &= ~VISIBILITY_MASK;
+ }
if ((changed & FOCUSABLE) != 0 || (changed & VISIBILITY_MASK) != 0
|| (changed & CLICKABLE) != 0 || (changed & LONG_CLICKABLE) != 0
|| (changed & CONTEXT_CLICKABLE) != 0) {
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index b09934e..276f50a 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -21,7 +21,7 @@
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
-import android.graphics.Point;
+import android.graphics.Picture;
import android.graphics.Rect;
import android.os.Debug;
import android.os.Handler;
@@ -1782,27 +1782,18 @@
* @hide
*/
public static class HardwareCanvasProvider implements CanvasProvider {
-
- private View mView;
- private Point mSize;
- private RenderNode mNode;
- private DisplayListCanvas mCanvas;
+ private Picture mPicture;
@Override
public Canvas getCanvas(View view, int width, int height) {
- mView = view;
- mSize = new Point(width, height);
- mNode = RenderNode.create("ViewDebug", mView);
- mNode.setLeftTopRightBottom(0, 0, width, height);
- mNode.setClipToBounds(false);
- mCanvas = mNode.start(width, height);
- return mCanvas;
+ mPicture = new Picture();
+ return mPicture.beginRecording(width, height);
}
@Override
public Bitmap createBitmap() {
- mNode.end(mCanvas);
- return ThreadedRenderer.createHardwareBitmap(mNode, mSize.x, mSize.y);
+ mPicture.endRecording();
+ return Bitmap.createBitmap(mPicture);
}
}
diff --git a/core/java/android/view/WindowInfo.java b/core/java/android/view/WindowInfo.java
index bb9e391..7bae28a 100644
--- a/core/java/android/view/WindowInfo.java
+++ b/core/java/android/view/WindowInfo.java
@@ -21,6 +21,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Pools;
+import android.view.accessibility.AccessibilityNodeInfo;
import java.util.ArrayList;
import java.util.List;
@@ -46,7 +47,7 @@
public final Rect boundsInScreen = new Rect();
public List<IBinder> childTokens;
public CharSequence title;
- public int accessibilityIdOfAnchor = View.NO_ID;
+ public long accessibilityIdOfAnchor = AccessibilityNodeInfo.UNDEFINED_NODE_ID;
public boolean inPictureInPicture;
private WindowInfo() {
@@ -105,7 +106,7 @@
parcel.writeInt(focused ? 1 : 0);
boundsInScreen.writeToParcel(parcel, flags);
parcel.writeCharSequence(title);
- parcel.writeInt(accessibilityIdOfAnchor);
+ parcel.writeLong(accessibilityIdOfAnchor);
parcel.writeInt(inPictureInPicture ? 1 : 0);
if (childTokens != null && !childTokens.isEmpty()) {
@@ -142,7 +143,7 @@
focused = (parcel.readInt() == 1);
boundsInScreen.readFromParcel(parcel);
title = parcel.readCharSequence();
- accessibilityIdOfAnchor = parcel.readInt();
+ accessibilityIdOfAnchor = parcel.readLong();
inPictureInPicture = (parcel.readInt() == 1);
final boolean hasChildren = (parcel.readInt() == 1);
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 1c5e871..c0a9666 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -63,6 +63,7 @@
import android.text.TextUtils;
import android.util.Log;
import android.util.proto.ProtoOutputStream;
+import android.view.accessibility.AccessibilityNodeInfo;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -2344,7 +2345,7 @@
*
* @hide
*/
- public int accessibilityIdOfAnchor = -1;
+ public long accessibilityIdOfAnchor = AccessibilityNodeInfo.UNDEFINED_NODE_ID;
/**
* The window title isn't kept in sync with what is displayed in the title bar, so we
@@ -2538,7 +2539,7 @@
out.writeInt(hasManualSurfaceInsets ? 1 : 0);
out.writeInt(preservePreviousSurfaceInsets ? 1 : 0);
out.writeInt(needsMenuKey);
- out.writeInt(accessibilityIdOfAnchor);
+ out.writeLong(accessibilityIdOfAnchor);
TextUtils.writeToParcel(accessibilityTitle, out, parcelableFlags);
out.writeInt(mColorMode);
out.writeLong(hideTimeoutMilliseconds);
@@ -2594,7 +2595,7 @@
hasManualSurfaceInsets = in.readInt() != 0;
preservePreviousSurfaceInsets = in.readInt() != 0;
needsMenuKey = in.readInt();
- accessibilityIdOfAnchor = in.readInt();
+ accessibilityIdOfAnchor = in.readLong();
accessibilityTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
mColorMode = in.readInt();
hideTimeoutMilliseconds = in.readLong();
diff --git a/core/java/android/view/animation/AnimationUtils.java b/core/java/android/view/animation/AnimationUtils.java
index 990fbdb..29f8442 100644
--- a/core/java/android/view/animation/AnimationUtils.java
+++ b/core/java/android/view/animation/AnimationUtils.java
@@ -18,6 +18,7 @@
import android.annotation.AnimRes;
import android.annotation.InterpolatorRes;
+import android.annotation.TestApi;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.Resources.NotFoundException;
@@ -58,14 +59,43 @@
}
};
- /** @hide */
+ /**
+ * Locks AnimationUtils{@link #currentAnimationTimeMillis()} to a fixed value for the current
+ * thread. This is used by {@link android.view.Choreographer} to ensure that all accesses
+ * during a vsync update are synchronized to the timestamp of the vsync.
+ *
+ * It is also exposed to tests to allow for rapid, flake-free headless testing.
+ *
+ * Must be followed by a call to {@link #unlockAnimationClock()} to allow time to
+ * progress. Failing to do this will result in stuck animations, scrolls, and flings.
+ *
+ * Note that time is not allowed to "rewind" and must perpetually flow forward. So the
+ * lock may fail if the time is in the past from a previously returned value, however
+ * time will be frozen for the duration of the lock. The clock is a thread-local, so
+ * ensure that {@link #lockAnimationClock(long)}, {@link #unlockAnimationClock()}, and
+ * {@link #currentAnimationTimeMillis()} are all called on the same thread.
+ *
+ * This is also not reference counted in any way. Any call to {@link #unlockAnimationClock()}
+ * will unlock the clock for everyone on the same thread. It is therefore recommended
+ * for tests to use their own thread to ensure that there is no collision with any existing
+ * {@link android.view.Choreographer} instance.
+ *
+ * @hide
+ * */
+ @TestApi
public static void lockAnimationClock(long vsyncMillis) {
AnimationState state = sAnimationState.get();
state.animationClockLocked = true;
state.currentVsyncTimeMillis = vsyncMillis;
}
- /** @hide */
+ /**
+ * Frees the time lock set in place by {@link #lockAnimationClock(long)}. Must be called
+ * to allow the animation clock to self-update.
+ *
+ * @hide
+ */
+ @TestApi
public static void unlockAnimationClock() {
sAnimationState.get().animationClockLocked = false;
}
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 8b64bad..cf81b97 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -356,6 +356,13 @@
@GuardedBy("mLock")
@Nullable private ArraySet<AutofillId> mFillableIds;
+ /**
+ * Views that were already "entered" - if they're entered again when the session is not active,
+ * they're ignored
+ * */
+ @GuardedBy("mLock")
+ @Nullable private ArraySet<AutofillId> mEnteredIds;
+
/** If set, session is commited when the field is clicked. */
@GuardedBy("mLock")
@Nullable private AutofillId mSaveTriggerId;
@@ -711,17 +718,29 @@
}
@GuardedBy("mLock")
- private boolean shouldIgnoreViewEnteredLocked(@NonNull View view, int flags) {
+ private boolean shouldIgnoreViewEnteredLocked(@NonNull AutofillId id, int flags) {
if (isDisabledByServiceLocked()) {
if (sVerbose) {
- Log.v(TAG, "ignoring notifyViewEntered(flags=" + flags + ", view=" + view
- + ") on state " + getStateAsStringLocked());
+ Log.v(TAG, "ignoring notifyViewEntered(flags=" + flags + ", view=" + id
+ + ") on state " + getStateAsStringLocked() + " because disabled by svc");
}
return true;
}
- if (sVerbose && isFinishedLocked()) {
- Log.v(TAG, "not ignoring notifyViewEntered(flags=" + flags + ", view=" + view
- + ") on state " + getStateAsStringLocked());
+ if (isFinishedLocked()) {
+ // Session already finished: ignore if automatic request and view already entered
+ if ((flags & FLAG_MANUAL_REQUEST) == 0 && mEnteredIds != null
+ && mEnteredIds.contains(id)) {
+ if (sVerbose) {
+ Log.v(TAG, "ignoring notifyViewEntered(flags=" + flags + ", view=" + id
+ + ") on state " + getStateAsStringLocked()
+ + " because view was already entered: " + mEnteredIds);
+ }
+ return true;
+ }
+ }
+ if (sVerbose) {
+ Log.v(TAG, "not ignoring notifyViewEntered(flags=" + flags + ", view=" + id
+ + ", state " + getStateAsStringLocked() + ", enteredIds=" + mEnteredIds);
}
return false;
}
@@ -753,7 +772,8 @@
/** Returns AutofillCallback if need fire EVENT_INPUT_UNAVAILABLE */
@GuardedBy("mLock")
private AutofillCallback notifyViewEnteredLocked(@NonNull View view, int flags) {
- if (shouldIgnoreViewEnteredLocked(view, flags)) return null;
+ final AutofillId id = getAutofillId(view);
+ if (shouldIgnoreViewEnteredLocked(id, flags)) return null;
AutofillCallback callback = null;
@@ -766,7 +786,6 @@
} else {
// don't notify entered when Activity is already in background
if (!isClientDisablingEnterExitEvent()) {
- final AutofillId id = getAutofillId(view);
final AutofillValue value = view.getAutofillValue();
if (!isActiveLocked()) {
@@ -776,6 +795,7 @@
// Update focus on existing session.
updateSessionLocked(id, null, value, ACTION_VIEW_ENTERED, flags);
}
+ addEnteredIdLocked(id);
}
}
return callback;
@@ -900,8 +920,9 @@
@GuardedBy("mLock")
private AutofillCallback notifyViewEnteredLocked(View view, int virtualId, Rect bounds,
int flags) {
+ final AutofillId id = getAutofillId(view, virtualId);
AutofillCallback callback = null;
- if (shouldIgnoreViewEnteredLocked(view, flags)) return callback;
+ if (shouldIgnoreViewEnteredLocked(id, flags)) return callback;
ensureServiceClientAddedIfNeededLocked();
@@ -912,8 +933,6 @@
} else {
// don't notify entered when Activity is already in background
if (!isClientDisablingEnterExitEvent()) {
- final AutofillId id = getAutofillId(view, virtualId);
-
if (!isActiveLocked()) {
// Starts new session.
startSessionLocked(id, bounds, null, flags);
@@ -921,11 +940,20 @@
// Update focus on existing session.
updateSessionLocked(id, bounds, null, ACTION_VIEW_ENTERED, flags);
}
+ addEnteredIdLocked(id);
}
}
return callback;
}
+ @GuardedBy("mLock")
+ private void addEnteredIdLocked(@NonNull AutofillId id) {
+ if (mEnteredIds == null) {
+ mEnteredIds = new ArraySet<>(1);
+ }
+ mEnteredIds.add(id);
+ }
+
/**
* Called when a virtual view that supports autofill is exited.
*
@@ -992,9 +1020,9 @@
}
if (!mEnabled || !isActiveLocked()) {
- if (sVerbose && mEnabled) {
- Log.v(TAG, "notifyValueChanged(" + view + "): ignoring on state "
- + getStateAsStringLocked());
+ if (sVerbose) {
+ Log.v(TAG, "notifyValueChanged(" + view.getAutofillId()
+ + "): ignoring on state " + getStateAsStringLocked());
}
return;
}
@@ -1024,6 +1052,10 @@
}
synchronized (mLock) {
if (!mEnabled || !isActiveLocked()) {
+ if (sVerbose) {
+ Log.v(TAG, "notifyValueChanged(" + view.getAutofillId() + ":" + virtualId
+ + "): ignoring on state " + getStateAsStringLocked());
+ }
return;
}
@@ -1032,7 +1064,6 @@
}
}
-
/**
* Called when a {@link View} is clicked. Currently only used by views that should trigger save.
*
@@ -1392,7 +1423,8 @@
if (sVerbose) {
Log.v(TAG, "startSessionLocked(): id=" + id + ", bounds=" + bounds + ", value=" + value
+ ", flags=" + flags + ", state=" + getStateAsStringLocked()
- + ", compatMode=" + isCompatibilityModeEnabledLocked());
+ + ", compatMode=" + isCompatibilityModeEnabledLocked()
+ + ", enteredIds=" + mEnteredIds);
}
if (mState != STATE_UNKNOWN && !isFinishedLocked() && (flags & FLAG_MANUAL_REQUEST) == 0) {
if (sVerbose) {
@@ -1407,7 +1439,8 @@
mSessionId = mService.startSession(client.autofillClientGetActivityToken(),
mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(),
- mCallback != null, flags, client.autofillClientGetComponentName());
+ mCallback != null, flags, client.autofillClientGetComponentName(),
+ isCompatibilityModeEnabledLocked());
if (mSessionId != NO_SESSION) {
mState = STATE_ACTIVE;
}
@@ -1429,7 +1462,7 @@
throw e.rethrowFromSystemServer();
}
- resetSessionLocked();
+ resetSessionLocked(/* resetEnteredIds= */ true);
}
@GuardedBy("mLock")
@@ -1444,22 +1477,25 @@
throw e.rethrowFromSystemServer();
}
- resetSessionLocked();
+ resetSessionLocked(/* resetEnteredIds= */ true);
}
@GuardedBy("mLock")
- private void resetSessionLocked() {
+ private void resetSessionLocked(boolean resetEnteredIds) {
mSessionId = NO_SESSION;
mState = STATE_UNKNOWN;
mTrackedViews = null;
mFillableIds = null;
mSaveTriggerId = null;
+ if (resetEnteredIds) {
+ mEnteredIds = null;
+ }
}
@GuardedBy("mLock")
private void updateSessionLocked(AutofillId id, Rect bounds, AutofillValue value, int action,
int flags) {
- if (sVerbose && action != ACTION_VIEW_EXITED) {
+ if (sVerbose) {
Log.v(TAG, "updateSessionLocked(): id=" + id + ", bounds=" + bounds
+ ", value=" + value + ", action=" + action + ", flags=" + flags);
}
@@ -1474,7 +1510,7 @@
client.autofillClientGetActivityToken(),
mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(),
mCallback != null, flags, client.autofillClientGetComponentName(),
- mSessionId, action);
+ mSessionId, action, isCompatibilityModeEnabledLocked());
if (newId != mSessionId) {
if (sDebug) Log.d(TAG, "Session restarted: " + mSessionId + "=>" + newId);
mSessionId = newId;
@@ -1629,7 +1665,7 @@
mEnabled = (flags & SET_STATE_FLAG_ENABLED) != 0;
if (!mEnabled || (flags & SET_STATE_FLAG_RESET_SESSION) != 0) {
// Reset the session state
- resetSessionLocked();
+ resetSessionLocked(/* resetEnteredIds= */ true);
}
if ((flags & SET_STATE_FLAG_RESET_CLIENT) != 0) {
// Reset connection to system
@@ -1825,7 +1861,7 @@
private void setSessionFinished(int newState) {
synchronized (mLock) {
if (sVerbose) Log.v(TAG, "setSessionFinished(): from " + mState + " to " + newState);
- resetSessionLocked();
+ resetSessionLocked(/* resetEnteredIds= */ false);
mState = newState;
}
}
@@ -1953,6 +1989,7 @@
pw.print(pfx2); pw.print("invisible:"); pw.println(mTrackedViews.mInvisibleTrackedIds);
}
pw.print(pfx); pw.print("fillable ids: "); pw.println(mFillableIds);
+ pw.print(pfx); pw.print("entered ids: "); pw.println(mEnteredIds);
pw.print(pfx); pw.print("save trigger id: "); pw.println(mSaveTriggerId);
pw.print(pfx); pw.print("save on finish(): "); pw.println(mSaveOnFinish);
pw.print(pfx); pw.print("compat mode enabled: "); pw.println(
diff --git a/core/java/android/view/autofill/AutofillPopupWindow.java b/core/java/android/view/autofill/AutofillPopupWindow.java
index e80fdd9..1da998d 100644
--- a/core/java/android/view/autofill/AutofillPopupWindow.java
+++ b/core/java/android/view/autofill/AutofillPopupWindow.java
@@ -46,6 +46,7 @@
private final WindowPresenter mWindowPresenter;
private WindowManager.LayoutParams mWindowLayoutParams;
+ private boolean mFullScreen;
private final View.OnAttachStateChangeListener mOnAttachStateChangeListener =
new View.OnAttachStateChangeListener() {
@@ -104,12 +105,17 @@
*/
public void update(View anchor, int offsetX, int offsetY, int width, int height,
Rect virtualBounds) {
+ mFullScreen = width == LayoutParams.MATCH_PARENT && height == LayoutParams.MATCH_PARENT;
// If we are showing the popup for a virtual view we use a fake view which
// delegates to the anchor but present itself with the same bounds as the
// virtual view. This ensures that the location logic in popup works
// symmetrically when the dropdown is below and above the anchor.
final View actualAnchor;
- if (virtualBounds != null) {
+ if (mFullScreen) {
+ offsetX = 0;
+ offsetY = 0;
+ actualAnchor = anchor;
+ } else if (virtualBounds != null) {
final int[] mLocationOnScreen = new int[] {virtualBounds.left, virtualBounds.top};
actualAnchor = new View(anchor.getContext()) {
@Override
@@ -209,6 +215,17 @@
}
@Override
+ protected boolean findDropDownPosition(View anchor, LayoutParams outParams,
+ int xOffset, int yOffset, int width, int height, int gravity, boolean allowScroll) {
+ if (mFullScreen) {
+ // Do not patch LayoutParams if force full screen
+ return false;
+ }
+ return super.findDropDownPosition(anchor, outParams, xOffset, yOffset,
+ width, height, gravity, allowScroll);
+ }
+
+ @Override
public void showAsDropDown(View anchor, int xoff, int yoff, int gravity) {
if (sVerbose) {
Log.v(TAG, "showAsDropDown(): anchor=" + anchor + ", xoff=" + xoff + ", yoff=" + yoff
diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl
index 0018547..56f79ab 100644
--- a/core/java/android/view/autofill/IAutoFillManager.aidl
+++ b/core/java/android/view/autofill/IAutoFillManager.aidl
@@ -38,7 +38,7 @@
void removeClient(in IAutoFillManagerClient client, int userId);
int startSession(IBinder activityToken, in IBinder appCallback, in AutofillId autoFillId,
in Rect bounds, in AutofillValue value, int userId, boolean hasCallback, int flags,
- in ComponentName componentName);
+ in ComponentName componentName, boolean compatMode);
FillEventHistory getFillEventHistory();
boolean restoreSession(int sessionId, in IBinder activityToken, in IBinder appCallback);
void updateSession(int sessionId, in AutofillId id, in Rect bounds,
@@ -46,7 +46,7 @@
int updateOrRestartSession(IBinder activityToken, in IBinder appCallback,
in AutofillId autoFillId, in Rect bounds, in AutofillValue value, int userId,
boolean hasCallback, int flags, in ComponentName componentName, int sessionId,
- int action);
+ int action, boolean compatMode);
void finishSession(int sessionId, int userId);
void cancelSession(int sessionId, int userId);
void setAuthenticationResult(in Bundle data, int sessionId, int authenticationId, int userId);
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index e91db13..7217def 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1583,7 +1583,7 @@
*
* @hide
*/
- protected final boolean findDropDownPosition(View anchor, WindowManager.LayoutParams outParams,
+ protected boolean findDropDownPosition(View anchor, WindowManager.LayoutParams outParams,
int xOffset, int yOffset, int width, int height, int gravity, boolean allowScroll) {
final int anchorHeight = anchor.getHeight();
final int anchorWidth = anchor.getWidth();
diff --git a/core/java/com/android/internal/app/ResolverListController.java b/core/java/com/android/internal/app/ResolverListController.java
index 6bd6930..61aeca6 100644
--- a/core/java/com/android/internal/app/ResolverListController.java
+++ b/core/java/com/android/internal/app/ResolverListController.java
@@ -56,9 +56,6 @@
private static final String TAG = "ResolverListController";
private static final boolean DEBUG = false;
- Object mLock = new Object();
-
- @GuardedBy("mLock")
private ResolverComparator mResolverComparator;
private boolean isComputed = false;
@@ -73,10 +70,8 @@
mLaunchedFromUid = launchedFromUid;
mTargetIntent = targetIntent;
mReferrerPackage = referrerPackage;
- synchronized (mLock) {
- mResolverComparator =
- new ResolverComparator(mContext, mTargetIntent, mReferrerPackage, null);
- }
+ mResolverComparator =
+ new ResolverComparator(mContext, mTargetIntent, mReferrerPackage, null);
}
@VisibleForTesting
@@ -244,29 +239,27 @@
@VisibleForTesting
@WorkerThread
public void sort(List<ResolverActivity.ResolvedComponentInfo> inputList) {
- synchronized (mLock) {
- if (mResolverComparator == null) {
- Log.d(TAG, "Comparator has already been destroyed; skipped.");
- return;
+ if (mResolverComparator == null) {
+ Log.d(TAG, "Comparator has already been destroyed; skipped.");
+ return;
+ }
+ try {
+ long beforeRank = System.currentTimeMillis();
+ if (!isComputed) {
+ final CountDownLatch finishComputeSignal = new CountDownLatch(1);
+ ComputeCallback callback = new ComputeCallback(finishComputeSignal);
+ mResolverComparator.setCallBack(callback);
+ mResolverComparator.compute(inputList);
+ finishComputeSignal.await();
+ isComputed = true;
}
- final CountDownLatch finishComputeSignal = new CountDownLatch(1);
- ComputeCallback callback = new ComputeCallback(finishComputeSignal);
- mResolverComparator.setCallBack(callback);
- try {
- long beforeRank = System.currentTimeMillis();
- if (!isComputed) {
- mResolverComparator.compute(inputList);
- finishComputeSignal.await();
- isComputed = true;
- }
- Collections.sort(inputList, mResolverComparator);
- long afterRank = System.currentTimeMillis();
- if (DEBUG) {
- Log.d(TAG, "Time Cost: " + Long.toString(afterRank - beforeRank));
- }
- } catch (InterruptedException e) {
- Log.e(TAG, "Compute & Sort was interrupted: " + e);
+ Collections.sort(inputList, mResolverComparator);
+ long afterRank = System.currentTimeMillis();
+ if (DEBUG) {
+ Log.d(TAG, "Time Cost: " + Long.toString(afterRank - beforeRank));
}
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Compute & Sort was interrupted: " + e);
}
}
@@ -287,36 +280,18 @@
@VisibleForTesting
public float getScore(ResolverActivity.DisplayResolveInfo target) {
- synchronized (mLock) {
- if (mResolverComparator == null) {
- return 0.0f;
- }
- return mResolverComparator.getScore(target.getResolvedComponentName());
- }
+ return mResolverComparator.getScore(target.getResolvedComponentName());
}
public void updateModel(ComponentName componentName) {
- synchronized (mLock) {
- if (mResolverComparator != null) {
- mResolverComparator.updateModel(componentName);
- }
- }
+ mResolverComparator.updateModel(componentName);
}
public void updateChooserCounts(String packageName, int userId, String action) {
- synchronized (mLock) {
- if (mResolverComparator != null) {
- mResolverComparator.updateChooserCounts(packageName, userId, action);
- }
- }
+ mResolverComparator.updateChooserCounts(packageName, userId, action);
}
public void destroy() {
- synchronized (mLock) {
- if (mResolverComparator != null) {
- mResolverComparator.destroy();
- }
- mResolverComparator = null;
- }
+ mResolverComparator.destroy();
}
}
diff --git a/core/java/com/android/internal/colorextraction/drawable/GradientDrawable.java b/core/java/com/android/internal/colorextraction/drawable/GradientDrawable.java
index 500c028..bf151c3 100644
--- a/core/java/com/android/internal/colorextraction/drawable/GradientDrawable.java
+++ b/core/java/com/android/internal/colorextraction/drawable/GradientDrawable.java
@@ -57,6 +57,8 @@
private int mMainColor;
private int mSecondaryColor;
private ValueAnimator mColorAnimation;
+ private int mMainColorTo;
+ private int mSecondaryColorTo;
public GradientDrawable(@NonNull Context context) {
mDensity = context.getResources().getDisplayMetrics().density;
@@ -76,7 +78,7 @@
}
public void setColors(int mainColor, int secondaryColor, boolean animated) {
- if (mainColor == mMainColor && secondaryColor == mSecondaryColor) {
+ if (mainColor == mMainColorTo && secondaryColor == mSecondaryColorTo) {
return;
}
@@ -84,6 +86,9 @@
mColorAnimation.cancel();
}
+ mMainColorTo = mainColor;
+ mSecondaryColorTo = mainColor;
+
if (animated) {
final int mainFrom = mMainColor;
final int secFrom = mSecondaryColor;
diff --git a/core/java/com/android/internal/notification/SystemNotificationChannels.java b/core/java/com/android/internal/notification/SystemNotificationChannels.java
index 4a181b2..44adbb2 100644
--- a/core/java/com/android/internal/notification/SystemNotificationChannels.java
+++ b/core/java/com/android/internal/notification/SystemNotificationChannels.java
@@ -49,6 +49,7 @@
public static String USB = "USB";
public static String FOREGROUND_SERVICE = "FOREGROUND_SERVICE";
public static String HEAVY_WEIGHT_APP = "HEAVY_WEIGHT_APP";
+ public static String SYSTEM_CHANGES = "SYSTEM_CHANGES";
public static void createAll(Context context) {
final NotificationManager nm = context.getSystemService(NotificationManager.class);
@@ -152,6 +153,11 @@
.build());
channelsList.add(heavyWeightChannel);
+ NotificationChannel systemChanges = new NotificationChannel(SYSTEM_CHANGES,
+ context.getString(R.string.notification_channel_system_changes),
+ NotificationManager.IMPORTANCE_LOW);
+ channelsList.add(systemChanges);
+
nm.createNotificationChannels(channelsList);
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index eb58b09..4c5991e 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -187,7 +187,7 @@
public final AtomicFile mCheckinFile;
public final AtomicFile mDailyFile;
- static final int MSG_UPDATE_WAKELOCKS = 1;
+ static final int MSG_REPORT_CPU_UPDATE_NEEDED = 1;
static final int MSG_REPORT_POWER_CHANGE = 2;
static final int MSG_REPORT_CHARGING = 3;
static final long DELAY_UPDATE_WAKELOCKS = 5*1000;
@@ -273,10 +273,7 @@
public void handleMessage(Message msg) {
BatteryCallback cb = mCallback;
switch (msg.what) {
- case MSG_UPDATE_WAKELOCKS:
- synchronized (BatteryStatsImpl.this) {
- updateCpuTimeLocked();
- }
+ case MSG_REPORT_CPU_UPDATE_NEEDED:
if (cb != null) {
cb.batteryNeedsCpuUpdate();
}
@@ -302,6 +299,10 @@
}
}
+ public void postBatteryNeedsCpuUpdateMsg() {
+ mHandler.sendEmptyMessage(MSG_REPORT_CPU_UPDATE_NEEDED);
+ }
+
/**
* Update per-freq cpu times for all the uids in {@link #mPendingUids}.
*/
@@ -487,6 +488,10 @@
Future<?> scheduleReadProcStateCpuTimes(boolean onBattery, boolean onBatteryScreenOff);
Future<?> scheduleCopyFromAllUidsCpuTimes(boolean onBattery, boolean onBatteryScreenOff);
Future<?> scheduleCpuSyncDueToSettingChange();
+ Future<?> scheduleCpuSyncDueToScreenStateChange(boolean onBattery,
+ boolean onBatteryScreenOff);
+ Future<?> scheduleCpuSyncDueToWakelockChange(long delayMillis);
+ void cancelCpuSyncDueToWakelockChange();
}
public Handler mHandler;
@@ -1453,12 +1458,10 @@
long mCount;
long mLoadedCount;
long mUnpluggedCount;
- long mPluggedCount;
LongSamplingCounter(TimeBase timeBase, Parcel in) {
mTimeBase = timeBase;
- mPluggedCount = in.readLong();
- mCount = mPluggedCount;
+ mCount = in.readLong();
mLoadedCount = in.readLong();
mUnpluggedCount = in.readLong();
timeBase.add(this);
@@ -1477,16 +1480,15 @@
@Override
public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
- mUnpluggedCount = mPluggedCount;
+ mUnpluggedCount = mCount;
}
@Override
public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
- mPluggedCount = mCount;
}
public long getCountLocked(int which) {
- long val = mTimeBase.isRunning() ? mCount : mPluggedCount;
+ long val = mCount;
if (which == STATS_SINCE_UNPLUGGED) {
val -= mUnpluggedCount;
} else if (which != STATS_SINCE_CHARGED) {
@@ -1499,12 +1501,15 @@
public void logState(Printer pw, String prefix) {
pw.println(prefix + "mCount=" + mCount
+ " mLoadedCount=" + mLoadedCount
- + " mUnpluggedCount=" + mUnpluggedCount
- + " mPluggedCount=" + mPluggedCount);
+ + " mUnpluggedCount=" + mUnpluggedCount);
}
void addCountLocked(long count) {
- if (mTimeBase.isRunning()) {
+ addCountLocked(count, mTimeBase.isRunning());
+ }
+
+ void addCountLocked(long count, boolean isRunning) {
+ if (isRunning) {
mCount += count;
}
}
@@ -1514,7 +1519,7 @@
*/
void reset(boolean detachIfReset) {
mCount = 0;
- mLoadedCount = mPluggedCount = mUnpluggedCount = 0;
+ mLoadedCount = mUnpluggedCount = 0;
if (detachIfReset) {
detach();
}
@@ -1531,7 +1536,7 @@
void readSummaryFromParcelLocked(Parcel in) {
mLoadedCount = in.readLong();
mCount = mLoadedCount;
- mUnpluggedCount = mPluggedCount = mLoadedCount;
+ mUnpluggedCount = mLoadedCount;
}
}
@@ -3852,9 +3857,6 @@
+ Display.stateToString(screenState)
+ " and battery is " + (unplugged ? "on" : "off"));
}
- updateCpuTimeLocked();
- mExternalSync.scheduleCopyFromAllUidsCpuTimes(mOnBatteryTimeBase.isRunning(),
- mOnBatteryScreenOffTimeBase.isRunning());
mOnBatteryTimeBase.setRunning(unplugged, uptime, realtime);
if (updateOnBatteryTimeBase) {
@@ -4143,15 +4145,11 @@
}
private void requestWakelockCpuUpdate() {
- if (!mHandler.hasMessages(MSG_UPDATE_WAKELOCKS)) {
- Message m = mHandler.obtainMessage(MSG_UPDATE_WAKELOCKS);
- mHandler.sendMessageDelayed(m, DELAY_UPDATE_WAKELOCKS);
- }
+ mExternalSync.scheduleCpuSyncDueToWakelockChange(DELAY_UPDATE_WAKELOCKS);
}
private void requestImmediateCpuUpdate() {
- mHandler.removeMessages(MSG_UPDATE_WAKELOCKS);
- mHandler.sendEmptyMessage(MSG_UPDATE_WAKELOCKS);
+ mExternalSync.scheduleCpuSyncDueToWakelockChange(0 /* delayMillis */);
}
public void setRecordAllHistoryLocked(boolean enabled) {
@@ -4554,7 +4552,7 @@
}
public boolean startAddingCpuLocked() {
- mHandler.removeMessages(MSG_UPDATE_WAKELOCKS);
+ mExternalSync.cancelCpuSyncDueToWakelockChange();
return mOnBatteryInternal;
}
@@ -4807,6 +4805,8 @@
+ Display.stateToString(state));
addHistoryRecordLocked(elapsedRealtime, uptime);
}
+ mExternalSync.scheduleCpuSyncDueToScreenStateChange(
+ mOnBatteryTimeBase.isRunning(), mOnBatteryScreenOffTimeBase.isRunning());
if (isScreenOn(state)) {
updateTimeBasesLocked(mOnBatteryTimeBase.isRunning(), state,
mClocks.uptimeMillis() * 1000, elapsedRealtime * 1000);
@@ -5286,6 +5286,18 @@
case TelephonyManager.NETWORK_TYPE_HSPAP:
bin = DATA_CONNECTION_HSPAP;
break;
+ case TelephonyManager.NETWORK_TYPE_GSM:
+ bin = DATA_CONNECTION_GSM;
+ break;
+ case TelephonyManager.NETWORK_TYPE_TD_SCDMA:
+ bin = DATA_CONNECTION_TD_SCDMA;
+ break;
+ case TelephonyManager.NETWORK_TYPE_IWLAN:
+ bin = DATA_CONNECTION_IWLAN;
+ break;
+ case TelephonyManager.NETWORK_TYPE_LTE_CA:
+ bin = DATA_CONNECTION_LTE_CA;
+ break;
default:
bin = DATA_CONNECTION_OTHER;
break;
@@ -9196,8 +9208,14 @@
}
public void addCpuTimeLocked(int utime, int stime) {
- mUserTime += utime;
- mSystemTime += stime;
+ addCpuTimeLocked(utime, stime, mBsi.mOnBatteryTimeBase.isRunning());
+ }
+
+ public void addCpuTimeLocked(int utime, int stime, boolean isRunning) {
+ if (isRunning) {
+ mUserTime += utime;
+ mSystemTime += stime;
+ }
}
public void addForegroundTimeLocked(long ttime) {
@@ -11761,13 +11779,24 @@
}
}
+ public boolean isOnBatteryLocked() {
+ return mOnBatteryTimeBase.isRunning();
+ }
+
+ public boolean isOnBatteryScreenOffLocked() {
+ return mOnBatteryScreenOffTimeBase.isRunning();
+ }
+
/**
* Read and distribute CPU usage across apps. If their are partial wakelocks being held
* and we are on battery with screen off, we give more of the cpu time to those apps holding
* wakelocks. If the screen is on, we just assign the actual cpu time an app used.
+ * It's possible this will be invoked after the internal battery/screen states are updated, so
+ * passing the appropriate battery/screen states to try attribute the cpu times to correct
+ * buckets.
*/
@GuardedBy("this")
- public void updateCpuTimeLocked() {
+ public void updateCpuTimeLocked(boolean onBattery, boolean onBatteryScreenOff) {
if (mPowerProfile == null) {
return;
}
@@ -11784,7 +11813,7 @@
// usually holding the wakelock on behalf of an app.
// And Only distribute cpu power to wakelocks if the screen is off and we're on battery.
ArrayList<StopwatchTimer> partialTimersToConsider = null;
- if (mOnBatteryScreenOffTimeBase.isRunning()) {
+ if (onBatteryScreenOff) {
partialTimersToConsider = new ArrayList<>();
for (int i = mPartialTimers.size() - 1; i >= 0; --i) {
final StopwatchTimer timer = mPartialTimers.get(i);
@@ -11802,7 +11831,7 @@
// When the battery is not on, we don't attribute the cpu times to any timers but we still
// need to take the snapshots.
- if (!mOnBatteryInternal) {
+ if (!onBattery) {
mKernelUidCpuTimeReader.readDelta(null);
mKernelUidCpuFreqTimeReader.readDelta(null);
if (mConstants.TRACK_CPU_ACTIVE_CLUSTER_TIME) {
@@ -11818,16 +11847,16 @@
mUserInfoProvider.refreshUserIds();
final SparseLongArray updatedUids = mKernelUidCpuFreqTimeReader.perClusterTimesAvailable()
? null : new SparseLongArray();
- readKernelUidCpuTimesLocked(partialTimersToConsider, updatedUids);
+ readKernelUidCpuTimesLocked(partialTimersToConsider, updatedUids, onBattery);
// updatedUids=null means /proc/uid_time_in_state provides snapshots of per-cluster cpu
// freqs, so no need to approximate these values.
if (updatedUids != null) {
- updateClusterSpeedTimes(updatedUids);
+ updateClusterSpeedTimes(updatedUids, onBattery);
}
- readKernelUidCpuFreqTimesLocked(partialTimersToConsider);
+ readKernelUidCpuFreqTimesLocked(partialTimersToConsider, onBattery, onBatteryScreenOff);
if (mConstants.TRACK_CPU_ACTIVE_CLUSTER_TIME) {
- readKernelUidCpuActiveTimesLocked();
- readKernelUidCpuClusterTimesLocked();
+ readKernelUidCpuActiveTimesLocked(onBattery);
+ readKernelUidCpuClusterTimesLocked(onBattery);
}
}
@@ -11867,7 +11896,7 @@
* @param updatedUids The uids for which times spent at different frequencies are calculated.
*/
@VisibleForTesting
- public void updateClusterSpeedTimes(@NonNull SparseLongArray updatedUids) {
+ public void updateClusterSpeedTimes(@NonNull SparseLongArray updatedUids, boolean onBattery) {
long totalCpuClustersTimeMs = 0;
// Read the time spent for each cluster at various cpu frequencies.
final long[][] clusterSpeedTimesMs = new long[mKernelCpuSpeedReaders.length][];
@@ -11909,7 +11938,7 @@
}
cpuSpeeds[speed].addCountLocked(appCpuTimeUs
* clusterSpeedTimesMs[cluster][speed]
- / totalCpuClustersTimeMs);
+ / totalCpuClustersTimeMs, onBattery);
}
}
}
@@ -11926,7 +11955,7 @@
*/
@VisibleForTesting
public void readKernelUidCpuTimesLocked(@Nullable ArrayList<StopwatchTimer> partialTimers,
- @Nullable SparseLongArray updatedUids) {
+ @Nullable SparseLongArray updatedUids, boolean onBattery) {
mTempTotalCpuUserTimeUs = mTempTotalCpuSystemTimeUs = 0;
final int numWakelocks = partialTimers == null ? 0 : partialTimers.size();
final long startTimeMs = mClocks.uptimeMillis();
@@ -11977,8 +12006,8 @@
Slog.d(TAG, sb.toString());
}
- u.mUserCpuTime.addCountLocked(userTimeUs);
- u.mSystemCpuTime.addCountLocked(systemTimeUs);
+ u.mUserCpuTime.addCountLocked(userTimeUs, onBattery);
+ u.mSystemCpuTime.addCountLocked(systemTimeUs, onBattery);
if (updatedUids != null) {
updatedUids.put(u.getUid(), userTimeUs + systemTimeUs);
}
@@ -12010,15 +12039,15 @@
Slog.d(TAG, sb.toString());
}
- timer.mUid.mUserCpuTime.addCountLocked(userTimeUs);
- timer.mUid.mSystemCpuTime.addCountLocked(systemTimeUs);
+ timer.mUid.mUserCpuTime.addCountLocked(userTimeUs, onBattery);
+ timer.mUid.mSystemCpuTime.addCountLocked(systemTimeUs, onBattery);
if (updatedUids != null) {
final int uid = timer.mUid.getUid();
updatedUids.put(uid, updatedUids.get(uid, 0) + userTimeUs + systemTimeUs);
}
final Uid.Proc proc = timer.mUid.getProcessStatsLocked("*wakelock*");
- proc.addCpuTimeLocked(userTimeUs / 1000, systemTimeUs / 1000);
+ proc.addCpuTimeLocked(userTimeUs / 1000, systemTimeUs / 1000, onBattery);
mTempTotalCpuUserTimeUs -= userTimeUs;
mTempTotalCpuSystemTimeUs -= systemTimeUs;
@@ -12033,7 +12062,8 @@
* @param partialTimers The wakelock holders among which the cpu freq times will be distributed.
*/
@VisibleForTesting
- public void readKernelUidCpuFreqTimesLocked(@Nullable ArrayList<StopwatchTimer> partialTimers) {
+ public void readKernelUidCpuFreqTimesLocked(@Nullable ArrayList<StopwatchTimer> partialTimers,
+ boolean onBattery, boolean onBatteryScreenOff) {
final boolean perClusterTimesAvailable =
mKernelUidCpuFreqTimeReader.perClusterTimesAvailable();
final int numWakelocks = partialTimers == null ? 0 : partialTimers.size();
@@ -12056,13 +12086,13 @@
if (u.mCpuFreqTimeMs == null || u.mCpuFreqTimeMs.getSize() != cpuFreqTimeMs.length) {
u.mCpuFreqTimeMs = new LongSamplingCounterArray(mOnBatteryTimeBase);
}
- u.mCpuFreqTimeMs.addCountLocked(cpuFreqTimeMs);
+ u.mCpuFreqTimeMs.addCountLocked(cpuFreqTimeMs, onBattery);
if (u.mScreenOffCpuFreqTimeMs == null ||
u.mScreenOffCpuFreqTimeMs.getSize() != cpuFreqTimeMs.length) {
u.mScreenOffCpuFreqTimeMs = new LongSamplingCounterArray(
mOnBatteryScreenOffTimeBase);
}
- u.mScreenOffCpuFreqTimeMs.addCountLocked(cpuFreqTimeMs);
+ u.mScreenOffCpuFreqTimeMs.addCountLocked(cpuFreqTimeMs, onBatteryScreenOff);
if (perClusterTimesAvailable) {
if (u.mCpuClusterSpeedTimesUs == null ||
@@ -12098,7 +12128,7 @@
} else {
appAllocationUs = cpuFreqTimeMs[freqIndex] * 1000;
}
- cpuTimesUs[speed].addCountLocked(appAllocationUs);
+ cpuTimesUs[speed].addCountLocked(appAllocationUs, onBattery);
freqIndex++;
}
}
@@ -12132,7 +12162,7 @@
}
final long allocationUs =
mWakeLockAllocationsUs[cluster][speed] / (numWakelocks - i);
- cpuTimeUs[speed].addCountLocked(allocationUs);
+ cpuTimeUs[speed].addCountLocked(allocationUs, onBattery);
mWakeLockAllocationsUs[cluster][speed] -= allocationUs;
}
}
@@ -12145,7 +12175,7 @@
* counters.
*/
@VisibleForTesting
- public void readKernelUidCpuActiveTimesLocked() {
+ public void readKernelUidCpuActiveTimesLocked(boolean onBattery) {
final long startTimeMs = mClocks.uptimeMillis();
mKernelUidCpuActiveTimeReader.readDelta((uid, cpuActiveTimesUs) -> {
uid = mapUid(uid);
@@ -12160,7 +12190,7 @@
return;
}
final Uid u = getUidStatsLocked(uid);
- u.mCpuActiveTimeMs.addCountLocked(cpuActiveTimesUs);
+ u.mCpuActiveTimeMs.addCountLocked(cpuActiveTimesUs, onBattery);
});
final long elapsedTimeMs = mClocks.uptimeMillis() - startTimeMs;
@@ -12174,7 +12204,7 @@
* counters.
*/
@VisibleForTesting
- public void readKernelUidCpuClusterTimesLocked() {
+ public void readKernelUidCpuClusterTimesLocked(boolean onBattery) {
final long startTimeMs = mClocks.uptimeMillis();
mKernelUidCpuClusterTimeReader.readDelta((uid, cpuClusterTimesUs) -> {
uid = mapUid(uid);
@@ -12189,7 +12219,7 @@
return;
}
final Uid u = getUidStatsLocked(uid);
- u.mCpuClusterTimesMs.addCountLocked(cpuClusterTimesUs);
+ u.mCpuClusterTimesMs.addCountLocked(cpuClusterTimesUs, onBattery);
});
final long elapsedTimeMs = mClocks.uptimeMillis() - startTimeMs;
@@ -12399,9 +12429,7 @@
reportChangesToStatsLog(mHaveBatteryLevel ? mHistoryCur : null,
status, plugType, level, temp);
- final boolean onBattery =
- plugType == BATTERY_PLUGGED_NONE &&
- status != BatteryManager.BATTERY_STATUS_UNKNOWN;
+ final boolean onBattery = isOnBattery(plugType, status);
final long uptime = mClocks.uptimeMillis();
final long elapsedRealtime = mClocks.elapsedRealtime();
if (!mHaveBatteryLevel) {
@@ -12591,6 +12619,10 @@
mMaxLearnedBatteryCapacity = Math.max(mMaxLearnedBatteryCapacity, chargeFullUAh);
}
+ public static boolean isOnBattery(int plugType, int status) {
+ return plugType == BATTERY_PLUGGED_NONE && status != BatteryManager.BATTERY_STATUS_UNKNOWN;
+ }
+
// Inform StatsLog of setBatteryState changes.
// If this is the first reporting, pass in recentPast == null.
private void reportChangesToStatsLog(HistoryItem recentPast,
diff --git a/core/java/com/android/internal/os/KernelSingleUidTimeReader.java b/core/java/com/android/internal/os/KernelSingleUidTimeReader.java
index ebeb24c4..4283917 100644
--- a/core/java/com/android/internal/os/KernelSingleUidTimeReader.java
+++ b/core/java/com/android/internal/os/KernelSingleUidTimeReader.java
@@ -16,6 +16,7 @@
package com.android.internal.os;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
+import static com.android.internal.os.KernelUidCpuFreqTimeReader.UID_TIMES_PROC_FILE;
import android.annotation.NonNull;
import android.util.Slog;
@@ -54,6 +55,12 @@
private boolean mSingleUidCpuTimesAvailable = true;
@GuardedBy("this")
private boolean mHasStaleData;
+ // We use the freq count obtained from /proc/uid_time_in_state to decide how many longs
+ // to read from each /proc/uid/<uid>/time_in_state. On the first read, verify if this is
+ // correct and if not, set {@link #mSingleUidCpuTimesAvailable} to false. This flag will
+ // indicate whether we checked for validity or not.
+ @GuardedBy("this")
+ private boolean mCpuFreqsCountVerified;
private final Injector mInjector;
@@ -82,15 +89,15 @@
final String procFile = new StringBuilder(PROC_FILE_DIR)
.append(uid)
.append(PROC_FILE_NAME).toString();
- final long[] cpuTimesMs = new long[mCpuFreqsCount];
+ final long[] cpuTimesMs;
try {
final byte[] data = mInjector.readData(procFile);
+ if (!mCpuFreqsCountVerified) {
+ verifyCpuFreqsCount(data.length, procFile);
+ }
final ByteBuffer buffer = ByteBuffer.wrap(data);
buffer.order(ByteOrder.nativeOrder());
- for (int i = 0; i < mCpuFreqsCount; ++i) {
- // Times read will be in units of 10ms
- cpuTimesMs[i] = buffer.getLong() * 10;
- }
+ cpuTimesMs = readCpuTimesFromByteBuffer(buffer);
} catch (Exception e) {
if (++mReadErrorCounter >= TOTAL_READ_ERROR_COUNT) {
mSingleUidCpuTimesAvailable = false;
@@ -103,6 +110,27 @@
}
}
+ private void verifyCpuFreqsCount(int numBytes, String procFile) {
+ final int actualCount = (numBytes / Long.BYTES);
+ if (mCpuFreqsCount != actualCount) {
+ mSingleUidCpuTimesAvailable = false;
+ throw new IllegalStateException("Freq count didn't match,"
+ + "count from " + UID_TIMES_PROC_FILE + "=" + mCpuFreqsCount + ", but"
+ + "count from " + procFile + "=" + actualCount);
+ }
+ mCpuFreqsCountVerified = true;
+ }
+
+ private long[] readCpuTimesFromByteBuffer(ByteBuffer buffer) {
+ final long[] cpuTimesMs;
+ cpuTimesMs = new long[mCpuFreqsCount];
+ for (int i = 0; i < mCpuFreqsCount; ++i) {
+ // Times read will be in units of 10ms
+ cpuTimesMs[i] = buffer.getLong() * 10;
+ }
+ return cpuTimesMs;
+ }
+
/**
* Compute and return cpu times delta of an uid using previously read cpu times and
* {@param latestCpuTimesMs}.
diff --git a/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java b/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java
index b8982cc..d97538c 100644
--- a/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java
+++ b/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java
@@ -49,7 +49,7 @@
public class KernelUidCpuFreqTimeReader {
private static final boolean DEBUG = false;
private static final String TAG = "KernelUidCpuFreqTimeReader";
- private static final String UID_TIMES_PROC_FILE = "/proc/uid_time_in_state";
+ static final String UID_TIMES_PROC_FILE = "/proc/uid_time_in_state";
public interface Callback {
void onUidCpuFreqTime(int uid, long[] cpuFreqTimeMs);
diff --git a/core/java/com/android/internal/os/KernelUidCpuTimeReader.java b/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
index 65615c0..444049e 100644
--- a/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
+++ b/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
@@ -78,10 +78,11 @@
final long userTimeUs = Long.parseLong(splitter.next(), 10);
final long systemTimeUs = Long.parseLong(splitter.next(), 10);
+ boolean notifyCallback = false;
+ long userTimeDeltaUs = userTimeUs;
+ long systemTimeDeltaUs = systemTimeUs;
// Only report if there is a callback and if this is not the first read.
if (callback != null && mLastTimeReadUs != 0) {
- long userTimeDeltaUs = userTimeUs;
- long systemTimeDeltaUs = systemTimeUs;
int index = mLastUserTimeUs.indexOfKey(uid);
if (index >= 0) {
userTimeDeltaUs -= mLastUserTimeUs.valueAt(index);
@@ -114,12 +115,13 @@
}
}
- if (userTimeDeltaUs != 0 || systemTimeDeltaUs != 0) {
- callback.onUidCpuTime(uid, userTimeDeltaUs, systemTimeDeltaUs);
- }
+ notifyCallback = (userTimeDeltaUs != 0 || systemTimeDeltaUs != 0);
}
mLastUserTimeUs.put(uid, userTimeUs);
mLastSystemTimeUs.put(uid, systemTimeUs);
+ if (notifyCallback) {
+ callback.onUidCpuTime(uid, userTimeDeltaUs, systemTimeDeltaUs);
+ }
}
} catch (IOException e) {
Slog.e(TAG, "Failed to read uid_cputime: " + e.getMessage());
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index 66475e4..895be08 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -71,10 +71,11 @@
public void uncaughtException(Thread t, Throwable e) {
// Don't re-enter if KillApplicationHandler has already run
if (mCrashing) return;
- if (mApplicationObject == null) {
- // The "FATAL EXCEPTION" string is still used on Android even though
- // apps can set a custom UncaughtExceptionHandler that renders uncaught
- // exceptions non-fatal.
+
+ // mApplicationObject is null for non-zygote java programs (e.g. "am")
+ // There are also apps running with the system UID. We don't want the
+ // first clause in either of these two cases, only for system_server.
+ if (mApplicationObject == null && (Process.SYSTEM_UID == Process.myUid())) {
Clog_e(TAG, "*** FATAL EXCEPTION IN SYSTEM PROCESS: " + t.getName(), e);
} else {
StringBuilder message = new StringBuilder();
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index e69a360..fac6b23 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -53,8 +53,8 @@
public static final int DISABLE_VERIFIER = 1 << 9;
/** Only use oat files located in /system. Otherwise use dex/jar/apk . */
public static final int ONLY_USE_SYSTEM_OAT_FILES = 1 << 10;
- /** Do not enfore hidden API access restrictions. */
- public static final int DISABLE_HIDDEN_API_CHECKS = 1 << 11;
+ /** Do enfore hidden API access restrictions. */
+ public static final int ENABLE_HIDDEN_API_CHECKS = 1 << 11;
/** Force generation of native debugging information for backtraces. */
public static final int DEBUG_GENERATE_MINI_DEBUG_INFO = 1 << 12;
@@ -160,9 +160,6 @@
*/
public static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
- // SystemServer is always allowed to use hidden APIs.
- runtimeFlags |= DISABLE_HIDDEN_API_CHECKS;
-
VM_HOOKS.preFork();
// Resets nice priority for zygote process.
resetNicePriority();
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 74802c8..30d81a7 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -98,10 +98,6 @@
private static final String SOCKET_NAME_ARG = "--socket-name=";
- /* Dexopt flag to disable hidden API access checks when dexopting SystemServer.
- * Must be kept in sync with com.android.server.pm.Installer. */
- private static final int DEXOPT_DISABLE_HIDDEN_API_CHECKS = 1 << 10;
-
/**
* Used to pre-load resources.
*/
@@ -569,10 +565,7 @@
if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
final String packageName = "*";
final String outputPath = null;
- // Dexopt with a flag which lifts restrictions on hidden API usage.
- // Offending methods would otherwise be re-verified at runtime and
- // we want to avoid the performance overhead of that.
- final int dexFlags = DEXOPT_DISABLE_HIDDEN_API_CHECKS;
+ final int dexFlags = 0;
final String compilerFilter = systemServerFilter;
final String uuid = StorageManager.UUID_PRIVATE_INTERNAL;
final String seInfo = null;
@@ -583,7 +576,8 @@
installd.dexopt(classPathElement, Process.SYSTEM_UID, packageName,
instructionSet, dexoptNeeded, outputPath, dexFlags, compilerFilter,
uuid, classLoaderContext, seInfo, false /* downgrade */,
- targetSdkVersion, /*profileName*/ null, /*dexMetadataPath*/ null);
+ targetSdkVersion, /*profileName*/ null, /*dexMetadataPath*/ null,
+ "server-dexopt");
} catch (RemoteException | ServiceSpecificException e) {
// Ignore (but log), we need this on the classpath for fallback mode.
Log.w(TAG, "Failed compiling classpath element for system server: "
diff --git a/core/java/com/android/internal/print/DumpUtils.java b/core/java/com/android/internal/print/DumpUtils.java
index 1916c11..f44a1d1 100644
--- a/core/java/com/android/internal/print/DumpUtils.java
+++ b/core/java/com/android/internal/print/DumpUtils.java
@@ -213,10 +213,9 @@
PrintAttributes.MediaSize mediaSize = attributes.getMediaSize();
if (mediaSize != null) {
writeMediaSize(context, proto, "media_size", PrintAttributesProto.MEDIA_SIZE, mediaSize);
+ proto.write("is_portrait", PrintAttributesProto.IS_PORTRAIT, attributes.isPortrait());
}
- proto.write("is_portrait", PrintAttributesProto.IS_PORTRAIT, attributes.isPortrait());
-
PrintAttributes.Resolution res = attributes.getResolution();
if (res != null) {
writeResolution(proto, "resolution", PrintAttributesProto.RESOLUTION, res);
diff --git a/core/java/com/android/internal/util/OWNERS b/core/java/com/android/internal/util/OWNERS
new file mode 100644
index 0000000..21d750c
--- /dev/null
+++ b/core/java/com/android/internal/util/OWNERS
@@ -0,0 +1,24 @@
+per-file AsyncChannel*=lorenzo@google.com
+per-file AsyncChannel*=satk@google.com
+per-file AsyncChannel*=silberst@google.com
+per-file BitUtils*=ek@google.com
+per-file BitUtils*=lorenzo@google.com
+per-file BitUtils*=satk@google.com
+per-file MessageUtils*=ek@google.com
+per-file MessageUtils*=lorenzo@google.com
+per-file MessageUtils*=satk@google.com
+per-file Protocol*=ek@google.com
+per-file Protocol*=lorenzo@google.com
+per-file Protocol*=quiche@google.com
+per-file Protocol*=satk@google.com
+per-file Protocol*=silberst@google.com
+per-file RingBuffer*=ek@google.com
+per-file RingBuffer*=lorenzo@google.com
+per-file RingBuffer*=satk@google.com
+per-file State*=ek@google.com
+per-file State*=lorenzo@google.com
+per-file State*=quiche@google.com
+per-file State*=silberst@google.com
+per-file TokenBucket*=ek@google.com
+per-file TokenBucket*=lorenzo@google.com
+per-file TokenBucket*=satk@google.com
diff --git a/core/jni/OWNERS b/core/jni/OWNERS
new file mode 100644
index 0000000..ce79049
--- /dev/null
+++ b/core/jni/OWNERS
@@ -0,0 +1,12 @@
+# Camera
+per-file *Camera*,*camera* = cychen@google.com
+per-file *Camera*,*camera* = epeev@google.com
+per-file *Camera*,*camera* = etalvala@google.com
+per-file *Camera*,*camera* = shuzhenwang@google.com
+per-file *Camera*,*camera* = yinchiayeh@google.com
+per-file *Camera*,*camera* = zhijunhe@google.com
+
+# Connectivity
+per-file android_net_*=ek@google.com
+per-file android_net_*=lorenzo@google.com
+per-file android_net_*=satk@google.com
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 0ef5445..8ca5062 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -846,6 +846,14 @@
transaction->setOverrideScalingMode(ctrl, scalingMode);
}
+static void nativeDestroyInTransaction(JNIEnv* env, jclass clazz,
+ jlong transactionObj,
+ jlong nativeObject) {
+ auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+ auto ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);
+ transaction->destroySurface(ctrl);
+}
+
static jobject nativeGetHandle(JNIEnv* env, jclass clazz, jlong nativeObject) {
auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
return javaObjectForIBinder(env, ctrl->getHandle());
@@ -997,6 +1005,8 @@
(void*)nativeSeverChildren } ,
{"nativeSetOverrideScalingMode", "(JJI)V",
(void*)nativeSetOverrideScalingMode },
+ {"nativeDestroy", "(JJ)V",
+ (void*)nativeDestroyInTransaction },
{"nativeGetHandle", "(J)Landroid/os/IBinder;",
(void*)nativeGetHandle },
{"nativeScreenshotToBuffer",
diff --git a/core/proto/android/net/OWNERS b/core/proto/android/net/OWNERS
new file mode 100644
index 0000000..a845dcb
--- /dev/null
+++ b/core/proto/android/net/OWNERS
@@ -0,0 +1,5 @@
+set noparent
+
+ek@google.com
+lorenzo@google.com
+satk@google.com
diff --git a/core/proto/android/os/cpufreq.proto b/core/proto/android/os/cpufreq.proto
index 8481ffc..46f4901 100644
--- a/core/proto/android/os/cpufreq.proto
+++ b/core/proto/android/os/cpufreq.proto
@@ -16,32 +16,30 @@
syntax = "proto2";
option java_multiple_files = true;
-option java_outer_classname = "CpuFreqProto";
import "frameworks/base/libs/incident/proto/android/privacy.proto";
package android.os;
// cpu frequency time from /sys/devices/system/cpu/cpufreq/all_time_in_state
-message CpuFreq {
+message CpuFreqProto {
option (android.msg_privacy).dest = DEST_AUTOMATIC;
optional int32 jiffy_hz = 1; // obtain by system config.
- repeated CpuFreqStats cpu_freqs = 2;
-}
-
-// frequency time pre cpu, unit in jiffy, TODO: obtain jiffies.
-message CpuFreqStats {
- option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
- optional string cpu_name = 1;
-
- message TimeInState {
+ // frequency time pre cpu, unit in jiffy.
+ message Stats {
option (android.msg_privacy).dest = DEST_AUTOMATIC;
- optional int32 state_khz = 1; // cpu frequency
- optional int64 time_jiffy = 2; // number of jiffies
+ optional string cpu_name = 1;
+
+ message TimeInState {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional int32 state_khz = 1; // cpu frequency
+ optional int64 time_jiffy = 2; // number of jiffies
+ }
+ repeated TimeInState times = 2;
}
- repeated TimeInState times = 2;
+ repeated Stats cpu_freqs = 2;
}
diff --git a/core/proto/android/os/cpuinfo.proto b/core/proto/android/os/cpuinfo.proto
index ca43602..ce69fc9 100644
--- a/core/proto/android/os/cpuinfo.proto
+++ b/core/proto/android/os/cpuinfo.proto
@@ -16,7 +16,6 @@
syntax = "proto2";
option java_multiple_files = true;
-option java_outer_classname = "CpuInfoProto";
import "frameworks/base/libs/incident/proto/android/privacy.proto";
@@ -28,7 +27,7 @@
*
* Next Tag: 6
*/
-message CpuInfo {
+message CpuInfoProto {
option (android.msg_privacy).dest = DEST_AUTOMATIC;
message TaskStats {
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index 698f394..9a53b89 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -46,18 +46,12 @@
import "frameworks/base/core/proto/android/util/event_log_tags.proto";
import "frameworks/base/core/proto/android/util/log.proto";
import "frameworks/base/libs/incident/proto/android/os/header.proto";
+import "frameworks/base/libs/incident/proto/android/os/metadata.proto";
import "frameworks/base/libs/incident/proto/android/privacy.proto";
import "frameworks/base/libs/incident/proto/android/section.proto";
package android.os;
-// This field contains internal metadata associated with an incident report,
-// such as the section ids and privacy policy specs from caller as well as how long
-// and how many bytes a section takes, etc.
-message IncidentMetadata {
-
-}
-
// privacy field options must not be set at this level because all
// the sections are able to be controlled and configured by section ids.
// Instead privacy field options need to be configured in each section proto message.
@@ -122,32 +116,32 @@
];
// Linux services
- optional Procrank procrank = 2000 [
+ optional ProcrankProto procrank = 2000 [
(section).type = SECTION_NONE, // disable procrank until figure out permission
(section).args = "/system/xbin/procrank"
];
- optional PageTypeInfo page_type_info = 2001 [
+ optional PageTypeInfoProto page_type_info = 2001 [
(section).type = SECTION_FILE,
(section).args = "/proc/pagetypeinfo"
];
- optional KernelWakeSources kernel_wake_sources = 2002 [
+ optional KernelWakeSourcesProto kernel_wake_sources = 2002 [
(section).type = SECTION_FILE,
(section).args = "/d/wakeup_sources"
];
- optional CpuInfo cpu_info = 2003 [
+ optional CpuInfoProto cpu_info = 2003 [
(section).type = SECTION_COMMAND,
(section).args = "top -b -n 1 -H -s 6 -o pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name"
];
- optional CpuFreq cpu_freq = 2004 [
+ optional CpuFreqProto cpu_freq = 2004 [
(section).type = SECTION_FILE,
(section).args = "/sys/devices/system/cpu/cpufreq/all_time_in_state"
];
- optional PsDumpProto processes_and_threads = 2005 [
+ optional PsProto processes_and_threads = 2005 [
(section).type = SECTION_COMMAND,
(section).args = "ps -A -T -Z -O pri,nice,rtprio,sched,pcy,time"
];
diff --git a/core/proto/android/os/kernelwake.proto b/core/proto/android/os/kernelwake.proto
index c296dab..5021a06 100644
--- a/core/proto/android/os/kernelwake.proto
+++ b/core/proto/android/os/kernelwake.proto
@@ -16,41 +16,40 @@
syntax = "proto2";
option java_multiple_files = true;
-option java_outer_classname = "WakeupSourcesProto";
import "frameworks/base/libs/incident/proto/android/privacy.proto";
package android.os;
-message KernelWakeSources {
+message KernelWakeSourcesProto {
option (android.msg_privacy).dest = DEST_AUTOMATIC;
// Kernel records of what caused the application processor to wake up
- repeated WakeupSourceProto wakeup_sources = 1;
-}
+ message WakeupSource {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
-// Next Tag: 11
-message WakeupSourceProto {
- option (android.msg_privacy).dest = DEST_AUTOMATIC;
+ // Name of the event which triggers application processor
+ optional string name = 1;
- // Name of the event which triggers application processor
- optional string name = 1;
+ optional int32 active_count = 2;
- optional int32 active_count = 2;
+ optional int32 event_count = 3;
- optional int32 event_count = 3;
+ optional int32 wakeup_count = 4;
- optional int32 wakeup_count = 4;
+ optional int32 expire_count = 5;
- optional int32 expire_count = 5;
+ optional int64 active_since = 6;
- optional int64 active_since = 6;
+ optional int64 total_time = 7;
- optional int64 total_time = 7;
+ optional int64 max_time = 8;
- optional int64 max_time = 8;
+ optional int64 last_change = 9;
- optional int64 last_change = 9;
+ optional int64 prevent_suspend_time = 10;
- optional int64 prevent_suspend_time = 10;
+ // Next Tag: 11
+ }
+ repeated WakeupSource wakeup_sources = 1;
}
diff --git a/core/proto/android/os/pagetypeinfo.proto b/core/proto/android/os/pagetypeinfo.proto
index b8f618b..f5d77d6 100644
--- a/core/proto/android/os/pagetypeinfo.proto
+++ b/core/proto/android/os/pagetypeinfo.proto
@@ -16,7 +16,6 @@
syntax = "proto2";
option java_multiple_files = true;
-option java_outer_classname = "PageTypeInfoProto";
import "frameworks/base/libs/incident/proto/android/privacy.proto";
@@ -37,49 +36,47 @@
*
* Next tag: 5
*/
-message PageTypeInfo {
+message PageTypeInfoProto {
option (android.msg_privacy).dest = DEST_AUTOMATIC;
optional int32 page_block_order = 1;
optional int32 pages_per_block = 2;
- repeated MigrateTypeProto migrate_types = 3;
+ // Next tag: 5
+ message MigrateType {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
- repeated BlockProto blocks = 4;
-}
+ optional int32 node = 1;
-// Next tag: 5
-message MigrateTypeProto {
- option (android.msg_privacy).dest = DEST_AUTOMATIC;
+ optional string zone = 2;
- optional int32 node = 1;
+ optional string type = 3;
- optional string zone = 2;
+ // order level starts from 0 for 4KB to page_block_order defined above, e.g. 10 for 4096KB
+ repeated int32 free_pages_count = 4;
+ }
+ repeated MigrateType migrate_types = 3;
- optional string type = 3;
+ // Next tag: 9
+ message Block {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
- // order level starts from 0 for 4KB to page_block_order defined above, e.g. 10 for 4096KB
- repeated int32 free_pages_count = 4;
-}
+ optional int32 node = 1;
-// Next tag: 9
-message BlockProto {
- option (android.msg_privacy).dest = DEST_AUTOMATIC;
+ optional string zone = 2;
- optional int32 node = 1;
+ optional int32 unmovable = 3;
- optional string zone = 2;
+ optional int32 reclaimable = 4;
- optional int32 unmovable = 3;
+ optional int32 movable = 5;
- optional int32 reclaimable = 4;
+ optional int32 cma = 6;
- optional int32 movable = 5;
+ optional int32 reserve = 7;
- optional int32 cma = 6;
-
- optional int32 reserve = 7;
-
- optional int32 isolate = 8;
+ optional int32 isolate = 8;
+ }
+ repeated Block blocks = 4;
}
diff --git a/core/proto/android/os/procrank.proto b/core/proto/android/os/procrank.proto
index 204a5af..ff7515e 100644
--- a/core/proto/android/os/procrank.proto
+++ b/core/proto/android/os/procrank.proto
@@ -16,78 +16,73 @@
syntax = "proto2";
option java_multiple_files = true;
-option java_outer_classname = "ProcrankProto";
import "frameworks/base/libs/incident/proto/android/privacy.proto";
package android.os;
//Memory usage of running processes
-message Procrank {
+message ProcrankProto {
option (android.msg_privacy).dest = DEST_AUTOMATIC;
// Currently running process
- repeated ProcessProto processes = 1;
+ // Next Tag: 11
+ message Process {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ // ID of the process
+ optional int32 pid = 1;
+
+ // virtual set size, unit KB
+ optional int64 vss = 2;
+
+ // resident set size, unit KB
+ optional int64 rss = 3;
+
+ // proportional set size, unit KB
+ optional int64 pss = 4;
+
+ // unique set size, unit KB
+ optional int64 uss = 5;
+
+ // swap size, unit KB
+ optional int64 swap = 6;
+
+ // proportional swap size, unit KB
+ optional int64 pswap = 7;
+
+ // unique swap size, unit KB
+ optional int64 uswap = 8;
+
+ // zswap size, unit KB
+ optional int64 zswap = 9;
+
+ // process command
+ optional string cmdline = 10;
+ }
+ repeated Process processes = 1;
// Summary
- optional SummaryProto summary = 2;
-}
+ // Next Tag: 3
+ message Summary {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
-// Next Tag: 11
-message ProcessProto {
- option (android.msg_privacy).dest = DEST_AUTOMATIC;
+ optional Process total = 1;
- // ID of the process
- optional int32 pid = 1;
+ // TODO: sync on how to use these values
+ message Zram {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
- // virtual set size, unit KB
- optional int64 vss = 2;
+ optional string raw_text = 1;
+ }
+ optional Zram zram = 2;
- // resident set size, unit KB
- optional int64 rss = 3;
+ message Ram {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
- // proportional set size, unit KB
- optional int64 pss = 4;
-
- // unique set size, unit KB
- optional int64 uss = 5;
-
- // swap size, unit KB
- optional int64 swap = 6;
-
- // proportional swap size, unit KB
- optional int64 pswap = 7;
-
- // unique swap size, unit KB
- optional int64 uswap = 8;
-
- // zswap size, unit KB
- optional int64 zswap = 9;
-
- // process command
- optional string cmdline = 10;
-}
-
-// Next Tag: 3
-message SummaryProto {
- option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
- optional ProcessProto total = 1;
-
- optional ZramProto zram = 2;
-
- optional RamProto ram = 3;
-}
-
-// TODO: sync on how to use these values
-message ZramProto {
- option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
- optional string raw_text = 1;
-}
-
-message RamProto {
- option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
- optional string raw_text = 1;
+ optional string raw_text = 1;
+ }
+ optional Ram ram = 3;
+ }
+ optional Summary summary = 2;
}
diff --git a/core/proto/android/os/ps.proto b/core/proto/android/os/ps.proto
index 9cce727..0ab92d7 100644
--- a/core/proto/android/os/ps.proto
+++ b/core/proto/android/os/ps.proto
@@ -22,7 +22,7 @@
import "frameworks/base/libs/incident/proto/android/privacy.proto";
-message PsDumpProto {
+message PsProto {
option (android.msg_privacy).dest = DEST_AUTOMATIC;
message Process {
diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto
index f2b7ab2..6b92aa8 100644
--- a/core/proto/android/providers/settings.proto
+++ b/core/proto/android/providers/settings.proto
@@ -399,6 +399,7 @@
optional SettingProto euicc_factory_reset_timeout_millis = 333 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto storage_settings_clobber_threshold = 334 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto chained_battery_attribution_enabled = 353 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto hidden_api_blacklist_exemptions = 355 [ (android.privacy).dest = DEST_AUTOMATIC ];
// Subscription to be used for voice call on a multi sim device. The
// supported values are 0 = SUB1, 1 = SUB2 and etc.
optional SettingProto multi_sim_voice_call_subscription = 276 [ (android.privacy).dest = DEST_AUTOMATIC ];
@@ -421,15 +422,18 @@
optional SettingProto enable_deletion_helper_no_threshold_toggle = 340 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto notification_snooze_options = 341 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto enable_gnss_raw_meas_full_tracking = 346 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto install_carrier_app_notification_persistent = 356 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto install_carrier_app_notification_sleep_millis = 357 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto zram_enabled = 347 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto smart_replies_in_notifications_flags = 348 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto show_first_crash_dialog = 349 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto show_restart_in_crash_dialog = 351 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto show_mute_in_crash_dialog = 352 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingsProto show_zen_upgrade_notification = 354 [ (android.privacy).dest = DEST_AUTOMATIC ];
// Please insert fields in the same order as in
// frameworks/base/core/java/android/provider/Settings.java.
- // Next tag = 354;
+ // Next tag = 356;
}
message SecureSettingsProto {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 5b87c33..3a527b5 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -174,6 +174,10 @@
<protected-broadcast
android:name="android.bluetooth.headsetclient.profile.action.LAST_VTAG" />
<protected-broadcast
+ android:name="android.bluetooth.hearingaid.profile.action.CONNECTION_STATE_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.hearingaid.profile.action.PLAYING_STATE_CHANGED" />
+ <protected-broadcast
android:name="android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast
android:name="android.bluetooth.a2dp.profile.action.ACTIVE_DEVICE_CHANGED" />
@@ -1827,19 +1831,20 @@
<permission android:name="android.permission.BIND_TELEPHONY_NETWORK_SERVICE"
android:protectionLevel="signature" />
- <!-- Allows an application to manage embedded subscriptions (those on a eUICC) through
- EuiccManager APIs.
+ <!-- @SystemApi Allows an application to manage embedded subscriptions (those on a eUICC)
+ through EuiccManager APIs.
<p>Protection level: signature|privileged|development
- TODO(b/35851809): Mark this as a SystemApi and remove com. prefix.
- @hide -->
- <permission android:name="com.android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS"
+ @hide
+ -->
+ <permission android:name="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS"
android:protectionLevel="signature|privileged|development" />
- <!-- Must be required by an EuiccService to ensure that only the system can bind to it.
+ <!-- @SystemApi Must be required by an EuiccService to ensure that only the system can bind to
+ it.
<p>Protection level: signature
- TODO(b/35851809): Mark this as a SystemApi and remove com. prefix.
- @hide -->
- <permission android:name="com.android.permission.BIND_EUICC_SERVICE"
+ @hide
+ -->
+ <permission android:name="android.permission.BIND_EUICC_SERVICE"
android:protectionLevel="signature" />
<!-- ================================== -->
@@ -3805,15 +3810,6 @@
<permission android:name="android.permission.INSTANT_APP_FOREGROUND_SERVICE"
android:protectionLevel="signature|development|instant|appop" />
- <!-- Allows a regular application to use {@link android.app.Service#startForeground
- Service.startForeground}.
- <p>Protection level: normal
- -->
- <permission android:name="android.permission.FOREGROUND_SERVICE"
- android:description="@string/permdesc_foregroundService"
- android:label="@string/permlab_foregroundService"
- android:protectionLevel="normal|instant" />
-
<!-- @hide Allows system components to access all app shortcuts. -->
<permission android:name="android.permission.ACCESS_SHORTCUTS"
android:protectionLevel="signature" />
diff --git a/core/res/res/color/watch_switch_track_color_material.xml b/core/res/res/color-watch/btn_watch_default_dark.xml
similarity index 82%
copy from core/res/res/color/watch_switch_track_color_material.xml
copy to core/res/res/color-watch/btn_watch_default_dark.xml
index c7dc5d3..68b0eb6 100644
--- a/core/res/res/color/watch_switch_track_color_material.xml
+++ b/core/res/res/color-watch/btn_watch_default_dark.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!-- 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.
@@ -17,6 +17,6 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false"
android:alpha="?attr/disabledAlpha"
- android:color="?android:colorPrimary" />
- <item android:color="?android:colorPrimary" />
-</selector>
\ No newline at end of file
+ android:color="?attr/colorPrimaryDark"/>
+ <item android:color="?attr/colorPrimaryDark"/>
+</selector>
diff --git a/core/res/res/color/watch_switch_thumb_color_material.xml b/core/res/res/color-watch/switch_thumb_watch_default_dark.xml
similarity index 85%
rename from core/res/res/color/watch_switch_thumb_color_material.xml
rename to core/res/res/color-watch/switch_thumb_watch_default_dark.xml
index f78d9b6..a553fa9 100644
--- a/core/res/res/color/watch_switch_thumb_color_material.xml
+++ b/core/res/res/color-watch/switch_thumb_watch_default_dark.xml
@@ -11,8 +11,8 @@
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:color="?attr/colorButtonNormal" android:alpha="?attr/disabledAlpha"
+ <item android:color="?attr/colorPrimary" android:alpha="?attr/disabledAlpha"
android:state_enabled="false" />
<item android:color="?attr/colorControlActivated" android:state_checked="true" />
- <item android:color="?attr/colorButtonNormal" />
+ <item android:color="?attr/colorPrimary" />
</selector>
diff --git a/core/res/res/color/watch_switch_track_color_material.xml b/core/res/res/color-watch/switch_track_watch_default_dark.xml
similarity index 87%
rename from core/res/res/color/watch_switch_track_color_material.xml
rename to core/res/res/color-watch/switch_track_watch_default_dark.xml
index c7dc5d3..15bbeda 100644
--- a/core/res/res/color/watch_switch_track_color_material.xml
+++ b/core/res/res/color-watch/switch_track_watch_default_dark.xml
@@ -17,6 +17,6 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false"
android:alpha="?attr/disabledAlpha"
- android:color="?android:colorPrimary" />
- <item android:color="?android:colorPrimary" />
-</selector>
\ No newline at end of file
+ android:color="?android:colorPrimaryDark" />
+ <item android:color="?android:colorPrimaryDark" />
+</selector>
diff --git a/core/res/res/drawable/watch_switch_thumb_material_anim.xml b/core/res/res/drawable-watch/switch_thumb_watch_default_dark_anim.xml
similarity index 100%
rename from core/res/res/drawable/watch_switch_thumb_material_anim.xml
rename to core/res/res/drawable-watch/switch_thumb_watch_default_dark_anim.xml
diff --git a/core/res/res/drawable/ic_settings_24dp.xml b/core/res/res/drawable/ic_settings_24dp.xml
index fc75f04..c70b122 100644
--- a/core/res/res/drawable/ic_settings_24dp.xml
+++ b/core/res/res/drawable/ic_settings_24dp.xml
@@ -16,9 +16,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
<path
- android:fillColor="#FF000000"
- android:pathData="M38.86 25.95c.08,-.64.14,-1.29.14,-1.95s-.06,-1.31,-.14,-1.95l4.23,-3.31c.38,-.3.49,-.84.24,-1.28l-4,-6.93c-.25,-.43,-.77,-.61,-1.22,-.43l-4.98 2.01c-1.03,-.79,-2.16,-1.46,-3.38,-1.97L29 4.84c-.09,-.47,-.5,-.84,-1,-.84h-8c-.5 0,-.91.37,-.99.84l-.75 5.3c-1.22.51,-2.35 1.17,-3.38 1.97L9.9 10.1c-.45,-.17,-.97 0,-1.22.43l-4 6.93c-.25.43,-.14.97.24 1.28l4.22 3.31C9.06 22.69 9 23.34 9 24s.06 1.31.14 1.95l-4.22 3.31c-.38.3,-.49.84,-.24 1.28l4 6.93c.25.43.77.61 1.22.43l4.98,-2.01c1.03.79 2.16 1.46 3.38 1.97l.75 5.3c.08.47.49.84.99.84h8c.5 0 .91,-.37.99,-.84l.75,-5.3c1.22,-.51 2.35,-1.17 3.38,-1.97l4.98 2.01c.45.17.97 0 1.22,-.43l4,-6.93c.25,-.43.14,-.97,-.24,-1.28l-4.22,-3.31zM24 31c-3.87 0,-7,-3.13,-7,-7s3.13,-7 7,-7 7 3.13 7 7,-3.13 7,-7 7z"/>
+ android:pathData="M19.4,13.0c0.0,-0.3 0.1,-0.6 0.1,-1.0s0.0,-0.7 -0.1,-1.0l2.1,-1.7c0.2,-0.2 0.2,-0.4 0.1,-0.6l-2.0,-3.5C19.5,5.1 19.3,5.0 19.0,5.1l-2.5,1.0c-0.5,-0.4 -1.1,-0.7 -1.7,-1.0l-0.4,-2.6C14.5,2.2 14.2,2.0 14.0,2.0l-4.0,0.0C9.8,2.0 9.5,2.2 9.5,2.4L9.1,5.1C8.5,5.3 8.0,5.7 7.4,6.1L5.0,5.1C4.7,5.0 4.5,5.1 4.3,5.3l-2.0,3.5C2.2,8.9 2.3,9.2 2.5,9.4L4.6,11.0c0.0,0.3 -0.1,0.6 -0.1,1.0s0.0,0.7 0.1,1.0l-2.1,1.7c-0.2,0.2 -0.2,0.4 -0.1,0.6l2.0,3.5C4.5,18.9 4.7,19.0 5.0,18.9l2.5,-1.0c0.5,0.4 1.1,0.7 1.7,1.0l0.4,2.6c0.0,0.2 0.2,0.4 0.5,0.4l4.0,0.0c0.2,0.0 0.5,-0.2 0.5,-0.4l0.4,-2.6c0.6,-0.3 1.2,-0.6 1.7,-1.0l2.5,1.0c0.2,0.1 0.5,0.0 0.6,-0.2l2.0,-3.5c0.1,-0.2 0.1,-0.5 -0.1,-0.6L19.4,13.0zM12.0,15.5c-1.9,0.0 -3.5,-1.6 -3.5,-3.5s1.6,-3.5 3.5,-3.5s3.5,1.6 3.5,3.5S13.9,15.5 12.0,15.5z"
+ android:fillColor="#FF000000" />
</vector>
diff --git a/core/res/res/drawable/ic_signal_cellular_alt_24px.xml b/core/res/res/drawable/ic_signal_cellular_alt_24px.xml
new file mode 100644
index 0000000..29f1f43
--- /dev/null
+++ b/core/res/res/drawable/ic_signal_cellular_alt_24px.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="20dp"
+ android:height="21dp"
+ android:viewportWidth="20"
+ android:viewportHeight="21">
+
+ <group
+ android:translateX="-31.000000"
+ android:translateY="-77.000000">
+ <group
+ android:translateX="24.000000"
+ android:translateY="72.000000">
+ <path
+ android:fillType="evenOdd"
+ android:strokeWidth="1"
+ android:pathData="M 0 0 H 32 V 32 H 0 V 0 Z" />
+ <path
+ android:fillColor="#4285F4"
+ android:strokeWidth="1"
+ android:pathData="M23,5 L27,5 L27,26 L23,26 L23,5 Z M7,18.125 L11,18.125 L11,26 L7,26 L7,18.125 Z
+M15,11.5625 L19,11.5625 L19,26 L15,26 L15,11.5625 Z" />
+ </group>
+ </group>
+</vector>
\ No newline at end of file
diff --git a/core/res/res/layout-watch/preference_widget_switch.xml b/core/res/res/layout-watch/preference_widget_switch.xml
index a1a845a..1f9d678 100644
--- a/core/res/res/layout-watch/preference_widget_switch.xml
+++ b/core/res/res/layout-watch/preference_widget_switch.xml
@@ -21,11 +21,11 @@
android:layout_height="40dp"
android:switchMinWidth="40dp"
android:layout_gravity="center"
- android:thumb="@drawable/watch_switch_thumb_material_anim"
- android:thumbTint="@color/watch_switch_thumb_color_material"
+ android:thumb="@drawable/switch_thumb_watch_default_dark_anim"
+ android:thumbTint="@color/switch_thumb_watch_default_dark"
android:thumbTintMode="multiply"
android:track="@drawable/watch_switch_track_mtrl"
- android:trackTint="@color/watch_switch_track_color_material"
+ android:trackTint="@color/switch_track_watch_default_dark"
android:focusable="false"
android:clickable="false"
android:background="@null" />
diff --git a/core/res/res/layout/autofill_dataset_picker_fullscreen.xml b/core/res/res/layout/autofill_dataset_picker_fullscreen.xml
new file mode 100644
index 0000000..07298c1
--- /dev/null
+++ b/core/res/res/layout/autofill_dataset_picker_fullscreen.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/autofill_dataset_picker"
+ style="@style/AutofillDatasetPicker"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/autofill_window_title"
+ android:layout_above="@+id/autofill_dataset_container"
+ android:layout_alignStart="@+id/autofill_dataset_container"
+ android:textSize="16sp"/>
+
+ <!-- autofill_container is the common parent for inserting authentication item or
+ autofill_dataset_list-->
+ <FrameLayout
+ android:id="@+id/autofill_dataset_container"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true">
+ <ListView
+ android:id="@+id/autofill_dataset_list"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:clickable="true"
+ android:divider="@null"
+ android:drawSelectorOnTop="true"
+ android:visibility="gone"/>
+ </FrameLayout>
+
+</RelativeLayout>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index df0f578..ba64d0f 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -264,10 +264,8 @@
<string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
<string name="safeMode" msgid="2788228061547930246">"Sikker tilstand"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
- <!-- no translation found for user_owner_label (8836124313744349203) -->
- <skip />
- <!-- no translation found for managed_profile_label (8947929265267690522) -->
- <skip />
+ <string name="user_owner_label" msgid="8836124313744349203">"Skift til personlig profil"</string>
+ <string name="managed_profile_label" msgid="8947929265267690522">"Skift til arbejdsprofil"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktpersoner"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"have adgang til dine kontaktpersoner"</string>
<string name="permgrouprequest_contacts" msgid="1601591667800538208">"Giv <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> adgang til dine kontaktpersoner"</string>
@@ -357,6 +355,8 @@
<string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"Tillader, at appen gør dele af sig selv vedholdende i hukommelsen. Dette kan begrænse den tilgængelige hukommelse for andre apps, hvilket gør tabletten langsommere."</string>
<string name="permdesc_persistentActivity" product="tv" msgid="5086862529499103587">"Giver appen lov til at gøre dele af sig selv vedholdende i hukommelsen. Dette kan begrænse den tilgængelige hukommelse for andre apps og derved gøre fjernsynet langsommere."</string>
<string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"Tillader, at appen gør dele af sig selv vedholdende i hukommelsen. Dette kan begrænse den tilgængelige hukommelse for andre apps, hvilket gør telefonen langsommere."</string>
+ <string name="permlab_foregroundService" msgid="3310786367649133115">"kør tjeneste i forgrunden"</string>
+ <string name="permdesc_foregroundService" msgid="6471634326171344622">"Tillad, at appen anvender tjenester i forgrunden."</string>
<string name="permlab_getPackageSize" msgid="7472921768357981986">"måle appens lagerplads"</string>
<string name="permdesc_getPackageSize" msgid="3921068154420738296">"Tillader, at en app kan hente sin kode, data og cachestørrelser"</string>
<string name="permlab_writeSettings" msgid="2226195290955224730">"ændre systemindstillinger"</string>
@@ -419,10 +419,8 @@
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Tillader, at appen kan få adgang til telefonfunktionerne på enheden. Med denne tilladelse kan appen fastslå telefonnummeret og enheds-id\'erne, hvorvidt et opkald er aktivt samt det eksterne nummer, der oprettes forbindelse til via et opkald."</string>
<string name="permlab_manageOwnCalls" msgid="1503034913274622244">"dirigere opkald gennem systemet"</string>
<string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Tillader appen at dirigere sine opkald gennem systemet for at forbedre opkaldsoplevelsen."</string>
- <!-- no translation found for permlab_acceptHandover (2661534649736022409) -->
- <skip />
- <!-- no translation found for permdesc_acceptHandovers (4570660484220539698) -->
- <skip />
+ <string name="permlab_acceptHandover" msgid="2661534649736022409">"fortsætte et opkald fra en anden app"</string>
+ <string name="permdesc_acceptHandovers" msgid="4570660484220539698">"Tillader, at appen fortsætter et opkald, der blev startet i en anden app."</string>
<string name="permlab_readPhoneNumbers" msgid="6108163940932852440">"læse telefonnumre"</string>
<string name="permdesc_readPhoneNumbers" msgid="8559488833662272354">"Tillader, at appen får adgang til telefonnumrene på denne enhed."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"afholde tabletcomputeren fra at gå i dvale"</string>
@@ -497,11 +495,12 @@
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Fingeraftrykket kan ikke gemmes. Fjern et eksisterende fingeraftryk."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Registrering af fingeraftryk fik timeout. Prøv igen."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Fingeraftrykshandlingen blev annulleret."</string>
- <!-- no translation found for fingerprint_error_user_canceled (7999639584615291494) -->
- <skip />
+ <string name="fingerprint_error_user_canceled" msgid="7999639584615291494">"Fingeraftrykshandlingen blev annulleret af brugeren."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Du har prøvet for mange gange. Prøv igen senere."</string>
<string name="fingerprint_error_lockout_permanent" msgid="5033251797919508137">"Du har brugt for mange forsøg. Fingeraftrykslæseren er deaktiveret."</string>
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Prøv igen."</string>
+ <string name="fingerprint_error_no_fingerprints" msgid="7654382120628334248">"Der er ikke registreret nogen fingeraftryk."</string>
+ <string name="fingerprint_error_hw_not_present" msgid="5729436878065119329">"Denne enhed har ingen fingeraftrykslæser"</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Fingeraftryk <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -1000,12 +999,9 @@
<string name="browse" msgid="1245903488306147205">"Åbn"</string>
<string name="sms" msgid="4560537514610063430">"Besked"</string>
<string name="add_contact" msgid="7867066569670597203">"Tilføj"</string>
- <!-- no translation found for view_calendar (979609872939597838) -->
- <skip />
- <!-- no translation found for add_calendar_event (1953664627192056206) -->
- <skip />
- <!-- no translation found for view_flight (7691640491425680214) -->
- <skip />
+ <string name="view_calendar" msgid="979609872939597838">"Se"</string>
+ <string name="add_calendar_event" msgid="1953664627192056206">"Planlæg"</string>
+ <string name="view_flight" msgid="7691640491425680214">"Spor"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Der er snart ikke mere lagerplads"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Nogle systemfunktioner virker måske ikke"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Der er ikke nok ledig lagerplads til systemet. Sørg for, at du har 250 MB ledig plads, og genstart."</string>
@@ -1131,8 +1127,7 @@
<item quantity="other">Åbne Wi-Fi-netværk er tilgængelige</item>
</plurals>
<string name="wifi_available_title" msgid="3817100557900599505">"Opret forbindelse til et åbent Wi-Fi-netværk"</string>
- <!-- no translation found for wifi_available_carrier_network_title (4527932626916527897) -->
- <skip />
+ <string name="wifi_available_carrier_network_title" msgid="4527932626916527897">"Opret forbindelse til dit mobilselskabs Wi‑Fi-netværk"</string>
<string name="wifi_available_title_connecting" msgid="1557292688310330032">"Opretter forbindelse til et åbent Wi‑Fi-netværk"</string>
<string name="wifi_available_title_connected" msgid="7542672851522241548">"Forbundet til Wi-Fi-netværket"</string>
<string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Der kan ikke oprettes forbindelse til Wi-Fi-netværket"</string>
@@ -1216,13 +1211,15 @@
<string name="no_permissions" msgid="7283357728219338112">"Der kræves ingen tilladelser"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"dette kan koste dig penge"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <string name="usb_charging_notification_title" msgid="6895185153353640787">"USB oplader denne enhed"</string>
- <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB, der leverer strøm til den tilsluttede enhed"</string>
- <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB til filoverførsel"</string>
- <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB til billedoverførsel"</string>
- <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB til MIDI"</string>
- <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Tilsluttet et USB-ekstraudstyr"</string>
+ <string name="usb_charging_notification_title" msgid="1595122345358177163">"Enheden oplades via USB"</string>
+ <string name="usb_supplying_notification_title" msgid="4631045789893086181">"Den tilsluttede enhed oplades via USB"</string>
+ <string name="usb_mtp_notification_title" msgid="4238227258391151029">"Filoverførsel via USB er slået til"</string>
+ <string name="usb_ptp_notification_title" msgid="5425857879922006878">"PTP via USB er slået til"</string>
+ <string name="usb_tether_notification_title" msgid="3716143122035802501">"Netdeling via USB er slået til"</string>
+ <string name="usb_midi_notification_title" msgid="5356040379749154805">"MIDI via USB er slået til"</string>
+ <string name="usb_accessory_notification_title" msgid="1899977434994900306">"Tilstanden USB-tilbehør er slået til"</string>
<string name="usb_notification_message" msgid="3370903770828407960">"Tryk for at se flere muligheder."</string>
+ <string name="usb_power_notification_message" msgid="4647527153291917218">"Den tilsluttede enhed oplades. Tryk for at få flere valgmuligheder."</string>
<string name="usb_unsupported_audio_accessory_title" msgid="3529881374464628084">"Der blev registreret et analogt lydtilbehør"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="6309553946441565215">"Den tilsluttede enhed er ikke kompatibel med denne telefon. Tryk for at få flere oplysninger."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB-fejlretning er tilsluttet"</string>
@@ -1524,7 +1521,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%2$d</xliff:g> yderligere mislykkede forsøg til vil du blive bedt om at låse din telefon op ved hjælp af en e-mailkonto.\n\n Prøv igen om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string>
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Fjern"</string>
- <string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Vil du skrue højere op end det anbefalede lydstyrkeniveau?\n\nDu kan skade hørelsen ved at lytte til meget højt musik over længere tid."</string>
+ <string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Vil du skrue højere op end det anbefalede lydstyrkeniveau?\n\nDu kan skade hørelsen ved at lytte til meget høj musik over længere tid."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="8404780875025725199">"Vil du bruge genvejen til Hjælpefunktioner?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Når genvejen er slået til, kan du starte en hjælpefunktion ved at trykke på begge lydstyrkeknapper i tre sekunder.\n\n Nuværende hjælpefunktion:\n<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Du kan skifte funktion i Indstillinger > Hjælpefunktioner."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"Deaktiver genvej"</string>
@@ -1661,9 +1658,6 @@
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> – arbejde"</string>
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2. <xliff:g id="LABEL">%1$s</xliff:g> til arbejde"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3. <xliff:g id="LABEL">%1$s</xliff:g> til arbejde"</string>
- <string name="lock_to_app_toast" msgid="6820571533009838261">"Hvis du vil frigøre dette skærmbillede, skal du trykke på knapperne Tilbage og Oversigt og holde fingrene nede"</string>
- <string name="lock_to_app_start" msgid="6643342070839862795">"Skærmen blev fastgjort"</string>
- <string name="lock_to_app_exit" msgid="8598219838213787430">"Skærmen blev frigjort"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Bed om pinkode inden frigørelse"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Bed om oplåsningsmønster ved deaktivering"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Bed om adgangskode inden frigørelse"</string>
@@ -1757,15 +1751,11 @@
<string name="language_picker_section_all" msgid="3097279199511617537">"Alle sprog"</string>
<string name="region_picker_section_all" msgid="8966316787153001779">"Alle områder"</string>
<string name="locale_search_menu" msgid="2560710726687249178">"Søg"</string>
- <!-- no translation found for work_mode_off_title (1118691887588435530) -->
- <skip />
- <!-- no translation found for work_mode_off_message (5130856710614337649) -->
- <skip />
+ <string name="work_mode_off_title" msgid="1118691887588435530">"Skal arbejdsprofilen slås til?"</string>
+ <string name="work_mode_off_message" msgid="5130856710614337649">"Dine arbejdsapps, underretninger, data og andre funktioner til din arbejdsprofil deaktiveres"</string>
<string name="work_mode_turn_on" msgid="2062544985670564875">"Slå til"</string>
- <!-- no translation found for deprecated_target_sdk_message (1449696506742572767) -->
- <skip />
- <!-- no translation found for deprecated_target_sdk_app_store (5032340500368495077) -->
- <skip />
+ <string name="deprecated_target_sdk_message" msgid="1449696506742572767">"Denne app er lavet til en ældre version af Android og fungerer muligvis ikke korrekt. Prøv at søge efter opdateringer, eller kontakt udvikleren."</string>
+ <string name="deprecated_target_sdk_app_store" msgid="5032340500368495077">"Søg efter opdatering"</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Du har nye beskeder"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Åbn sms-appen for at se beskeden"</string>
<string name="user_encrypted_title" msgid="9054897468831672082">"Nogle funktioner er begrænsede"</string>
@@ -1832,17 +1822,14 @@
<string name="mmcc_illegal_me" msgid="1950705155760872972">"Telefon er ikke tilladt for tale"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Pop op-vindue"</string>
<string name="slice_more_content" msgid="8504342889413274608">"<xliff:g id="NUMBER">%1$d</xliff:g> mere"</string>
- <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Denne genvej kræver den nyeste app"</string>
+ <string name="shortcut_restored_on_lower_version" msgid="4860853725206702336">"Appversionen er nedgraderet, eller også er den ikke kompatibel med denne genvej"</string>
<string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Genvejen kunne ikke gendannes, da appen ikke understøtter backup og gendannelse"</string>
<string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Genvejen kunne ikke gendannes på grund af uoverensstemmelse i appsignatur"</string>
<string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Genvejen kunne ikke gendannes"</string>
<string name="shortcut_disabled_reason_unknown" msgid="5276016910284687075">"Genvejen er deaktiveret"</string>
- <!-- no translation found for harmful_app_warning_uninstall (4837672735619532931) -->
- <skip />
- <!-- no translation found for harmful_app_warning_open_anyway (596432803680914321) -->
- <skip />
- <!-- no translation found for harmful_app_warning_title (8982527462829423432) -->
- <skip />
+ <string name="harmful_app_warning_uninstall" msgid="4837672735619532931">"AFINSTALLER"</string>
+ <string name="harmful_app_warning_open_anyway" msgid="596432803680914321">"ÅBN ALLIGEVEL"</string>
+ <string name="harmful_app_warning_title" msgid="8982527462829423432">"Der er registreret en skadelig app"</string>
<string name="slices_permission_request" msgid="8484943441501672932">"<xliff:g id="APP_0">%1$s</xliff:g> anmoder om tilladelse til at vise eksempler fra <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="screenshot_edit" msgid="7867478911006447565">"Rediger"</string>
</resources>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 2436326..1b3e131 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -264,10 +264,8 @@
<string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
<string name="safeMode" msgid="2788228061547930246">"Modu segurua"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android sistema"</string>
- <!-- no translation found for user_owner_label (8836124313744349203) -->
- <skip />
- <!-- no translation found for managed_profile_label (8947929265267690522) -->
- <skip />
+ <string name="user_owner_label" msgid="8836124313744349203">"Aldatu profil pertsonalera"</string>
+ <string name="managed_profile_label" msgid="8947929265267690522">"Aldatu laneko profilera"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktuak"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"atzitu kontaktuak"</string>
<string name="permgrouprequest_contacts" msgid="1601591667800538208">"Baimendu kontaktuak atzitzea <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> aplikazioari"</string>
@@ -357,6 +355,8 @@
<string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"Beren zati batzuk memoria modu iraunkorrean ezartzeko baimena ematen die aplikazioei. Horrela, beste aplikazioek erabilgarri duten memoria murritz daiteke eta tableta motel daiteke."</string>
<string name="permdesc_persistentActivity" product="tv" msgid="5086862529499103587">"Beren zati batzuk memorian modu iraunkorrean aktibo uztea baimentzen die aplikazioei. Horrela, beste aplikazioek memoria gutxiago izan lezakete erabilgarri eta telebistak motelago funtziona lezake."</string>
<string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"Beren zati batzuk memoria modu iraunkorrean ezartzeko baimena ematen die aplikazioei. Horrela, beste aplikazioek erabilgarri duten memoria murritz daiteke eta telefonoa motel daiteke."</string>
+ <string name="permlab_foregroundService" msgid="3310786367649133115">"Exekutatu zerbitzuak aurreko planoan"</string>
+ <string name="permdesc_foregroundService" msgid="6471634326171344622">"Aurreko planoko zerbitzuak erabiltzea baimentzen dio aplikazioari."</string>
<string name="permlab_getPackageSize" msgid="7472921768357981986">"neurtu aplikazioen biltegiratze-tokia"</string>
<string name="permdesc_getPackageSize" msgid="3921068154420738296">"Bere kodea, datuak eta cache-tamainak eskuratzea baimentzen die aplikazioei."</string>
<string name="permlab_writeSettings" msgid="2226195290955224730">"aldatu sistemaren ezarpenak"</string>
@@ -419,10 +419,8 @@
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Gailuaren telefono-eginbideak atzitzeko baimena ematen die aplikazioei. Baimen horrek aplikazioari telefono-zenbakia eta gailu IDak zein diren, deirik aktibo dagoen eta deia zer zenbakirekin konektatuta dagoen zehazteko baimena ematen die aplikazioei."</string>
<string name="permlab_manageOwnCalls" msgid="1503034913274622244">"bideratu deiak sistemaren bidez"</string>
<string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Deiak sistemaren bidez bideratzea baimentzen die aplikazioei, deien zerbitzua ahal bezain ona izan dadin."</string>
- <!-- no translation found for permlab_acceptHandover (2661534649736022409) -->
- <skip />
- <!-- no translation found for permdesc_acceptHandovers (4570660484220539698) -->
- <skip />
+ <string name="permlab_acceptHandover" msgid="2661534649736022409">"Jarraitu beste aplikazio batean hasitako deia"</string>
+ <string name="permdesc_acceptHandovers" msgid="4570660484220539698">"Beste aplikazio batean hasitako dei bat jarraitzea baimentzen dio aplikazioari."</string>
<string name="permlab_readPhoneNumbers" msgid="6108163940932852440">"irakurri telefono-zenbakiak"</string>
<string name="permdesc_readPhoneNumbers" msgid="8559488833662272354">"Gailuaren telefono-zenbakiak atzitzea baimentzen die aplikazioei."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"eragotzi tableta inaktibo ezartzea"</string>
@@ -497,11 +495,12 @@
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Ezin da gorde hatz-marka digitala. Kendu lehendik gordeta duzunetako bat."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Hatz-marka digitalak prozesatzeko denbora-muga gainditu da. Saiatu berriro."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Hatz-markaren eragiketa bertan behera utzi da."</string>
- <!-- no translation found for fingerprint_error_user_canceled (7999639584615291494) -->
- <skip />
+ <string name="fingerprint_error_user_canceled" msgid="7999639584615291494">"Erabiltzaileak bertan behera utzi du hatz-marka bidezko eragiketa."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Saiakera gehiegi egin dituzu. Saiatu berriro geroago."</string>
<string name="fingerprint_error_lockout_permanent" msgid="5033251797919508137">"Saiakera gehiegi egin dituzu. Desgaitu egin da hatz-marken sentsorea."</string>
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Saiatu berriro."</string>
+ <string name="fingerprint_error_no_fingerprints" msgid="7654382120628334248">"Ez da erregistratu hatz-markarik."</string>
+ <string name="fingerprint_error_hw_not_present" msgid="5729436878065119329">"Gailu honek ez du hatz-marken sentsorerik"</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"<xliff:g id="FINGERID">%d</xliff:g> hatza"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -1000,12 +999,9 @@
<string name="browse" msgid="1245903488306147205">"Ireki"</string>
<string name="sms" msgid="4560537514610063430">"Bidali mezua"</string>
<string name="add_contact" msgid="7867066569670597203">"Gehitu"</string>
- <!-- no translation found for view_calendar (979609872939597838) -->
- <skip />
- <!-- no translation found for add_calendar_event (1953664627192056206) -->
- <skip />
- <!-- no translation found for view_flight (7691640491425680214) -->
- <skip />
+ <string name="view_calendar" msgid="979609872939597838">"Ikusi"</string>
+ <string name="add_calendar_event" msgid="1953664627192056206">"Antolatu"</string>
+ <string name="view_flight" msgid="7691640491425680214">"Egin jarraipena"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Memoria betetzen ari da"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Sistemaren funtzio batzuek ez dute agian funtzionatuko"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Sisteman ez dago behar adina memoria. Ziurtatu gutxienez 250 MB erabilgarri dituzula eta, ondoren, berrabiarazi gailua."</string>
@@ -1131,8 +1127,7 @@
<item quantity="one">Wi-Fi sare irekia erabilgarri</item>
</plurals>
<string name="wifi_available_title" msgid="3817100557900599505">"Konektatu Wi‑Fi sare irekira"</string>
- <!-- no translation found for wifi_available_carrier_network_title (4527932626916527897) -->
- <skip />
+ <string name="wifi_available_carrier_network_title" msgid="4527932626916527897">"Konektatu operadorearen Wi‑Fi sarera"</string>
<string name="wifi_available_title_connecting" msgid="1557292688310330032">"Wi‑Fi sare irekira konektatzen"</string>
<string name="wifi_available_title_connected" msgid="7542672851522241548">"Wi‑Fi sare irekira konektatuta"</string>
<string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Ezin izan da konektatu Wi‑Fi sare irekira"</string>
@@ -1217,13 +1212,15 @@
<string name="no_permissions" msgid="7283357728219338112">"Ez da baimenik behar"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"dirua kosta dakizuke"</string>
<string name="dlg_ok" msgid="7376953167039865701">"Ados"</string>
- <string name="usb_charging_notification_title" msgid="6895185153353640787">"Gailua USB bidez ari da kargatzen"</string>
- <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Konektatutako gailua USB bidez jasotzen ari da energia"</string>
- <string name="usb_mtp_notification_title" msgid="8396264943589760855">"Fitxategiak transferitzeko USBa"</string>
- <string name="usb_ptp_notification_title" msgid="1347328437083192112">"Argazkiak transferitzeko USBa"</string>
- <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI modurako USBa"</string>
- <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USB osagarri batera konektatuta"</string>
+ <string name="usb_charging_notification_title" msgid="1595122345358177163">"Gailua USB bidez kargatzen"</string>
+ <string name="usb_supplying_notification_title" msgid="4631045789893086181">"Konektatutako gailua USB bidez kargatzen ari da"</string>
+ <string name="usb_mtp_notification_title" msgid="4238227258391151029">"Aktibatuta dago USB bidezko fitxategi-transferentzia"</string>
+ <string name="usb_ptp_notification_title" msgid="5425857879922006878">"Aktibatuta dago USB bidezko PTP modua"</string>
+ <string name="usb_tether_notification_title" msgid="3716143122035802501">"Aktibatuta dago USB bidez konexioa partekatzeko aukera"</string>
+ <string name="usb_midi_notification_title" msgid="5356040379749154805">"Aktibatuta dago USB bidezko MIDI modua"</string>
+ <string name="usb_accessory_notification_title" msgid="1899977434994900306">"Aktibatuta dago USB osagarriaren modua"</string>
<string name="usb_notification_message" msgid="3370903770828407960">"Sakatu aukera gehiago ikusteko."</string>
+ <string name="usb_power_notification_message" msgid="4647527153291917218">"Konektatutako gailua kargatzen ari da. Sakatu aukera gehiago ikusteko."</string>
<string name="usb_unsupported_audio_accessory_title" msgid="3529881374464628084">"Audio-osagarri analogiko bat hauteman da"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="6309553946441565215">"Erantsitako gailua ez da telefono honekin bateragarria. Sakatu informazio gehiago lortzeko."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB arazketa konektatuta"</string>
@@ -1662,9 +1659,6 @@
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Laneko <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"Laneko 2. <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"Laneko 3. <xliff:g id="LABEL">%1$s</xliff:g>"</string>
- <string name="lock_to_app_toast" msgid="6820571533009838261">"Pantailari aingura kentzeko, eduki sakatuta Atzera eta Ikuspegi orokorra botoiak"</string>
- <string name="lock_to_app_start" msgid="6643342070839862795">"Pantaila ainguratu da"</string>
- <string name="lock_to_app_exit" msgid="8598219838213787430">"Aingura kendu zaio pantailari"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Eskatu PIN kodea aingura kendu aurretik"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Eskatu desblokeatzeko eredua aingura kendu aurretik"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Eskatu pasahitza aingura kendu aurretik"</string>
@@ -1758,15 +1752,11 @@
<string name="language_picker_section_all" msgid="3097279199511617537">"Hizkuntza guztiak"</string>
<string name="region_picker_section_all" msgid="8966316787153001779">"Lurralde guztiak"</string>
<string name="locale_search_menu" msgid="2560710726687249178">"Bilaketa"</string>
- <!-- no translation found for work_mode_off_title (1118691887588435530) -->
- <skip />
- <!-- no translation found for work_mode_off_message (5130856710614337649) -->
- <skip />
+ <string name="work_mode_off_title" msgid="1118691887588435530">"Laneko profila aktibatu?"</string>
+ <string name="work_mode_off_message" msgid="5130856710614337649">"Laneko aplikazioak, jakinarazpenak, datuak eta laneko profileko bestelako eginbideak aktibatuko dira"</string>
<string name="work_mode_turn_on" msgid="2062544985670564875">"Aktibatu"</string>
- <!-- no translation found for deprecated_target_sdk_message (1449696506742572767) -->
- <skip />
- <!-- no translation found for deprecated_target_sdk_app_store (5032340500368495077) -->
- <skip />
+ <string name="deprecated_target_sdk_message" msgid="1449696506742572767">"Aplikazioa Android-en bertsio zaharrago baterako sortu zenez, baliteke behar bezala ez funtzionatzea. Bilatu eguneratzerik baden, edo jarri garatzailearekin harremanetan."</string>
+ <string name="deprecated_target_sdk_app_store" msgid="5032340500368495077">"Bilatu eguneratzeak"</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Mezu berriak dituzu"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Mezuak ikusteko, ireki SMS mezuen aplikazioa"</string>
<string name="user_encrypted_title" msgid="9054897468831672082">"Funtzioak mugatuta egon litezke"</string>
@@ -1833,17 +1823,14 @@
<string name="mmcc_illegal_me" msgid="1950705155760872972">"Telefonoa ezin da erabili ahotsa erabiltzeko"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Leiho gainerakorra"</string>
<string name="slice_more_content" msgid="8504342889413274608">"Beste <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
- <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Aplikazioaren bertsio berriena behar da lasterbideak funtziona dezan"</string>
+ <string name="shortcut_restored_on_lower_version" msgid="4860853725206702336">"Aplikazioaren bertsio zaharrago batera aldatu da, edo aplikazioa ez da lasterbide honekin bateragarria"</string>
<string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Ezin izan da leheneratu lasterbidea aplikazioak ez duelako onartzen babeskopiak egiteko eta leheneratzeko aukera"</string>
<string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Ezin izan da leheneratu lasterbidea aplikazioaren sinadurak ez datozelako bat"</string>
<string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Ezin izan da leheneratu lasterbidea"</string>
<string name="shortcut_disabled_reason_unknown" msgid="5276016910284687075">"Desgaituta dago lasterbidea"</string>
- <!-- no translation found for harmful_app_warning_uninstall (4837672735619532931) -->
- <skip />
- <!-- no translation found for harmful_app_warning_open_anyway (596432803680914321) -->
- <skip />
- <!-- no translation found for harmful_app_warning_title (8982527462829423432) -->
- <skip />
+ <string name="harmful_app_warning_uninstall" msgid="4837672735619532931">"DESINSTALATU"</string>
+ <string name="harmful_app_warning_open_anyway" msgid="596432803680914321">"IREKI, HALA ERE"</string>
+ <string name="harmful_app_warning_title" msgid="8982527462829423432">"Aplikazio kaltegarri bat hauteman da"</string>
<string name="slices_permission_request" msgid="8484943441501672932">"<xliff:g id="APP_0">%1$s</xliff:g> aplikazioak <xliff:g id="APP_2">%2$s</xliff:g> aplikazioaren zatiak erakutsi nahi ditu"</string>
<string name="screenshot_edit" msgid="7867478911006447565">"Editatu"</string>
</resources>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 2891b8c..ade233c 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -355,6 +355,8 @@
<string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"Permet à l\'application de rendre certains de ces composants persistants dans la mémoire. Cette autorisation peut limiter la mémoire disponible pour d\'autres applications et ralentir la tablette."</string>
<string name="permdesc_persistentActivity" product="tv" msgid="5086862529499103587">"Permet à l\'application de placer certaines de ses parties en permanence dans la mémoire. Cela peut limiter la mémoire disponible pour les autres applications et ralentir le téléviseur."</string>
<string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"Permet à l\'application de rendre certains de ces composants persistants dans la mémoire. Cette autorisation peut limiter la mémoire disponible pour d\'autres applications et ralentir le téléphone."</string>
+ <string name="permlab_foregroundService" msgid="3310786367649133115">"exécuter le service en premier plan"</string>
+ <string name="permdesc_foregroundService" msgid="6471634326171344622">"Permet à l\'application d\'utiliser les services en premier plan."</string>
<string name="permlab_getPackageSize" msgid="7472921768357981986">"évaluer l\'espace de stockage de l\'application"</string>
<string name="permdesc_getPackageSize" msgid="3921068154420738296">"Permet à l\'application de récupérer la taille de son code, de ses données et de sa mémoire cache."</string>
<string name="permlab_writeSettings" msgid="2226195290955224730">"modifier les paramètres du système"</string>
@@ -497,10 +499,8 @@
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Trop de tentatives. Veuillez réessayer plus tard."</string>
<string name="fingerprint_error_lockout_permanent" msgid="5033251797919508137">"Trop de tentatives. Capteur d\'empreintes digitales désactivé."</string>
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Réessayer."</string>
- <!-- no translation found for fingerprint_error_no_fingerprints (7654382120628334248) -->
- <skip />
- <!-- no translation found for fingerprint_error_hw_not_present (5729436878065119329) -->
- <skip />
+ <string name="fingerprint_error_no_fingerprints" msgid="7654382120628334248">"Aucune empreinte digitale enregistrée."</string>
+ <string name="fingerprint_error_hw_not_present" msgid="5729436878065119329">"Cet appareil ne possède pas de capteur d\'empreintes digitales"</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Doigt <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -1211,23 +1211,15 @@
<string name="no_permissions" msgid="7283357728219338112">"Aucune autorisation requise"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"cela peut engendrer des frais"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <!-- no translation found for usb_charging_notification_title (1595122345358177163) -->
- <skip />
- <!-- no translation found for usb_supplying_notification_title (4631045789893086181) -->
- <skip />
- <!-- no translation found for usb_mtp_notification_title (4238227258391151029) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (5425857879922006878) -->
- <skip />
- <!-- no translation found for usb_tether_notification_title (3716143122035802501) -->
- <skip />
- <!-- no translation found for usb_midi_notification_title (5356040379749154805) -->
- <skip />
- <!-- no translation found for usb_accessory_notification_title (1899977434994900306) -->
- <skip />
+ <string name="usb_charging_notification_title" msgid="1595122345358177163">"Chargement de cet appareil par USB"</string>
+ <string name="usb_supplying_notification_title" msgid="4631045789893086181">"Chargement de l\'appareil connecté par USB"</string>
+ <string name="usb_mtp_notification_title" msgid="4238227258391151029">"Transfert de fichiers USB activé"</string>
+ <string name="usb_ptp_notification_title" msgid="5425857879922006878">"Mode PTP par USB activé"</string>
+ <string name="usb_tether_notification_title" msgid="3716143122035802501">"Partage de connexion USB activé"</string>
+ <string name="usb_midi_notification_title" msgid="5356040379749154805">"Mode MIDI par USB activé"</string>
+ <string name="usb_accessory_notification_title" msgid="1899977434994900306">"Mode accessoire USB activé"</string>
<string name="usb_notification_message" msgid="3370903770828407960">"Touchez pour afficher plus d\'options."</string>
- <!-- no translation found for usb_power_notification_message (4647527153291917218) -->
- <skip />
+ <string name="usb_power_notification_message" msgid="4647527153291917218">"Chargement de l\'appareil connecté. Touchez l\'écran pour afficher plus d\'options."</string>
<string name="usb_unsupported_audio_accessory_title" msgid="3529881374464628084">"Un accessoire audio analogique a été détecté"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="6309553946441565215">"L\'appareil connecté n\'est pas compatible avec ce téléphone. Touchez ici en savoir plus."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Débogage USB activé"</string>
@@ -1830,8 +1822,7 @@
<string name="mmcc_illegal_me" msgid="1950705155760872972">"Ce téléphone n\'est pas autorisé pour la voix"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Fenêtre contextuelle"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
- <!-- no translation found for shortcut_restored_on_lower_version (4860853725206702336) -->
- <skip />
+ <string name="shortcut_restored_on_lower_version" msgid="4860853725206702336">"La version de l\'application a été rétrogradée ou n\'est pas compatible avec ce raccourci"</string>
<string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Impossible de restaurer le raccourci, car l\'application ne prend pas en charge la sauvegarde et la restauration"</string>
<string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Impossible de restaurer le raccourci en raison d\'une erreur de correspondance des signature d\'applications"</string>
<string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Impossible de restaurer le raccourci"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 0b7b7d09..efee736 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -264,10 +264,8 @@
<string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
<string name="safeMode" msgid="2788228061547930246">"Անվտանգ ռեժիմ"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android համակարգ"</string>
- <!-- no translation found for user_owner_label (8836124313744349203) -->
- <skip />
- <!-- no translation found for managed_profile_label (8947929265267690522) -->
- <skip />
+ <string name="user_owner_label" msgid="8836124313744349203">"Բացել անձնական պրոֆիլը"</string>
+ <string name="managed_profile_label" msgid="8947929265267690522">"Բացել աշխատանքային պրոֆիլը"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Կոնտակտներ"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"օգտագործել ձեր կոնտակտները"</string>
<string name="permgrouprequest_contacts" msgid="1601591667800538208">"Թույլ տալ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> հավելվածին օգտագործել ձեր կոնտակտները"</string>
@@ -357,6 +355,8 @@
<string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"Թույլ է տալիս հավելվածին մնայուն դարձնել իր մասերը հիշողության մեջ: Սա կարող է սահմանափակել այլ հավելվածներին հասանելի հիշողությունը` դանդաղեցնելով պլանշետի աշխատանքը:"</string>
<string name="permdesc_persistentActivity" product="tv" msgid="5086862529499103587">"Թույլ է տալիս հավելվածին պահել իր տարրերը հիշողության մեջ: Սա կարող է սահմանափակել այլ հավելվածների համար հատկացված հիշողությունը և դանդաղեցնել հեռուստացույցի աշխատանքը:"</string>
<string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"Թույլ է տալիս հավելվածին մնայուն դարձնել իր մասերը հիշողության մեջ: Սա կարող է սահմանափակել այլ հավելվածներին հասանելի հիշողությունը` դանդաղեցնելով հեռախոսի աշխատանքը:"</string>
+ <string name="permlab_foregroundService" msgid="3310786367649133115">"աշխատեցնել ակտիվ ծառայությունները"</string>
+ <string name="permdesc_foregroundService" msgid="6471634326171344622">"Թույլ է տալիս հավելվածին օգտագործել ակտիվ ծառայությունները:"</string>
<string name="permlab_getPackageSize" msgid="7472921768357981986">"չափել հավելվածի պահոցի տարածքը"</string>
<string name="permdesc_getPackageSize" msgid="3921068154420738296">"Թույլ է տալիս հավելվածին առբերել իր կոդը, տվյալները և քեշի չափերը"</string>
<string name="permlab_writeSettings" msgid="2226195290955224730">"փոփոխել համակարգի կարգավորումները"</string>
@@ -419,10 +419,8 @@
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Թույլ է տալիս հավելվածին օգտագործել սարքի հեռախոսային գործիքները: Այս թույլտվությունը հավելվածին հնարավորություն է տալիս որոշել հեռախոսահամարը և սարքի ID-ները, արդյոք զանգը ակտիվ է և միացված զանգի հեռակա հեռախոսահամարը:"</string>
<string name="permlab_manageOwnCalls" msgid="1503034913274622244">"զանգերն ուղարկել համակարգի միջոցով"</string>
<string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Հավելվածին թույլ է տալիս իր զանգերն ուղարկել համակարգի միջոցով՝ կապի որակը բարձրացնելու նպատակով։"</string>
- <!-- no translation found for permlab_acceptHandover (2661534649736022409) -->
- <skip />
- <!-- no translation found for permdesc_acceptHandovers (4570660484220539698) -->
- <skip />
+ <string name="permlab_acceptHandover" msgid="2661534649736022409">"շարունակել զանգը այլ հավելվածի միջոցով"</string>
+ <string name="permdesc_acceptHandovers" msgid="4570660484220539698">"Թույլ է տալիս հավելվածին շարունակել մեկ այլ հավելվածի միջոցով սկսած զանգը:"</string>
<string name="permlab_readPhoneNumbers" msgid="6108163940932852440">"օգտագործել հեռախոսահամարները"</string>
<string name="permdesc_readPhoneNumbers" msgid="8559488833662272354">"Հավելվածին թույլ է տալիս օգտագործել սարքի հեռախոսահամարները:"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"զերծ պահել պլանշետը քնելուց"</string>
@@ -497,11 +495,12 @@
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Հնարավոր չէ պահել մատնահետքը: Հեռացրեք առկա մատնահետքը:"</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Մատնահետքի գրանցման ժամանակը սպառվել է: Փորձեք նորից:"</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Իսկորոշումը մատնահետքի միջոցով չեղարկվեց:"</string>
- <!-- no translation found for fingerprint_error_user_canceled (7999639584615291494) -->
- <skip />
+ <string name="fingerprint_error_user_canceled" msgid="7999639584615291494">"Մատնահետքով նույնականացման գործողությունը չեղարկվել է օգտատիրոջ կողմից:"</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Չափից շատ փորձ եք կատարել: Փորձեք նորից քիչ հետո:"</string>
<string name="fingerprint_error_lockout_permanent" msgid="5033251797919508137">"Չափից շատ փորձ եք կատարել: Մատնահետքերի սկաներն անջատվել է:"</string>
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Փորձեք նորից:"</string>
+ <string name="fingerprint_error_no_fingerprints" msgid="7654382120628334248">"Գրանցված մատնահետք չկա:"</string>
+ <string name="fingerprint_error_hw_not_present" msgid="5729436878065119329">"Սարքը չունի մատնահետքի սկաներ"</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Մատնահետք <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -1000,12 +999,9 @@
<string name="browse" msgid="1245903488306147205">"Բացել"</string>
<string name="sms" msgid="4560537514610063430">"SMS գրել"</string>
<string name="add_contact" msgid="7867066569670597203">"Ավելացնել"</string>
- <!-- no translation found for view_calendar (979609872939597838) -->
- <skip />
- <!-- no translation found for add_calendar_event (1953664627192056206) -->
- <skip />
- <!-- no translation found for view_flight (7691640491425680214) -->
- <skip />
+ <string name="view_calendar" msgid="979609872939597838">"Դիտել"</string>
+ <string name="add_calendar_event" msgid="1953664627192056206">"Ժամանակացույց"</string>
+ <string name="view_flight" msgid="7691640491425680214">"Հետագծել"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Հիշողությունը սպառվում է"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Որոշ գործառույթներ կարող են չաշխատել"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Համակարգի համար բավարար հիշողություն չկա: Համոզվեք, որ ունեք 250ՄԲ ազատ տարածություն և վերագործարկեք:"</string>
@@ -1131,8 +1127,7 @@
<item quantity="other">Հասանելի են չպաշտպանված Wi-Fi ցանցեր</item>
</plurals>
<string name="wifi_available_title" msgid="3817100557900599505">"Միացեք բաց Wi‑Fi ցանցին"</string>
- <!-- no translation found for wifi_available_carrier_network_title (4527932626916527897) -->
- <skip />
+ <string name="wifi_available_carrier_network_title" msgid="4527932626916527897">"Միացեք օպերատորի Wi‑Fi ցանցին"</string>
<string name="wifi_available_title_connecting" msgid="1557292688310330032">"Միացում բաց Wi‑Fi ցանցին"</string>
<string name="wifi_available_title_connected" msgid="7542672851522241548">"Միացել է Wi‑Fi ցանցին"</string>
<string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Չհաջողվեց միանալ Wi‑Fi ցանցին"</string>
@@ -1216,13 +1211,15 @@
<string name="no_permissions" msgid="7283357728219338112">"Թույլտվություններ չեն պահանջվում"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"Սա կարող է գումար պահանջել"</string>
<string name="dlg_ok" msgid="7376953167039865701">"Հաստատել"</string>
- <string name="usb_charging_notification_title" msgid="6895185153353640787">"Սարքի լիցքավորում USB լարի միջոցով"</string>
- <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Հոսանքի մատակարարում կցված սարքերին USB լարի միջոցով"</string>
- <string name="usb_mtp_notification_title" msgid="8396264943589760855">"Ֆայլերի փոխանցման USB"</string>
- <string name="usb_ptp_notification_title" msgid="1347328437083192112">"Լուսանկարների փոխանցման USB"</string>
- <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI-ի USB"</string>
- <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Կապակցված է USB լրասարքի"</string>
+ <string name="usb_charging_notification_title" msgid="1595122345358177163">"Սարքի լիցքավորում USB-ի միջոցով"</string>
+ <string name="usb_supplying_notification_title" msgid="4631045789893086181">"Միացված սարքի լիցքավորում USB-ի միջոցով"</string>
+ <string name="usb_mtp_notification_title" msgid="4238227258391151029">"Ֆայլերի փոխանցումը USB-ի միջոցով միացավ"</string>
+ <string name="usb_ptp_notification_title" msgid="5425857879922006878">"PTP ռեժիմը USB-ի միջոցով միացավ"</string>
+ <string name="usb_tether_notification_title" msgid="3716143122035802501">"USB մոդեմի ռեժիմը միացավ"</string>
+ <string name="usb_midi_notification_title" msgid="5356040379749154805">"MIDI ռեժիմը USB-ի միջոցով միացավ"</string>
+ <string name="usb_accessory_notification_title" msgid="1899977434994900306">"USB լրասարքի ռեժիմը միացավ"</string>
<string name="usb_notification_message" msgid="3370903770828407960">"Հպեք՝ լրացուցիչ ընտրանքների համար:"</string>
+ <string name="usb_power_notification_message" msgid="4647527153291917218">"Միացված սարքի լիցքավորում: Հպեք՝ ավելի շատ ընտրանքների համար:"</string>
<string name="usb_unsupported_audio_accessory_title" msgid="3529881374464628084">"Հայտնաբերված է անալոգային աուդիո լրասարք"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="6309553946441565215">"Միացված սարքը համատեղելի չէ այս հեռախոսի հետ: Հպեք` ավելին իմանալու համար:"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB վրիպազերծումը միացված է"</string>
@@ -1458,7 +1455,7 @@
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Գրասալիկ"</string>
<string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Հեռուստացույց"</string>
<string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Հեռախոս"</string>
- <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Համակցված բարձրախոսներ"</string>
+ <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Դոկ-կայանի բարձրախոսներ"</string>
<string name="default_audio_route_name_hdmi" msgid="1486254205617081251">"HDMI"</string>
<string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Ականջակալներ"</string>
<string name="default_audio_route_name_usb" msgid="1234984851352637769">"USB"</string>
@@ -1661,9 +1658,6 @@
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Աշխատանքային <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2-րդ աշխատանք <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3-րդ աշխատանք <xliff:g id="LABEL">%1$s</xliff:g>"</string>
- <string name="lock_to_app_toast" msgid="6820571533009838261">"Այս էկրանն ապամրացնելու համար հպեք և պահեք Հետ և Համատեսք կոճակները"</string>
- <string name="lock_to_app_start" msgid="6643342070839862795">"Էկրանն ամրացված է"</string>
- <string name="lock_to_app_exit" msgid="8598219838213787430">"Էկրանն ապամրացված է"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Ապաամրացնելուց առաջ հարցնել PIN-կոդը"</string>
<string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Ապաամրացնելուց առաջ հարցնել ապակողպող նախշը"</string>
<string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Ապաամրացնելուց առաջ հարցնել գաղտնաբառը"</string>
@@ -1757,15 +1751,11 @@
<string name="language_picker_section_all" msgid="3097279199511617537">"Բոլոր լեզուները"</string>
<string name="region_picker_section_all" msgid="8966316787153001779">"Բոլոր տարածաշրջանները"</string>
<string name="locale_search_menu" msgid="2560710726687249178">"Որոնում"</string>
- <!-- no translation found for work_mode_off_title (1118691887588435530) -->
- <skip />
- <!-- no translation found for work_mode_off_message (5130856710614337649) -->
- <skip />
+ <string name="work_mode_off_title" msgid="1118691887588435530">"Միացնե՞լ աշխատանքային պրոֆիլը"</string>
+ <string name="work_mode_off_message" msgid="5130856710614337649">"Ձեր աշխատանքային հավելվածները, ծանուցումները, տվյալները և աշխատանքային պրոֆիլի մյուս գործառույթները կմիանան"</string>
<string name="work_mode_turn_on" msgid="2062544985670564875">"Միացնել"</string>
- <!-- no translation found for deprecated_target_sdk_message (1449696506742572767) -->
- <skip />
- <!-- no translation found for deprecated_target_sdk_app_store (5032340500368495077) -->
- <skip />
+ <string name="deprecated_target_sdk_message" msgid="1449696506742572767">"Այս հավելվածը ստեղծվել է Android-ի ավելի հին տարբերակի համար և կարող է պատշաճ չաշխատել: Ստուգեք թարմացումների առկայությունը կամ դիմեք մշակողին:"</string>
+ <string name="deprecated_target_sdk_app_store" msgid="5032340500368495077">"Ստուգել նոր տարբերակի առկայությունը"</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"Դուք ունեք նոր հաղորդագրություններ"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"Դիտելու համար բացել SMS հավելվածը"</string>
<string name="user_encrypted_title" msgid="9054897468831672082">"Որոշ գործառույթներ կարող են սահմանափակված լինել"</string>
@@ -1832,17 +1822,14 @@
<string name="mmcc_illegal_me" msgid="1950705155760872972">"Այս հեռախոսով չեք կարող զանգել"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Հայտնվող պատուհան"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
- <string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Այս դյուրանցման համար անհրաժեշտ է հավելվածի վերջին տարբերակը"</string>
+ <string name="shortcut_restored_on_lower_version" msgid="4860853725206702336">"Սա հավելվածի ավելի հին տարբերակն է կամ համատեղելի չէ այս դյուրանցման հետ"</string>
<string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Չհաջողվեց վերականգնել դյուրանցումը, քանի որ հավելվածում չի աջակցվում պահուստավորման և վերականգնման գործառույթը"</string>
<string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Չհաջողվեց վերականգնել դյուրանցումը, քանի որ հավելվածների ստորագրությունները տարբեր են"</string>
<string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Չհաջողվեց վերականգնել դյուրանցումը"</string>
<string name="shortcut_disabled_reason_unknown" msgid="5276016910284687075">"Դյուրանցումն անջատված է"</string>
- <!-- no translation found for harmful_app_warning_uninstall (4837672735619532931) -->
- <skip />
- <!-- no translation found for harmful_app_warning_open_anyway (596432803680914321) -->
- <skip />
- <!-- no translation found for harmful_app_warning_title (8982527462829423432) -->
- <skip />
+ <string name="harmful_app_warning_uninstall" msgid="4837672735619532931">"ՀԵՌԱՑՆԵԼ"</string>
+ <string name="harmful_app_warning_open_anyway" msgid="596432803680914321">"ԲԱՑԵԼ"</string>
+ <string name="harmful_app_warning_title" msgid="8982527462829423432">"Հայտնաբերվել է վնասաբեր հավելված"</string>
<string name="slices_permission_request" msgid="8484943441501672932">"<xliff:g id="APP_0">%1$s</xliff:g> հավելվածն ուզում է ցուցադրել հատվածներ <xliff:g id="APP_2">%2$s</xliff:g> հավելվածից"</string>
<string name="screenshot_edit" msgid="7867478911006447565">"Փոփոխել"</string>
</resources>
diff --git a/core/res/res/values-mcc302-mnc220/config.xml b/core/res/res/values-mcc302-mnc220/config.xml
index 9a3d736..8774334 100644
--- a/core/res/res/values-mcc302-mnc220/config.xml
+++ b/core/res/res/values-mcc302-mnc220/config.xml
@@ -36,7 +36,7 @@
<!-- Values for GPS configuration (Telus) -->
<string-array translatable="false" name="config_gpsParameters">
- <item>SUPL_HOST=supl.telusmobility.com</item>
+ <item>SUPL_HOST=supl.google.com</item>
<item>SUPL_PORT=7275</item>
<item>SUPL_VER=0x20000</item>
<item>SUPL_MODE=1</item>
diff --git a/core/res/res/values-mcc302-mnc221/config.xml b/core/res/res/values-mcc302-mnc221/config.xml
index 007fd04..05896b1 100644
--- a/core/res/res/values-mcc302-mnc221/config.xml
+++ b/core/res/res/values-mcc302-mnc221/config.xml
@@ -34,7 +34,7 @@
<!-- Values for GPS configuration (Telus) -->
<string-array translatable="false" name="config_gpsParameters">
- <item>SUPL_HOST=supl.telusmobility.com</item>
+ <item>SUPL_HOST=supl.google.com</item>
<item>SUPL_PORT=7275</item>
<item>SUPL_VER=0x20000</item>
<item>SUPL_MODE=1</item>
diff --git a/core/res/res/values-television/dimens.xml b/core/res/res/values-television/dimens.xml
index 4c25225..aa56251 100644
--- a/core/res/res/values-television/dimens.xml
+++ b/core/res/res/values-television/dimens.xml
@@ -20,4 +20,8 @@
<item type="dimen" format="float" name="ambient_shadow_alpha">0.15</item>
<item type="dimen" format="float" name="spot_shadow_alpha">0.3</item>
+ <!-- Max width/height of the autofill data set picker as a fraction of the screen width/height -->
+ <dimen name="autofill_dataset_picker_max_width">60%</dimen>
+ <dimen name="autofill_dataset_picker_max_height">70%</dimen>
+
</resources>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index c9076ca..5ac81d5 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -355,6 +355,8 @@
<string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"Ilovaga o‘zining komponentlarini xotirada doimiy saqlashga ruxsat beradi. Bu mavjud xotirani cheklashi va planshetni sekin ishlashiga sabab bo‘lishi mumkin."</string>
<string name="permdesc_persistentActivity" product="tv" msgid="5086862529499103587">"Ilovaga o‘zining muayyan qismlarining xotiraning turg‘un qismiga aylantirish huquqini beradi. Bunda, boshqa ilovalar uchun xotiradan ajratilgan joy cheklanib, televizorning ishlashi sekinlashishi mumkin."</string>
<string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"Ilovaga o‘zining komponentlarini xotirada doimiy saqlashga ruxsat beradi. Bu mavjud xotirani cheklashi va telefonni sekin ishlashiga sabab bo‘lishi mumkin."</string>
+ <string name="permlab_foregroundService" msgid="3310786367649133115">"faol xizmatlarni ishga tushirish"</string>
+ <string name="permdesc_foregroundService" msgid="6471634326171344622">"Ilovaga faol xizmatlardan foydalanishga ruxsat beradi."</string>
<string name="permlab_getPackageSize" msgid="7472921768357981986">"ilovalar egallagan xotira joyini hisoblash"</string>
<string name="permdesc_getPackageSize" msgid="3921068154420738296">"Ilova o‘zining kodi, ma’lumotlari va kesh o‘lchami to‘g‘risidagi ma’lumotlarni olishi mumkin"</string>
<string name="permlab_writeSettings" msgid="2226195290955224730">"tizim sozlamalarini o‘zgartirish"</string>
@@ -497,10 +499,8 @@
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Urinishlar soni ko‘payib ketdi. Keyinroq qayta urinib ko‘ring."</string>
<string name="fingerprint_error_lockout_permanent" msgid="5033251797919508137">"Urinishlar soni ko‘payib ketdi. Barmoq izi skaneri bloklandi."</string>
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Qayta urinib ko‘ring."</string>
- <!-- no translation found for fingerprint_error_no_fingerprints (7654382120628334248) -->
- <skip />
- <!-- no translation found for fingerprint_error_hw_not_present (5729436878065119329) -->
- <skip />
+ <string name="fingerprint_error_no_fingerprints" msgid="7654382120628334248">"Hech qanday barmoq izi qayd qilinmagan."</string>
+ <string name="fingerprint_error_hw_not_present" msgid="5729436878065119329">"Bu qurilmada barmoq izi skaneri yo‘q"</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Barmoq izi <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -1212,23 +1212,15 @@
<string name="no_permissions" msgid="7283357728219338112">"Hech qanday ruxsat talab qilinmaydi"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"buning uchun sizdan haq olinishi mumkin"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <!-- no translation found for usb_charging_notification_title (1595122345358177163) -->
- <skip />
- <!-- no translation found for usb_supplying_notification_title (4631045789893086181) -->
- <skip />
- <!-- no translation found for usb_mtp_notification_title (4238227258391151029) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (5425857879922006878) -->
- <skip />
- <!-- no translation found for usb_tether_notification_title (3716143122035802501) -->
- <skip />
- <!-- no translation found for usb_midi_notification_title (5356040379749154805) -->
- <skip />
- <!-- no translation found for usb_accessory_notification_title (1899977434994900306) -->
- <skip />
+ <string name="usb_charging_notification_title" msgid="1595122345358177163">"Bu qurilma USB orqali quvvatlanmoqda"</string>
+ <string name="usb_supplying_notification_title" msgid="4631045789893086181">"USB orqali ulangan qurilma quvvatlanmoqda"</string>
+ <string name="usb_mtp_notification_title" msgid="4238227258391151029">"USB orqali fayl uzatish yoqildi"</string>
+ <string name="usb_ptp_notification_title" msgid="5425857879922006878">"USB orqali PTP rejimi yoqildi"</string>
+ <string name="usb_tether_notification_title" msgid="3716143122035802501">"USB modem rejimi yoqildi"</string>
+ <string name="usb_midi_notification_title" msgid="5356040379749154805">"USB orqali MIDI rejimi yoqildi"</string>
+ <string name="usb_accessory_notification_title" msgid="1899977434994900306">"USB qurilma ulandi"</string>
<string name="usb_notification_message" msgid="3370903770828407960">"Boshqa parametrlarini ko‘rish uchun bosing."</string>
- <!-- no translation found for usb_power_notification_message (4647527153291917218) -->
- <skip />
+ <string name="usb_power_notification_message" msgid="4647527153291917218">"Ulangan qurilma quvvatlanmoqda. Boshqa parametrlar uchun bosing."</string>
<string name="usb_unsupported_audio_accessory_title" msgid="3529881374464628084">"Analogli audio uskuna aniqlandi"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="6309553946441565215">"Biriktirilgan qurilma mazkur telefon bilan mos emas. Batafsil axborot olish uchun bu yerga bosing."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB orqali nosozliklarni tuzatish"</string>
@@ -1831,8 +1823,7 @@
<string name="mmcc_illegal_me" msgid="1950705155760872972">"Ovoz uchun telefon taqiqlangan"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Qalqib chiquvchi oyna"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
- <!-- no translation found for shortcut_restored_on_lower_version (4860853725206702336) -->
- <skip />
+ <string name="shortcut_restored_on_lower_version" msgid="4860853725206702336">"Ilova versiyasi eski yoki bu yorliq bilan mos emas"</string>
<string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Ilovada zaxiralash va tiklash ishlamagani uchun yorliq tiklanmadi"</string>
<string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Ilova imzosi mos kelmagani uchun yorliq tiklanmadi"</string>
<string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Yorliq tiklanmadi"</string>
diff --git a/core/res/res/values-watch/colors_device_defaults.xml b/core/res/res/values-watch/colors_device_defaults.xml
index 654e92c..6ffd6e6 100644
--- a/core/res/res/values-watch/colors_device_defaults.xml
+++ b/core/res/res/values-watch/colors_device_defaults.xml
@@ -14,48 +14,88 @@
limitations under the License.
-->
-<!-- Colors specific to DeviceDefault themes. These are mostly pass-throughs to enable
- overlaying new theme colors. -->
+<!-- Colors specific to Theme.DeviceDefault on watches, as specified via themes_device_default.xml
+ Note: These colors specifically proide a darker, high-contrast UI that is suitable for
+ wearables with respect to 'glanceability'. OEM customization is supported within this set. -->
<resources>
-
- <!--
- primary_device_default_dark
- > from values/colors_material/primary_material_dark
- > from values/colors_material/material_grey_900
- = #ff212121
- ! replaced with custom color #33ffffff
- -->
- <color name="primary_device_default_dark">#33ffffff</color>
- <!--
- primary_dark_device_default_dark
- > from values/colors_material/primary_dark_material_dark
- = @color/black
- -->
- <color name="primary_dark_device_default_dark">@color/black</color>
<!--
accent_device_default_dark
> from values/colors_material/accent_material_dark
> from values/colors_material/material_deep_teal_200
= #ff80cbc4
! replaced with custom color #5E97F6
+ ! OEMS can customize as per specification
-->
<color name="accent_device_default_dark">#5E97F6</color>
+
+ <!--
+ foreground_device_default_dark
+ - introduced to avoid coupling to foreground_material_dark
+ - colorForeground typically falls through Theme.DeviceDefault to Theme.Material
+ ! fixed as white for optimal glanceability/contrast
+ ! OEMs should not customize
+ -->
+ <color name="foreground_device_default_dark">@color/white</color>
+
<!--
background_device_default_dark
> from values/colors_material/background_material_dark
> from values/colors_material/material_grey_850
= #ff303030
- ! replaced with custom color #232E33
+ ! replaced with custom color #000000
+ ! OEMs can customized as per specification
+ (derived from accent color, constrained by brightness)
-->
- <color name="background_device_default_dark">#232E33</color>
+ <color name="background_device_default_dark">#000000</color>
+
<!--
background_floating_device_default_dark
> from values/colors_material/background_floating_material_dark
> from values/colors_material/material_grey_800
= #ff424242
- ! replaced with custom color #3E5059
+ ! replaced with custom color #1D2E4D
+ (derived from accent color, constrained by brightness)
-->
- <color name="background_floating_device_default_dark">#3E5059</color>
+ <color name="background_floating_device_default_dark">#1D2E4D</color>
+
+ <!--
+ primary_device_default_dark
+ > from values/colors_material/primary_material_dark
+ > from values/colors_material/material_grey_900
+ = #ff212121
+ ! replaced with custom color #808080
+ ! OEMs can customize as per specification
+ (derived from background color + foreground @ 50% opacity)
+ -->
+ <color name="primary_device_default_dark">#808080</color>
+
+ <!--
+ primary_dark_device_default_dark
+ > from values/colors_material/primary_dark_material_dark
+ = @color/black
+ ! replaced with custom color #333333
+ ! OEMS can customize as per specification
+ (derived from background color + foreground @ 20% opacity)
+ -->
+ <color name="primary_dark_device_default_dark">#333333</color>
+
+ <!--
+ button_normal_device_default_dark
+ - uses ?attr/disabledAlpha and ?attr/colorPrimaryDark to draw state list
+ (used as colorButtonNormal attribute in theme)
+ - see color-watch/btn_watch_default_dark.xml
+ -->
+ <color name="button_normal_device_default_dark">@color/btn_watch_default_dark</color>
+
+ <!--
+ error_color_device_default_dark
+ - introduced to avoid coupling to error_color_mtterial (also #F4511E)
+ - colorError typically falls through Theme.DeviceDefault to Theme.Material
+ ! OEMs can customize as per specification
+ -->
+ <color name="error_color_device_default_dark">#F4511E</color>
+
+ <!-- no customization required/suggested below this point -->
<!--
background_cache_hint_selector_device_default
@@ -65,38 +105,12 @@
- no color customization required here
-->
- <!--
- button_normal_device_default_dark
- - uses ?attr/disabledAlpha and button_material_dark to draw
- - cloned to watch_btn_default.xml drawable
- (btn_default_material_dark & button_material_dark - see
- values-watch/colors_material.xml)
- -->
- <color name="button_normal_device_default_dark">@color/btn_default_material_dark</color>
-
- <!-- Use the same value as for accent_device_default_dark but start with #99,
- i.e. 60% opacity -->
- <color name="accent_device_default_dark_60_percent_opacity">#995E97f6</color>
-
- <!--
- foreground_device_default_dark
- - introduced to avoid coupling to foreground_material_dark
- - colorForeground typically falls through Theme.DeviceDefault to Theme.Material
- -->
- <color name="foreground_device_default_dark">@color/white</color>
-
- <!--
- error_color_device_default_dark
- - introduced to avoid coupling to error_color_material (also #F4511E)
- - colorError typically falls through Theme.DeviceDefault to Theme.Material
- -->
- <color name="error_color_device_default_dark">#F4511E</color>
-
<!-- deprecated for Wear
these overrides exist only for compatibility with existing
WTS theme test heuristics, based on the previous modifications
to the material theme, they should not be used for customization
as they are not exposed via publicly accessible attributes -->
+ <color name="accent_device_default_dark_60_percent_opacity">#995E97f6</color>
<color name="accent_device_default_700">#5385DB</color>
<color name="accent_device_default_light">#75A4F5</color>
<color name="accent_device_default_50">#93B7F5</color>
diff --git a/core/res/res/values-watch/colors_material.xml b/core/res/res/values-watch/colors_material.xml
deleted file mode 100644
index b19820c..0000000
--- a/core/res/res/values-watch/colors_material.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 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.
--->
-<resources>
-
- <!-- referenced in colors/watch_btn_default.xml selector -->
- <color name="button_material_dark">#ff919699</color>
-
-</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 005d07d..d26567e 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -7918,6 +7918,10 @@
android.content.pm.PackageInfo#getLongVersionCode()} for the target package.
-->
<attr name="maxLongVersionCode" format="string" />
+ <!-- The resource id of view that contains the URL bar of the HTML page being loaded.
+ Typically used when compatibility mode is used in a browser.
+ -->
+ <attr name="urlBarResourceId" format="string" />
</declare-styleable>
<!-- =============================== -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index d2194ba..0911298 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -999,7 +999,7 @@
<integer name="config_shortPressOnSleepBehavior">0</integer>
<!-- Time to wait while a button is pressed before triggering a very long press. -->
- <integer name="config_veryLongPressTimeout">6000</integer>
+ <integer name="config_veryLongPressTimeout">3500</integer>
<!-- Package name for default keyguard appwidget [DO NOT TRANSLATE] -->
<string name="widget_default_package_name" translatable="false"></string>
@@ -2328,6 +2328,10 @@
<string name="config_customVpnAlwaysOnDisconnectedDialogComponent" translatable="false"
>com.android.vpndialogs/com.android.vpndialogs.AlwaysOnDisconnectedDialog</string>
+ <!-- Name of the dialog that is used to install the carrier app when the SIM is inserted -->
+ <string name="config_carrierAppInstallDialogComponent" translatable="false"
+ >com.android.simappdialog/com.android.simappdialog.InstallCarrierAppActivity</string>
+
<!-- Apps that are authorized to access shared accounts, overridden by product overlays -->
<string name="config_appsAuthorizedForSharedAccounts" translatable="false">;com.android.settings;</string>
@@ -2913,8 +2917,8 @@
<item name="config_pictureInPictureAspectRatioLimitForMinSize" format="float" type="dimen">1.777778</item>
<!-- The default gravity for the picture-in-picture window.
- Currently, this maps to Gravity.BOTTOM | Gravity.RIGHT -->
- <integer name="config_defaultPictureInPictureGravity">0x55</integer>
+ Currently, this maps to Gravity.TOP | Gravity.RIGHT -->
+ <integer name="config_defaultPictureInPictureGravity">0x35</integer>
<!-- The minimum aspect ratio (width/height) that is supported for picture-in-picture. Any
ratio smaller than this is considered too tall and thin to be usable. Currently, this
@@ -3311,4 +3315,10 @@
<!-- IWLAN network service package name to bind to by default. If none is specified in an overlay, an
empty string is passed in -->
<string name="config_wlan_network_service_package" translatable="false"></string>
+
+ <!-- Wear devices: Controls the radios affected by Activity Mode. -->
+ <string-array name="config_wearActivityModeRadios">
+ <item>"wifi"</item>
+ </string-array>
+
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 0411c6e..cfaab6a 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -626,7 +626,8 @@
<dimen name="messaging_avatar_size">@dimen/notification_right_icon_size</dimen>
<!-- Max width/height of the autofill data set picker as a fraction of the screen width/height -->
- <dimen name="autofill_dataset_picker_max_size">90%</dimen>
+ <dimen name="autofill_dataset_picker_max_width">90%</dimen>
+ <dimen name="autofill_dataset_picker_max_height">90%</dimen>
<!-- Max height of the the autofill save custom subtitle as a fraction of the screen width/height -->
<dimen name="autofill_save_custom_subtitle_max_height">20%</dimen>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 93f22f25..82fefef 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2869,6 +2869,7 @@
<public name="outlineSpotShadowColor" />
<public name="outlineAmbientShadowColor" />
<public name="maxLongVersionCode" />
+ <public name="urlBarResourceId" />
</public-group>
<public-group type="style" first-id="0x010302e0">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 2b7b056..837113d 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -182,6 +182,8 @@
<string name="notification_channel_voice_mail">Voicemail messages</string>
<!-- Telephony notification channel name for a channel containing wifi calling status notifications. -->
<string name="notification_channel_wfc">Wi-Fi calling</string>
+ <!-- Telephony notification channel name for a channel containing SIM notifications -->
+ <string name="notification_channel_sim">SIM status</string>
<!-- Displayed to tell the user that peer changed TTY mode -->
<string name="peerTtyModeFull">Peer requested TTY Mode FULL</string>
@@ -547,7 +549,7 @@
<string name="global_action_voice_assist">Voice Assist</string>
<!-- label for item that locks the phone and enforces that it can't be unlocked without strong authentication. [CHAR LIMIT=15] -->
- <string name="global_action_lockdown">Enter lockdown</string>
+ <string name="global_action_lockdown">Lockdown</string>
<!-- Text to use when the number in a notification info is too large
(greater than status_bar_notification_info_maxnum, defined in
@@ -916,11 +918,6 @@
<string name="permdesc_persistentActivity" product="default">Allows the app to make parts of itself persistent in memory. This can limit memory available to other apps slowing down the phone.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permlab_foregroundService">run foreground service</string>
- <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permdesc_foregroundService">Allows the app to make use of foreground services.</string>
-
- <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_getPackageSize">measure app storage space</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_getPackageSize">Allows the app to retrieve its code, data, and cache sizes</string>
@@ -2174,6 +2171,9 @@
<!-- Text to show in the auto complete drop down list on a text view when the WebView can auto fill the entire form but the user has not configured an AutoFill profile [CHAR-LIMIT=19] -->
<string name="setup_autofill">Set up Autofill</string>
+ <!-- Title of fullscreen autofill window [CHAR-LIMIT=80] -->
+ <string name="autofill_window_title">Autofill</string>
+
<!-- String used to separate FirstName and LastName when writing out a local name
e.g. John<separator>Smith [CHAR-LIMIT=NONE]-->
<string name="autofill_address_name_separator">\u0020</string>
@@ -3199,10 +3199,12 @@
<!-- See SIM_ADDED_DIALOG. This is the button of that dialog. -->
<string name="sim_restart_button">Restart</string>
<!-- See Carrier_App_Dialog. This is the message of that dialog. -->
- <string name="carrier_app_dialog_message">To get your new SIM working properly, you\'ll need to install and open an app from your carrier.</string>
- <!-- See Carrier_App_Dialog. This is the button of that dialog. -->
- <string name="carrier_app_dialog_button">GET THE APP</string>
- <string name="carrier_app_dialog_not_now">NOT NOW</string>
+ <string name="install_carrier_app_notification_title">Activate mobile service</string>
+ <string name="install_carrier_app_notification_text">
+ Download the carrier app to activate your new SIM
+ </string>
+ <!-- See Carrier_App_Notification. This is the button of that dialog. -->
+ <string name="install_carrier_app_notification_button">Download app</string>
<!-- See carrier_app_notification. This is the headline. -->
<string name="carrier_app_notification_title">New SIM inserted</string>
<string name="carrier_app_notification_text">Tap to set it up</string>
@@ -4859,4 +4861,11 @@
<!-- Notification action for editing a screenshot (drawing on it, cropping it, etc) -->
<string name="screenshot_edit">Edit</string>
+
+ <!-- Title for the notification channel notifying user of settings system changes (i.e. Do Not Disturb has changed). [CHAR LIMIT=NONE] -->
+ <string name="notification_channel_system_changes">System changes</string>
+ <!-- Title of notification indicating do not disturb settings have changed when upgrading to P -->
+ <string name="zen_upgrade_notification_title">Do Not Disturb has changed</string>
+ <!-- Content of notification indicating users can tap on the notification to go to dnd behavior settings -->
+ <string name="zen_upgrade_notification_content">Tap to check your behavior settings for interruptions</string>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index ca698ef..9995642 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -574,6 +574,7 @@
<java-symbol type="string" name="notification_channel_sms" />
<java-symbol type="string" name="notification_channel_voice_mail" />
<java-symbol type="string" name="notification_channel_wfc" />
+ <java-symbol type="string" name="notification_channel_sim" />
<java-symbol type="string" name="SetupCallDefault" />
<java-symbol type="string" name="accept" />
<java-symbol type="string" name="activity_chooser_view_see_all" />
@@ -1383,6 +1384,7 @@
<java-symbol type="drawable" name="ic_sim_card_multi_24px_clr" />
<java-symbol type="drawable" name="ic_sim_card_multi_48px_clr" />
+ <java-symbol type="drawable" name="ic_signal_cellular_alt_24px" />
<java-symbol type="drawable" name="stat_notify_mmcc_indication_icn" />
<java-symbol type="drawable" name="autofilled_highlight"/>
@@ -1716,6 +1718,7 @@
<java-symbol type="string" name="bugreport_status" />
<java-symbol type="string" name="bugreport_title" />
<java-symbol type="string" name="faceunlock_multiple_failures" />
+ <java-symbol type="string" name="global_actions" />
<java-symbol type="string" name="global_action_power_off" />
<java-symbol type="string" name="global_action_restart" />
<java-symbol type="string" name="global_actions_airplane_mode_off_status" />
@@ -2071,6 +2074,7 @@
<java-symbol type="string" name="config_customAdbPublicKeyConfirmationSecondaryUserComponent" />
<java-symbol type="string" name="config_customVpnConfirmDialogComponent" />
<java-symbol type="string" name="config_customVpnAlwaysOnDisconnectedDialogComponent" />
+ <java-symbol type="string" name="config_carrierAppInstallDialogComponent" />
<java-symbol type="string" name="config_defaultNetworkScorerPackageName" />
<java-symbol type="string" name="config_persistentDataPackageName" />
@@ -2770,9 +2774,9 @@
<java-symbol type="array" name="resolver_target_actions_pin" />
<java-symbol type="array" name="resolver_target_actions_unpin" />
- <java-symbol type="string" name="carrier_app_dialog_message" />
- <java-symbol type="string" name="carrier_app_dialog_button" />
- <java-symbol type="string" name="carrier_app_dialog_not_now" />
+ <java-symbol type="string" name="install_carrier_app_notification_title" />
+ <java-symbol type="string" name="install_carrier_app_notification_text" />
+ <java-symbol type="string" name="install_carrier_app_notification_button" />
<java-symbol type="string" name="carrier_app_notification_title" />
<java-symbol type="string" name="carrier_app_notification_text" />
<java-symbol type="string" name="negative_duration" />
@@ -2986,6 +2990,8 @@
<!-- com.android.server.autofill -->
<java-symbol type="layout" name="autofill_save"/>
<java-symbol type="layout" name="autofill_dataset_picker"/>
+ <java-symbol type="layout" name="autofill_dataset_picker_fullscreen"/>
+ <java-symbol type="id" name="autofill_dataset_container"/>
<java-symbol type="id" name="autofill_dataset_list"/>
<java-symbol type="id" name="autofill_dataset_picker"/>
<java-symbol type="id" name="autofill" />
@@ -3014,7 +3020,8 @@
<java-symbol type="drawable" name="autofill_dataset_picker_background" />
<java-symbol type="style" name="AutofillDatasetPicker" />
<java-symbol type="style" name="AutofillSaveAnimation" />
- <java-symbol type="dimen" name="autofill_dataset_picker_max_size"/>
+ <java-symbol type="dimen" name="autofill_dataset_picker_max_width"/>
+ <java-symbol type="dimen" name="autofill_dataset_picker_max_height"/>
<java-symbol type="dimen" name="autofill_save_custom_subtitle_max_height"/>
<java-symbol type="dimen" name="autofill_save_icon_max_size"/>
@@ -3102,6 +3109,7 @@
<java-symbol type="string" name="notification_channel_retail_mode" />
<java-symbol type="string" name="notification_channel_usb" />
<java-symbol type="string" name="notification_channel_heavy_weight_app" />
+ <java-symbol type="string" name="notification_channel_system_changes" />
<java-symbol type="string" name="config_defaultAutofillService" />
<java-symbol type="string" name="config_defaultTextClassifierService" />
@@ -3254,4 +3262,11 @@
<java-symbol type="bool" name="config_keepRestrictedProfilesInBackground" />
<java-symbol type="array" name="config_ringtoneEffectUris" />
+
+ <!-- For Wear devices -->
+ <java-symbol type="array" name="config_wearActivityModeRadios" />
+
+ <java-symbol type="string" name="zen_upgrade_notification_title" />
+ <java-symbol type="string" name="zen_upgrade_notification_content" />
+
</resources>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 9c3d8eb..f6a11bd 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -451,8 +451,8 @@
<item name="tooltipBackgroundColor">@color/tooltip_background_light</item>
<!-- Autofill: max width/height of the dataset picker as a fraction of screen size -->
- <item name="autofillDatasetPickerMaxWidth">@dimen/autofill_dataset_picker_max_size</item>
- <item name="autofillDatasetPickerMaxHeight">@dimen/autofill_dataset_picker_max_size</item>
+ <item name="autofillDatasetPickerMaxWidth">@dimen/autofill_dataset_picker_max_width</item>
+ <item name="autofillDatasetPickerMaxHeight">@dimen/autofill_dataset_picker_max_height</item>
<!-- Autofill: max height of custom save subtitle as a fraction of screen size -->
<item name="autofillSaveCustomSubtitleMaxHeight">@dimen/autofill_save_custom_subtitle_max_height</item>
diff --git a/core/res/res/xml/default_zen_mode_config.xml b/core/res/res/xml/default_zen_mode_config.xml
index a446088..7849a2a 100644
--- a/core/res/res/xml/default_zen_mode_config.xml
+++ b/core/res/res/xml/default_zen_mode_config.xml
@@ -18,7 +18,7 @@
-->
<!-- Default configuration for zen mode. See android.service.notification.ZenModeConfig. -->
-<zen version="2">
+<zen version="3">
<allow alarms="true" media_system_other="true" calls="false" messages="false" reminders="false"
events="false" />
</zen>
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 53c22f6..7d5c60a 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -51,7 +51,6 @@
<uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" />
<uses-permission android:name="android.permission.DELETE_CACHE_FILES" />
<uses-permission android:name="android.permission.DOWNLOAD_CACHE_NON_PURGEABLE" />
- <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.GET_PACKAGE_SIZE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.INJECT_EVENTS" />
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 5bb9abe..67c9754 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -354,6 +354,7 @@
Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS,
Settings.Global.SHOW_RESTART_IN_CRASH_DIALOG,
Settings.Global.SHOW_TEMPERATURE_WARNING,
+ Settings.Global.SHOW_ZEN_UPGRADE_NOTIFICATION,
Settings.Global.SMART_SELECTION_UPDATE_CONTENT_URL,
Settings.Global.SMART_SELECTION_UPDATE_METADATA_URL,
Settings.Global.SMS_OUTGOING_CHECK_INTERVAL_MS,
@@ -366,6 +367,7 @@
Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS,
Settings.Global.STORAGE_BENCHMARK_INTERVAL,
Settings.Global.STORAGE_SETTINGS_CLOBBER_THRESHOLD,
+ Settings.Global.SYNC_MANAGER_CONSTANTS,
Settings.Global.SYNC_MAX_RETRY_DELAY_IN_SECONDS,
Settings.Global.SYS_FREE_STORAGE_LOG_INTERVAL,
Settings.Global.SYS_STORAGE_CACHE_MAX_BYTES,
@@ -400,6 +402,8 @@
Settings.Global.GPU_DEBUG_APP,
Settings.Global.GPU_DEBUG_LAYERS,
Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING,
+ Settings.Global.INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT,
+ Settings.Global.INSTALL_CARRIER_APP_NOTIFICATION_SLEEP_MILLIS,
Settings.Global.NETWORK_ACCESS_TIMEOUT_MS,
Settings.Global.WARNING_TEMPERATURE,
Settings.Global.WEBVIEW_DATA_REDUCTION_PROXY_KEY,
@@ -450,7 +454,8 @@
Settings.Global.ZEN_MODE_RINGER_LEVEL,
Settings.Global.ZRAM_ENABLED,
Settings.Global.OVERRIDE_SETTINGS_PROVIDER_RESTORE_ANY_VERSION,
- Settings.Global.CHAINED_BATTERY_ATTRIBUTION_ENABLED);
+ Settings.Global.CHAINED_BATTERY_ATTRIBUTION_ENABLED,
+ Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS);
private static final Set<String> BACKUP_BLACKLISTED_SECURE_SETTINGS =
newHashSet(
@@ -465,6 +470,7 @@
Settings.Secure.ASSIST_SCREENSHOT_ENABLED,
Settings.Secure.ASSIST_STRUCTURE_ENABLED,
Settings.Secure.AUTOFILL_FEATURE_FIELD_CLASSIFICATION,
+ Settings.Secure.AUTOFILL_USER_DATA_MAX_CATEGORY_COUNT,
Settings.Secure.AUTOFILL_USER_DATA_MAX_FIELD_CLASSIFICATION_IDS_SIZE,
Settings.Secure.AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE,
Settings.Secure.AUTOFILL_USER_DATA_MAX_VALUE_LENGTH,
@@ -492,6 +498,7 @@
Settings.Secure.DOZE_ALWAYS_ON,
Settings.Secure.DOZE_PULSE_ON_LONG_PRESS,
Settings.Secure.EMERGENCY_ASSISTANCE_APPLICATION,
+ Settings.Secure.ENABLED_INPUT_METHODS, // Intentionally removed in P
Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT,
Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
diff --git a/core/tests/coretests/src/android/service/euicc/EuiccProfileInfoTest.java b/core/tests/coretests/src/android/service/euicc/EuiccProfileInfoTest.java
index 1e3ddf3..e69d1e7 100644
--- a/core/tests/coretests/src/android/service/euicc/EuiccProfileInfoTest.java
+++ b/core/tests/coretests/src/android/service/euicc/EuiccProfileInfoTest.java
@@ -30,14 +30,15 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Arrays;
+
@SmallTest
@RunWith(AndroidJUnit4.class)
public class EuiccProfileInfoTest {
@Test
public void testWriteToParcel() {
EuiccProfileInfo p =
- new EuiccProfileInfo.Builder()
- .setIccid("21430000000000006587")
+ new EuiccProfileInfo.Builder("21430000000000006587")
.setNickname("profile nickname")
.setServiceProviderName("service provider")
.setProfileName("profile name")
@@ -50,9 +51,7 @@
"45"))
.setPolicyRules(EuiccProfileInfo.POLICY_RULE_DO_NOT_DELETE)
.setUiccAccessRule(
- new UiccAccessRule[] {
- new UiccAccessRule(new byte[] {}, "package", 12345L)
- })
+ Arrays.asList(new UiccAccessRule(new byte[] {}, "package", 12345L)))
.build();
Parcel parcel = Parcel.obtain();
@@ -68,8 +67,7 @@
@Test
public void testWriteToParcelNullCarrierId() {
EuiccProfileInfo p =
- new EuiccProfileInfo.Builder()
- .setIccid("21430000000000006587")
+ new EuiccProfileInfo.Builder("21430000000000006587")
.setNickname("profile nickname")
.setServiceProviderName("service provider")
.setProfileName("profile name")
@@ -77,9 +75,8 @@
.setState(EuiccProfileInfo.PROFILE_STATE_ENABLED)
.setPolicyRules(EuiccProfileInfo.POLICY_RULE_DO_NOT_DELETE)
.setUiccAccessRule(
- new UiccAccessRule[] {
- new UiccAccessRule(new byte[] {}, "package", 12345L)
- })
+ Arrays.asList(new UiccAccessRule(new byte[] {}, "package", 12345L))
+ )
.build();
Parcel parcel = Parcel.obtain();
@@ -95,8 +92,7 @@
@Test
public void testBuilderAndGetters() {
EuiccProfileInfo p =
- new EuiccProfileInfo.Builder()
- .setIccid("21430000000000006587")
+ new EuiccProfileInfo.Builder("21430000000000006587")
.setNickname("profile nickname")
.setProfileName("profile name")
.setServiceProviderName("service provider")
@@ -108,10 +104,7 @@
.setState(EuiccProfileInfo.PROFILE_STATE_ENABLED)
.setProfileClass(EuiccProfileInfo.PROFILE_CLASS_OPERATIONAL)
.setPolicyRules(EuiccProfileInfo.POLICY_RULE_DO_NOT_DELETE)
- .setUiccAccessRule(
- new UiccAccessRule[] {
- new UiccAccessRule(new byte[0], null, 0)
- })
+ .setUiccAccessRule(Arrays.asList(new UiccAccessRule(new byte[0], null, 0)))
.build();
assertEquals("21430000000000006587", p.getIccid());
@@ -130,14 +123,13 @@
assertFalse(p.hasPolicyRule(EuiccProfileInfo.POLICY_RULE_DO_NOT_DISABLE));
assertArrayEquals(
new UiccAccessRule[] {new UiccAccessRule(new byte[0], null, 0)},
- p.getUiccAccessRules());
+ p.getUiccAccessRules().toArray());
}
@Test
public void testBuilder_BasedOnAnotherProfile() {
EuiccProfileInfo p =
- new EuiccProfileInfo.Builder()
- .setIccid("21430000000000006587")
+ new EuiccProfileInfo.Builder("21430000000000006587")
.setNickname("profile nickname")
.setProfileName("profile name")
.setServiceProviderName("service provider")
@@ -150,9 +142,7 @@
.setProfileClass(EuiccProfileInfo.PROFILE_CLASS_OPERATIONAL)
.setPolicyRules(EuiccProfileInfo.POLICY_RULE_DO_NOT_DELETE)
.setUiccAccessRule(
- new UiccAccessRule[] {
- new UiccAccessRule(new byte[0], null, 0)
- })
+ Arrays.asList(new UiccAccessRule(new byte[] {}, "package", 12345L)))
.build();
EuiccProfileInfo copied = new EuiccProfileInfo.Builder(p).build();
@@ -164,8 +154,7 @@
@Test
public void testEqualsHashCode() {
EuiccProfileInfo p =
- new EuiccProfileInfo.Builder()
- .setIccid("21430000000000006587")
+ new EuiccProfileInfo.Builder("21430000000000006587")
.setNickname("profile nickname")
.setProfileName("profile name")
.setServiceProviderName("service provider")
@@ -177,10 +166,7 @@
.setState(EuiccProfileInfo.PROFILE_STATE_ENABLED)
.setProfileClass(EuiccProfileInfo.PROFILE_STATE_ENABLED)
.setPolicyRules(EuiccProfileInfo.POLICY_RULE_DO_NOT_DELETE)
- .setUiccAccessRule(
- new UiccAccessRule[] {
- new UiccAccessRule(new byte[0], null, 0)
- })
+ .setUiccAccessRule(Arrays.asList(new UiccAccessRule(new byte[0], null, 0)))
.build();
assertTrue(p.equals(p));
@@ -229,13 +215,13 @@
}
@Test(expected = IllegalStateException.class)
- public void testBuilderBuild_NoIccid() {
- new EuiccProfileInfo.Builder().build();
+ public void testBuilderBuild_IllegalIccid() {
+ new EuiccProfileInfo.Builder("abc").build();
}
@Test(expected = IllegalArgumentException.class)
public void testBuilderSetOperatorMccMnc_Illegal() {
- new EuiccProfileInfo.Builder()
+ new EuiccProfileInfo.Builder("21430000000000006587")
.setCarrierIdentifier(new CarrierIdentifier(new byte[] {1, 2, 3, 4}, null, null));
}
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 32053e3..cb049b7 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
@@ -114,7 +114,7 @@
when(mKernelUidCpuFreqTimeReader.readFreqs(mPowerProfile)).thenReturn(freqs);
// RUN
- mBatteryStatsImpl.updateCpuTimeLocked();
+ mBatteryStatsImpl.updateCpuTimeLocked(false, false);
// VERIFY
assertArrayEquals("Unexpected cpu freqs", freqs, mBatteryStatsImpl.getCpuFreqs());
@@ -134,7 +134,7 @@
mBatteryStatsImpl.setOnBatteryInternal(true);
// RUN
- mBatteryStatsImpl.updateCpuTimeLocked();
+ mBatteryStatsImpl.updateCpuTimeLocked(true, false);
// VERIFY
verify(mUserInfoProvider).refreshUserIds();
@@ -213,7 +213,7 @@
}
// RUN
- mBatteryStatsImpl.updateClusterSpeedTimes(updatedUids);
+ mBatteryStatsImpl.updateClusterSpeedTimes(updatedUids, true);
// VERIFY
int totalClustersTimeMs = 0;
@@ -261,7 +261,7 @@
// RUN
final SparseLongArray updatedUids = new SparseLongArray();
- mBatteryStatsImpl.readKernelUidCpuTimesLocked(null, updatedUids);
+ mBatteryStatsImpl.readKernelUidCpuTimesLocked(null, updatedUids, true);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -294,7 +294,7 @@
}).when(mKernelUidCpuTimeReader).readDelta(any(KernelUidCpuTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuTimesLocked(null, null);
+ mBatteryStatsImpl.readKernelUidCpuTimesLocked(null, null, true);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -333,7 +333,7 @@
}).when(mKernelUidCpuTimeReader).readDelta(any(KernelUidCpuTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuTimesLocked(null, null);
+ mBatteryStatsImpl.readKernelUidCpuTimesLocked(null, null, true);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -368,7 +368,7 @@
}).when(mKernelUidCpuTimeReader).readDelta(any(KernelUidCpuTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuTimesLocked(null, null);
+ mBatteryStatsImpl.readKernelUidCpuTimesLocked(null, null, true);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -423,7 +423,7 @@
}).when(mKernelUidCpuTimeReader).readDelta(any(KernelUidCpuTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuTimesLocked(null, null);
+ mBatteryStatsImpl.readKernelUidCpuTimesLocked(null, null, true);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -470,7 +470,7 @@
// RUN
final SparseLongArray updatedUids = new SparseLongArray();
- mBatteryStatsImpl.readKernelUidCpuTimesLocked(partialTimers, updatedUids);
+ mBatteryStatsImpl.readKernelUidCpuTimesLocked(partialTimers, updatedUids, true);
// VERIFY
long totalUserTimeUs = 0;
@@ -549,7 +549,7 @@
any(KernelUidCpuFreqTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null);
+ mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -582,7 +582,7 @@
any(KernelUidCpuFreqTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null);
+ mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, true);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -633,7 +633,7 @@
when(mKernelUidCpuFreqTimeReader.perClusterTimesAvailable()).thenReturn(true);
// RUN
- mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null);
+ mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -676,7 +676,7 @@
any(KernelUidCpuFreqTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null);
+ mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, true);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -743,7 +743,7 @@
when(mKernelUidCpuFreqTimeReader.perClusterTimesAvailable()).thenReturn(true);
// RUN
- mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(partialTimers);
+ mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(partialTimers, true, false);
// VERIFY
final long[][] expectedWakeLockUidTimesUs = new long[clusterFreqs.length][];
@@ -832,7 +832,7 @@
any(KernelUidCpuFreqTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null);
+ mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -865,7 +865,7 @@
any(KernelUidCpuFreqTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null);
+ mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, true);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -909,7 +909,7 @@
any(KernelUidCpuFreqTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null);
+ mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -949,7 +949,7 @@
any(KernelUidCpuFreqTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null);
+ mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -1006,7 +1006,7 @@
any(KernelUidCpuFreqTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null);
+ mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -1047,7 +1047,7 @@
any(KernelUidCpuActiveTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuActiveTimesLocked();
+ mBatteryStatsImpl.readKernelUidCpuActiveTimesLocked(true);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -1073,7 +1073,7 @@
any(KernelUidCpuActiveTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuActiveTimesLocked();
+ mBatteryStatsImpl.readKernelUidCpuActiveTimesLocked(true);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -1112,7 +1112,7 @@
any(KernelUidCpuClusterTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked();
+ mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked(true);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
@@ -1142,7 +1142,7 @@
any(KernelUidCpuClusterTimeReader.Callback.class));
// RUN
- mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked();
+ mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked(true);
// VERIFY
for (int i = 0; i < testUids.length; ++i) {
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 82ac9da..01ddc15 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
@@ -161,9 +161,7 @@
actualRunTimeUs = uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_FOREGROUND_SERVICE,
elapsedTimeUs, STATS_SINCE_CHARGED);
- expectedRunTimeMs = stateRuntimeMap.get(
- ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE)
- + stateRuntimeMap.get(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+ expectedRunTimeMs = stateRuntimeMap.get(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
assertEquals(expectedRunTimeMs * 1000, actualRunTimeUs);
actualRunTimeUs = uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_TOP_SLEEPING,
@@ -173,7 +171,8 @@
actualRunTimeUs = uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_FOREGROUND,
elapsedTimeUs, STATS_SINCE_CHARGED);
- expectedRunTimeMs = stateRuntimeMap.get(ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
+ expectedRunTimeMs = stateRuntimeMap.get(ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND)
+ + stateRuntimeMap.get(ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
assertEquals(expectedRunTimeMs * 1000, actualRunTimeUs);
actualRunTimeUs = uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_BACKGROUND,
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 5d72942..29227f9 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelSingleUidTimeReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelSingleUidTimeReaderTest.java
@@ -115,6 +115,30 @@
}
@Test
+ public void readDelta_incorrectCount() {
+ assertTrue(mReader.singleUidCpuTimesAvailable());
+
+ long[] cpuTimes = new long[TEST_FREQ_COUNT - 1];
+ for (int i = 0; i < cpuTimes.length; ++i) {
+ cpuTimes[i] = 111 + i;
+ }
+ mInjector.setData(cpuTimes);
+ assertCpuTimesEqual(null, mReader.readDeltaMs(TEST_UID));
+ assertFalse(mReader.singleUidCpuTimesAvailable());
+
+ // Reset
+ mReader.setSingleUidCpuTimesAvailable(true);
+
+ cpuTimes = new long[TEST_FREQ_COUNT + 1];
+ for (int i = 0; i < cpuTimes.length; ++i) {
+ cpuTimes[i] = 222 + i;
+ }
+ mInjector.setData(cpuTimes);
+ assertCpuTimesEqual(null, mReader.readDeltaMs(TEST_UID));
+ assertFalse(mReader.singleUidCpuTimesAvailable());
+ }
+
+ @Test
public void testComputeDelta() {
// proc file not available
mReader.setSingleUidCpuTimesAvailable(false);
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 7b239f0..cb05253 100644
--- a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
+++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
@@ -171,6 +171,20 @@
return null;
}
+ @Override
+ public Future<?> scheduleCpuSyncDueToScreenStateChange(
+ boolean onBattery, boolean onBatteryScreenOff) {
+ return null;
+ }
+
+ @Override
+ public Future<?> scheduleCpuSyncDueToWakelockChange(long delayMillis) {
+ return null;
+ }
+
+ @Override
+ public void cancelCpuSyncDueToWakelockChange() {
+ }
}
}
diff --git a/core/tests/featureflagtests/OWNERS b/core/tests/featureflagtests/OWNERS
new file mode 100644
index 0000000..1a8fd2b
--- /dev/null
+++ b/core/tests/featureflagtests/OWNERS
@@ -0,0 +1,2 @@
+sbasi@google.com
+zhfan@google.com
\ No newline at end of file
diff --git a/core/tests/hosttests/test-apps/SharedUid/32/jni/Android.mk b/core/tests/hosttests/test-apps/SharedUid/32/jni/Android.mk
index 994131a..9b9e811 100644
--- a/core/tests/hosttests/test-apps/SharedUid/32/jni/Android.mk
+++ b/core/tests/hosttests/test-apps/SharedUid/32/jni/Android.mk
@@ -29,13 +29,10 @@
LOCAL_SRC_FILES:= \
native.cpp
-# All of the shard libraries we link against.
-LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_LDLIBS := -llog
LOCAL_CFLAGS += -Wall -Wextra -Werror
-# Also need the JNI headers.
-LOCAL_C_INCLUDES += \
- $(JNI_H_INCLUDE)
+LOCAL_SDK_VERSION := current
include $(BUILD_SHARED_LIBRARY)
diff --git a/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp b/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp
index 99cf587..fe32454 100644
--- a/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp
+++ b/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp
@@ -15,12 +15,15 @@
*/
#define LOG_TAG "pmtest32 native.cpp"
-#include <utils/Log.h>
+#include <android/log.h>
#include <stdio.h>
#include "jni.h"
+#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
+#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
+
static jint
add(JNIEnv */* env */, jobject /* thiz */, jint a, jint b) {
int result = a + b;
diff --git a/core/tests/hosttests/test-apps/SharedUid/64/jni/Android.mk b/core/tests/hosttests/test-apps/SharedUid/64/jni/Android.mk
index 6c2679b..600a5d1 100644
--- a/core/tests/hosttests/test-apps/SharedUid/64/jni/Android.mk
+++ b/core/tests/hosttests/test-apps/SharedUid/64/jni/Android.mk
@@ -30,14 +30,10 @@
LOCAL_SRC_FILES:= \
native.cpp
-# All of the shared libraries we link against.
-LOCAL_SHARED_LIBRARIES := \
- libutils liblog
+LOCAL_LDLIBS := -llog
LOCAL_CFLAGS += -Wall -Wextra -Werror
-# Also need the JNI headers.
-LOCAL_C_INCLUDES += \
- $(JNI_H_INCLUDE)
+LOCAL_SDK_VERSION := current
include $(BUILD_SHARED_LIBRARY)
diff --git a/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp b/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp
index 0b6d750..ad9e746 100644
--- a/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp
+++ b/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp
@@ -15,12 +15,15 @@
*/
#define LOG_TAG "pmtest64 native.cpp"
-#include <utils/Log.h>
+#include <android/log.h>
#include <stdio.h>
#include "jni.h"
+#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
+#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
+
static jint
add(JNIEnv */* env */, jobject /* thiz */, jint a, jint b) {
int result = a + b;
diff --git a/core/tests/hosttests/test-apps/SharedUid/dual/jni/Android.mk b/core/tests/hosttests/test-apps/SharedUid/dual/jni/Android.mk
index d668f29..8e9ac6b 100644
--- a/core/tests/hosttests/test-apps/SharedUid/dual/jni/Android.mk
+++ b/core/tests/hosttests/test-apps/SharedUid/dual/jni/Android.mk
@@ -29,14 +29,10 @@
LOCAL_SRC_FILES:= \
native.cpp
-# All of the shard libraries we link against.
LOCAL_LDLIBS = -llog
-LOCAL_SHARED_LIBRARIES := liblog
LOCAL_CFLAGS += -Wall -Wextra -Werror
-# Also need the JNI headers.
-LOCAL_C_INCLUDES += \
- $(JNI_H_INCLUDE)
+LOCAL_SDK_VERSION := current
include $(BUILD_SHARED_LIBRARY)
diff --git a/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp b/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp
index 3947e21..5c5088f 100644
--- a/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp
+++ b/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp
@@ -15,12 +15,15 @@
*/
#define LOG_TAG "pmtestdual native.cpp"
-#include <utils/Log.h>
+#include <android/log.h>
#include <stdio.h>
#include "jni.h"
+#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
+#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
+
static jint
add(JNIEnv */* env */, jobject /* thiz */, jint a, jint b) {
int result = a + b;
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 3495b84..9d1fdbd 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -176,7 +176,7 @@
<permission name="android.permission.UPDATE_LOCK"/>
<permission name="android.permission.WRITE_APN_SETTINGS"/>
<permission name="android.permission.WRITE_SECURE_SETTINGS"/>
- <permission name="com.android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS"/>
+ <permission name="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS"/>
<permission name="com.android.voicemail.permission.READ_VOICEMAIL"/>
<permission name="com.android.voicemail.permission.WRITE_VOICEMAIL"/>
</privapp-permissions>
@@ -381,7 +381,7 @@
<permission name="android.permission.WRITE_DREAM_STATE"/>
<permission name="android.permission.WRITE_MEDIA_STORAGE"/>
<permission name="android.permission.WRITE_SECURE_SETTINGS"/>
- <permission name="com.android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS"/>
+ <permission name="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS"/>
</privapp-permissions>
<privapp-permissions package="com.android.tv">
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index a56e8d1..66f2a31 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -667,8 +667,9 @@
return;
}
- final int sourceDensity = ninePatch.getDensity();
final int targetDensity = mTargetDensity;
+ final int sourceDensity = ninePatch.getDensity() == Bitmap.DENSITY_NONE ?
+ targetDensity : ninePatch.getDensity();
final Insets sourceOpticalInsets = mNinePatchState.mOpticalInsets;
if (sourceOpticalInsets != Insets.NONE) {
diff --git a/libs/hwui/hwui/AnimatedImageDrawable.cpp b/libs/hwui/hwui/AnimatedImageDrawable.cpp
index 2bded9b..7e4f755 100644
--- a/libs/hwui/hwui/AnimatedImageDrawable.cpp
+++ b/libs/hwui/hwui/AnimatedImageDrawable.cpp
@@ -41,8 +41,7 @@
return false;
}
- // This will trigger a reset.
- mFinished = true;
+ mStarting = true;
mRunning = true;
return true;
@@ -125,8 +124,11 @@
mDidDraw = true;
- bool drewDirectly = false;
- if (!mSnapshot.mPic) {
+ const bool starting = mStarting;
+ mStarting = false;
+
+ const bool drawDirectly = !mSnapshot.mPic;
+ if (drawDirectly) {
// The image is not animating, and never was. Draw directly from
// mSkAnimatedImage.
SkAutoCanvasRestore acr(canvas, false);
@@ -136,13 +138,14 @@
std::unique_lock lock{mImageLock};
mSkAnimatedImage->draw(canvas);
- drewDirectly = true;
- }
-
- if (mRunning && mFinished) {
+ if (!mRunning) {
+ return;
+ }
+ } else if (starting) {
+ // The image has animated, and now is being reset. Queue up the first
+ // frame, but keep showing the current frame until the first is ready.
auto& thread = uirenderer::AnimatedImageThread::getInstance();
mNextSnapshot = thread.reset(sk_ref_sp(this));
- mFinished = false;
}
bool finalFrame = false;
@@ -154,7 +157,6 @@
if (mSnapshot.mDuration == SkAnimatedImage::kFinished) {
finalFrame = true;
mRunning = false;
- mFinished = true;
} else {
mTimeToShowNextSnapshot += mSnapshot.mDuration;
if (mCurrentTime >= mTimeToShowNextSnapshot) {
@@ -173,7 +175,7 @@
mNextSnapshot = thread.decodeNextFrame(sk_ref_sp(this));
}
- if (!drewDirectly) {
+ if (!drawDirectly) {
// No other thread will modify mCurrentSnap so this should be safe to
// use without locking.
canvas->drawPicture(mSnapshot.mPic, nullptr, lazyPaint.getMaybeNull());
@@ -195,14 +197,29 @@
canvas->saveLayer(mSkAnimatedImage->getBounds(), &paint);
}
- if (mFinished && !mRunning) {
- // Continue drawing the last frame, and return 0 to indicate no need to
- // redraw.
+ if (!mRunning) {
+ // Continue drawing the current frame, and return 0 to indicate no need
+ // to redraw.
std::unique_lock lock{mImageLock};
canvas->drawDrawable(mSkAnimatedImage.get());
return 0.0;
}
+ if (mStarting) {
+ mStarting = false;
+ double duration = 0.0;
+ {
+ std::unique_lock lock{mImageLock};
+ mSkAnimatedImage->reset();
+ duration = mSkAnimatedImage->currentFrameDuration();
+ }
+ {
+ std::unique_lock lock{mSwapLock};
+ mLastWallTime = 0.0;
+ mTimeToShowNextSnapshot = duration;
+ }
+ }
+
bool update = false;
{
const double currentTime = SkTime::GetMSecs();
@@ -211,18 +228,12 @@
// the current time and avoid updating
if (mLastWallTime == 0.0) {
mCurrentTime = currentTime;
- } else if (mRunning) {
- if (mFinished) {
- mCurrentTime = currentTime;
- {
- std::unique_lock lock{mImageLock};
- mSkAnimatedImage->reset();
- }
- mTimeToShowNextSnapshot = currentTime + mSkAnimatedImage->currentFrameDuration();
- } else {
- mCurrentTime += currentTime - mLastWallTime;
- update = mCurrentTime >= mTimeToShowNextSnapshot;
- }
+ // mTimeToShowNextSnapshot is already set to the duration of the
+ // first frame.
+ mTimeToShowNextSnapshot += currentTime;
+ } else if (mRunning && mDidDraw) {
+ mCurrentTime += currentTime - mLastWallTime;
+ update = mCurrentTime >= mTimeToShowNextSnapshot;
}
mLastWallTime = currentTime;
}
@@ -237,13 +248,20 @@
canvas->drawDrawable(mSkAnimatedImage.get());
}
+ mDidDraw = true;
+
std::unique_lock lock{mSwapLock};
if (update) {
if (duration == SkAnimatedImage::kFinished) {
mRunning = false;
- mFinished = true;
- } else {
- mTimeToShowNextSnapshot += duration;
+ return duration;
+ }
+
+ const double timeToShowCurrentSnapshot = mTimeToShowNextSnapshot;
+ mTimeToShowNextSnapshot += duration;
+ if (mCurrentTime >= mTimeToShowNextSnapshot) {
+ // As in onDraw, prevent speedy catch-up behavior.
+ mCurrentTime = timeToShowCurrentSnapshot;
}
}
return mTimeToShowNextSnapshot;
diff --git a/libs/hwui/hwui/AnimatedImageDrawable.h b/libs/hwui/hwui/AnimatedImageDrawable.h
index 2fd6f40..07469d2 100644
--- a/libs/hwui/hwui/AnimatedImageDrawable.h
+++ b/libs/hwui/hwui/AnimatedImageDrawable.h
@@ -102,7 +102,7 @@
private:
sk_sp<SkAnimatedImage> mSkAnimatedImage;
bool mRunning = false;
- bool mFinished = false;
+ bool mStarting = false;
// A snapshot of the current frame to draw.
Snapshot mSnapshot;
diff --git a/libs/incident/Android.mk b/libs/incident/Android.mk
index b63400f..08c8346 100644
--- a/libs/incident/Android.mk
+++ b/libs/incident/Android.mk
@@ -33,6 +33,7 @@
../../core/java/android/os/IIncidentManager.aidl \
../../core/java/android/os/IIncidentReportStatusListener.aidl \
proto/android/os/header.proto \
+ proto/android/os/metadata.proto \
src/IncidentReportArgs.cpp
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
diff --git a/libs/incident/proto/android/os/metadata.proto b/libs/incident/proto/android/os/metadata.proto
new file mode 100644
index 0000000..a1e89b0
--- /dev/null
+++ b/libs/incident/proto/android/os/metadata.proto
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+option java_multiple_files = true;
+
+package android.os;
+
+// This field contains internal metadata associated with an incident report,
+// such as the section ids and privacy policy specs from caller as well as how long
+// and how many bytes a section takes, etc.
+message IncidentMetadata {
+
+ // privacy level of the incident report.
+ enum Destination {
+ AUTOMATIC = 0;
+ EXPLICIT = 1;
+ LOCAL = 2;
+ }
+ optional Destination dest = 1;
+
+ optional int32 request_size = 2;
+
+ optional bool use_dropbox = 3;
+
+ // stats of each section taken in this incident report.
+ message SectionStats {
+ // section id.
+ optional int32 id = 1;
+ // if the section is successfully taken.
+ optional bool success = 2;
+ // number of bytes in the report after filtering.
+ optional int32 report_size_bytes = 3;
+ // the total duration to execute the section.
+ optional int64 exec_duration_ms = 4;
+
+ // number of bytes dumped from the section directly.
+ optional int32 dump_size_bytes = 5;
+ // duration of the dump takes.
+ optional int64 dump_duration_ms = 6;
+ // true if the section timed out.
+ optional bool timed_out = 7;
+ // true if the section is truncated.
+ optional bool is_truncated = 8;
+
+ // Next Tag: 9
+ }
+ repeated SectionStats sections = 4;
+}
+
diff --git a/media/OWNERS b/media/OWNERS
new file mode 100644
index 0000000..8f405e9
--- /dev/null
+++ b/media/OWNERS
@@ -0,0 +1,4 @@
+elaurent@google.com
+etalvala@google.com
+lajos@google.com
+marcone@google.com
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 0be54ec..9ff964b 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -16,6 +16,7 @@
package android.media;
+import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -65,6 +66,8 @@
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executor;
+
/**
* AudioManager provides access to volume and ringer mode control.
@@ -4864,6 +4867,114 @@
}
}
+
+ /**
+ * @hide
+ * Abstract class to receive event notification about audioserver process state.
+ */
+ @SystemApi
+ public abstract static class AudioServerStateCallback {
+ public void onAudioServerDown() { }
+ public void onAudioServerUp() { }
+ }
+
+ private Executor mAudioServerStateExec;
+ private AudioServerStateCallback mAudioServerStateCb;
+ private final Object mAudioServerStateCbLock = new Object();
+
+ private final IAudioServerStateDispatcher mAudioServerStateDispatcher =
+ new IAudioServerStateDispatcher.Stub() {
+ @Override
+ public void dispatchAudioServerStateChange(boolean state) {
+ Executor exec;
+ AudioServerStateCallback cb;
+
+ synchronized (mAudioServerStateCbLock) {
+ exec = mAudioServerStateExec;
+ cb = mAudioServerStateCb;
+ }
+
+ if ((exec == null) || (cb == null)) {
+ return;
+ }
+ if (state) {
+ exec.execute(() -> cb.onAudioServerUp());
+ } else {
+ exec.execute(() -> cb.onAudioServerDown());
+ }
+ }
+ };
+
+ /**
+ * @hide
+ * Registers a callback for notification of audio server state changes.
+ * @param executor {@link Executor} to handle the callbacks
+ * @param stateCallback the callback to receive the audio server state changes
+ * To remove the callabck, pass a null reference for both executor and stateCallback.
+ */
+ @SystemApi
+ public void setAudioServerStateCallback(@NonNull Executor executor,
+ @NonNull AudioServerStateCallback stateCallback) {
+ if (stateCallback == null) {
+ throw new IllegalArgumentException("Illegal null AudioServerStateCallback");
+ }
+ if (executor == null) {
+ throw new IllegalArgumentException(
+ "Illegal null Executor for the AudioServerStateCallback");
+ }
+
+ synchronized (mAudioServerStateCbLock) {
+ if (mAudioServerStateCb != null) {
+ throw new IllegalStateException(
+ "setAudioServerStateCallback called with already registered callabck");
+ }
+ final IAudioService service = getService();
+ try {
+ service.registerAudioServerStateDispatcher(mAudioServerStateDispatcher);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ mAudioServerStateExec = executor;
+ mAudioServerStateCb = stateCallback;
+ }
+ }
+
+ /**
+ * @hide
+ * Unregisters the callback for notification of audio server state changes.
+ */
+ @SystemApi
+ public void clearAudioServerStateCallback() {
+ synchronized (mAudioServerStateCbLock) {
+ if (mAudioServerStateCb != null) {
+ final IAudioService service = getService();
+ try {
+ service.unregisterAudioServerStateDispatcher(
+ mAudioServerStateDispatcher);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ mAudioServerStateExec = null;
+ mAudioServerStateCb = null;
+ }
+ }
+
+ /**
+ * @hide
+ * Checks if native audioservice is running or not.
+ * @return true if native audioservice runs, false otherwise.
+ */
+ @SystemApi
+ public boolean isAudioServerRunning() {
+ final IAudioService service = getService();
+ try {
+ return service.isAudioServerRunning();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
//---------------------------------------------------------
// Inner classes
//--------------------
diff --git a/core/java/android/security/keymaster/KeymasterArguments.aidl b/media/java/android/media/IAudioServerStateDispatcher.aidl
similarity index 67%
rename from core/java/android/security/keymaster/KeymasterArguments.aidl
rename to media/java/android/media/IAudioServerStateDispatcher.aidl
index 44d9f09..2bc90ea 100644
--- a/core/java/android/security/keymaster/KeymasterArguments.aidl
+++ b/media/java/android/media/IAudioServerStateDispatcher.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 The Android Open Source Project
+ * 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.
@@ -14,7 +14,15 @@
* limitations under the License.
*/
-package android.security.keymaster;
+package android.media;
-/* @hide */
-parcelable KeymasterArguments cpp_header "keystore/KeymasterArguments.h";
+/**
+ * AIDL for the AudioService to signal audio server state changes
+ *
+ * {@hide}
+ */
+oneway interface IAudioServerStateDispatcher {
+
+ void dispatchAudioServerStateChange(boolean state);
+
+}
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 4c37014..05ba4c3 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -24,10 +24,12 @@
import android.media.AudioRoutesInfo;
import android.media.IAudioFocusDispatcher;
import android.media.IAudioRoutesObserver;
+import android.media.IAudioServerStateDispatcher;
import android.media.IPlaybackConfigDispatcher;
import android.media.IRecordingConfigDispatcher;
import android.media.IRingtonePlayer;
import android.media.IVolumeController;
+import android.media.IVolumeController;
import android.media.PlayerBase;
import android.media.VolumePolicy;
import android.media.audiopolicy.AudioPolicyConfig;
@@ -208,6 +210,12 @@
oneway void setFocusRequestResultFromExtPolicy(in AudioFocusInfo afi, int requestResult,
in IAudioPolicyCallback pcb);
+ void registerAudioServerStateDispatcher(IAudioServerStateDispatcher asd);
+
+ oneway void unregisterAudioServerStateDispatcher(IAudioServerStateDispatcher asd);
+
+ boolean isAudioServerRunning();
+
// WARNING: read warning at top of file, new methods that need to be used by native
// code via IAudioManager.h need to be added to the top section.
}
diff --git a/media/java/android/media/MediaBrowser2.java b/media/java/android/media/MediaBrowser2.java
index 5cb8313..32d3162 100644
--- a/media/java/android/media/MediaBrowser2.java
+++ b/media/java/android/media/MediaBrowser2.java
@@ -53,8 +53,32 @@
@Nullable Bundle rootExtra) { }
/**
+ * Called when there's change in the parent's children.
+ *
+ * @param parentId parent id that you've specified with {@link #subscribe(String, Bundle)}
+ * @param extras extra bundle that you've specified with {@link #subscribe(String, Bundle)}
+ */
+ public void onChildrenChanged(@NonNull String parentId, @Nullable Bundle extras) { }
+
+ /**
+ * Called when the list of items has been returned by the library service for the previous
+ * {@link MediaBrowser2#getChildren(String, int, int, Bundle)}.
+ *
+ * @param parentId parent id
+ * @param page page number that you've specified with
+ * {@link #getChildren(String, int, int, Bundle)}
+ * @param pageSize page size that you've specified with
+ * {@link #getChildren(String, int, int, Bundle)}
+ * @param extras extra bundle that you've specified with
+ * {@link #getChildren(String, int, int, Bundle)}
+ * @param result result. Can be {@code null}
+ */
+ public void onChildrenLoaded(@NonNull String parentId, int page, int pageSize,
+ @Nullable Bundle extras, @Nullable List<MediaItem2> result) { }
+
+ /**
* Called when the item has been returned by the library service for the previous
- * {@link MediaBrowser2#getItem} call.
+ * {@link MediaBrowser2#getItem(String)} call.
* <p>
* Result can be null if there had been error.
*
@@ -64,40 +88,33 @@
public void onItemLoaded(@NonNull String mediaId, @Nullable MediaItem2 result) { }
/**
- * Called when the list of items has been returned by the library service for the previous
- * {@link MediaBrowser2#getChildren(String, int, int, Bundle)}.
+ * Called when there's change in the search result.
*
- * @param parentId parent id
- * @param page page number that you've specified
- * @param pageSize page size that you've specified
- * @param options optional bundle that you've specified
- * @param result result. Can be {@code null}
+ * @param query search query that you've specified with {@link #search(String, Bundle)}
+ * @param extras extra bundle that you've specified with {@link #search(String, Bundle)}
+ * @param totalItemCount The total item count for the search result
*/
- public void onChildrenLoaded(@NonNull String parentId, int page, int pageSize,
- @Nullable Bundle options, @Nullable List<MediaItem2> result) { }
-
- /**
- * Called when there's change in the parent's children.
- *
- * @param parentId parent id that you've specified with subscribe
- * @param options optional bundle that you've specified with subscribe
- */
- public void onChildrenChanged(@NonNull String parentId, @Nullable Bundle options) { }
+ public void onSearchResultChanged(@NonNull String query, @Nullable Bundle extras,
+ int totalItemCount) { }
/**
* Called when the search result has been returned by the library service for the previous
- * {@link MediaBrowser2#search(String, int, int, Bundle)}.
+ * {@link MediaBrowser2#getSearchResult(String, int, int, Bundle)}.
* <p>
* Result can be null if there had been error.
*
- * @param query query string that you've specified
- * @param page page number that you've specified
- * @param pageSize page size that you've specified
- * @param options optional bundle that you've specified
- * @param result result. Can be {@code null}
+ * @param query search query that you've specified with
+ * {@link #getSearchResult(String, int, int, Bundle)}
+ * @param page page number that you've specified with
+ * {@link #getSearchResult(String, int, int, Bundle)}
+ * @param pageSize page size that you've specified with
+ * {@link #getSearchResult(String, int, int, Bundle)}
+ * @param extras extra bundle that you've specified with
+ * {@link #getSearchResult(String, int, int, Bundle)}
+ * @param result result. Can be {@code null}.
*/
- public void onSearchResult(@NonNull String query, int page, int pageSize,
- @Nullable Bundle options, @Nullable List<MediaItem2> result) { }
+ public void onSearchResultLoaded(@NonNull String query, int page, int pageSize,
+ @Nullable Bundle extras, @Nullable List<MediaItem2> result) { }
}
public MediaBrowser2(@NonNull Context context, @NonNull SessionToken2 token,
@@ -131,10 +148,10 @@
* the actual contents for the parent.
*
* @param parentId parent id
- * @param options optional bundle
+ * @param extras extra bundle
*/
- public void subscribe(String parentId, @Nullable Bundle options) {
- mProvider.subscribe_impl(parentId, options);
+ public void subscribe(String parentId, @Nullable Bundle extras) {
+ mProvider.subscribe_impl(parentId, extras);
}
/**
@@ -142,43 +159,59 @@
* {@link #subscribe(String, Bundle)}.
*
* @param parentId parent id
- * @param options optional bundle
+ * @param extras extra bundle
*/
- public void unsubscribe(String parentId, @Nullable Bundle options) {
- mProvider.unsubscribe_impl(parentId, options);
- }
-
- /**
- * Get the media item with the given media id. Result would be sent back asynchronously with the
- * {@link BrowserCallback#onItemLoaded(String, MediaItem2)}.
- *
- * @param mediaId media id
- */
- public void getItem(String mediaId) {
- mProvider.getItem_impl(mediaId);
+ public void unsubscribe(String parentId, @Nullable Bundle extras) {
+ mProvider.unsubscribe_impl(parentId, extras);
}
/**
* Get list of children under the parent. Result would be sent back asynchronously with the
* {@link BrowserCallback#onChildrenLoaded(String, int, int, Bundle, List)}.
*
- * @param parentId
- * @param page
- * @param pageSize
- * @param options
+ * @param parentId parent id for getting the children.
+ * @param page page number to get the result. Starts from {@code 1}
+ * @param pageSize page size. Should be greater or equal to {@code 1}
+ * @param extras extra bundle
*/
- public void getChildren(String parentId, int page, int pageSize, @Nullable Bundle options) {
- mProvider.getChildren_impl(parentId, page, pageSize, options);
+ public void getChildren(String parentId, int page, int pageSize, @Nullable Bundle extras) {
+ mProvider.getChildren_impl(parentId, page, pageSize, extras);
}
/**
+ * Get the media item with the given media id. Result would be sent back asynchronously with the
+ * {@link BrowserCallback#onItemLoaded(String, MediaItem2)}.
*
- * @param query search query deliminated by string
+ * @param mediaId media id for specifying the item
+ */
+ public void getItem(String mediaId) {
+ mProvider.getItem_impl(mediaId);
+ }
+
+ /**
+ * Send a search request to the library service. When there's a change,
+ * {@link BrowserCallback#onSearchResultChanged(String, Bundle, int)} will be called with the
+ * bundle that you've specified. You should call
+ * {@link #getSearchResult(String, int, int, Bundle)} to get the actual search result.
+ *
+ * @param query search query. Should not be an empty string.
+ * @param extras extra bundle
+ */
+ public void search(@NonNull String query, @Nullable Bundle extras) {
+ mProvider.search_impl(query, extras);
+ }
+
+ /**
+ * Get the search result from lhe library service. Result would be sent back asynchronously with
+ * the {@link BrowserCallback#onSearchResultLoaded(String, int, int, Bundle, List)}.
+ *
+ * @param query search query that you've specified with {@link #search(String, Bundle)}
* @param page page number to get search result. Starts from {@code 1}
* @param pageSize page size. Should be greater or equal to {@code 1}
* @param extras extra bundle
*/
- public void search(String query, int page, int pageSize, Bundle extras) {
- mProvider.search_impl(query, page, pageSize, extras);
+ public void getSearchResult(@NonNull String query, int page, int pageSize,
+ @Nullable Bundle extras) {
+ mProvider.getSearchResult_impl(query, page, pageSize, extras);
}
}
diff --git a/media/java/android/media/MediaItem2.java b/media/java/android/media/MediaItem2.java
index eae4436..667aac1 100644
--- a/media/java/android/media/MediaItem2.java
+++ b/media/java/android/media/MediaItem2.java
@@ -123,27 +123,26 @@
}
/**
- * Set a metadata. Metadata shouldn't be {@code null} and its id should be match
- * with this instance's id.
+ * Set a metadata. If the metadata is not null, its id should be matched with this instance's
+ * media id.
*
* @param metadata metadata to update
*/
- public void setMetadata(@NonNull MediaMetadata2 metadata) {
+ public void setMetadata(@Nullable MediaMetadata2 metadata) {
mProvider.setMetadata_impl(metadata);
}
/**
* Returns the metadata of the media.
*/
- public @NonNull MediaMetadata2 getMetadata() {
+ public @Nullable MediaMetadata2 getMetadata() {
return mProvider.getMetadata_impl();
}
/**
- * Returns the media id in the {@link MediaMetadata2} for this item.
- * @see MediaMetadata2#METADATA_KEY_MEDIA_ID
+ * Returns the media id for this item.
*/
- public @Nullable String getMediaId() {
+ public @NonNull String getMediaId() {
return mProvider.getMediaId_impl();
}
diff --git a/media/java/android/media/MediaLibraryService2.java b/media/java/android/media/MediaLibraryService2.java
index a11768e..7a05d3c 100644
--- a/media/java/android/media/MediaLibraryService2.java
+++ b/media/java/android/media/MediaLibraryService2.java
@@ -82,22 +82,22 @@
*
* @param controller controller to notify
* @param parentId
- * @param options
+ * @param extras
*/
public void notifyChildrenChanged(@NonNull ControllerInfo controller,
- @NonNull String parentId, @NonNull Bundle options) {
- mProvider.notifyChildrenChanged_impl(controller, parentId, options);
+ @NonNull String parentId, @NonNull Bundle extras) {
+ mProvider.notifyChildrenChanged_impl(controller, parentId, extras);
}
/**
* Notify subscribed controller about change in a parent's children.
*
* @param parentId parent id
- * @param options optional bundle
+ * @param extras extra bundle
*/
// This is for the backward compatibility.
- public void notifyChildrenChanged(@NonNull String parentId, @Nullable Bundle options) {
- mProvider.notifyChildrenChanged_impl(parentId, options);
+ public void notifyChildrenChanged(@NonNull String parentId, @Nullable Bundle extras) {
+ mProvider.notifyChildrenChanged_impl(parentId, extras);
}
}
@@ -134,27 +134,12 @@
}
/**
- * Called to get the search result. Return search result here for the browser.
+ * Called to get an item. Return result here for the browser.
* <p>
- * Return an empty list for no search result, and return {@code null} for the error.
- *
- * @param query The search query sent from the media browser. It contains keywords separated
- * by space.
- * @param extras The bundle of service-specific arguments sent from the media browser.
- * @return search result. {@code null} for error.
- */
- public @Nullable List<MediaItem2> onSearch(@NonNull ControllerInfo controllerInfo,
- @NonNull String query, @Nullable Bundle extras) {
- return null;
- }
-
- /**
- * Called to get the search result . Return result here for the browser.
- * <p>
- * Return an empty list for no search result, and return {@code null} for the error.
+ * Return {@code null} for no result or error.
*
* @param itemId item id to get media item.
- * @return media item2. {@code null} for error.
+ * @return a media item. {@code null} for no result or error.
*/
public @Nullable MediaItem2 onLoadItem(@NonNull ControllerInfo controllerInfo,
@NonNull String itemId) {
@@ -162,18 +147,18 @@
}
/**
- * Called to get the search result. Return search result here for the browser.
+ * Called to get children of given parent id. Return the children here for the browser.
* <p>
- * Return an empty list for no search result, and return {@code null} for the error.
+ * Return an empty list for no children, and return {@code null} for the error.
*
* @param parentId parent id to get children
* @param page number of page
* @param pageSize size of the page
- * @param options
+ * @param extras extra bundle
* @return list of children. Can be {@code null}.
*/
public @Nullable List<MediaItem2> onLoadChildren(@NonNull ControllerInfo controller,
- @NonNull String parentId, int page, int pageSize, @Nullable Bundle options) {
+ @NonNull String parentId, int page, int pageSize, @Nullable Bundle extras) {
return null;
}
@@ -182,10 +167,10 @@
*
* @param controller controller
* @param parentId parent id
- * @param options optional bundle
+ * @param extras extra bundle
*/
- public void onSubscribed(@NonNull ControllerInfo controller,
- String parentId, @Nullable Bundle options) {
+ public void onSubscribed(@NonNull ControllerInfo controller, String parentId,
+ @Nullable Bundle extras) {
}
/**
@@ -193,10 +178,41 @@
*
* @param controller controller
* @param parentId parent id
- * @param options optional bundle
+ * @param extras extra bundle
*/
- public void onUnsubscribed(@NonNull ControllerInfo controller,
- String parentId, @Nullable Bundle options) {
+ public void onUnsubscribed(@NonNull ControllerInfo controller, String parentId,
+ @Nullable Bundle extras) {
+ }
+
+ /**
+ * Called when a controller requests search.
+ *
+ * @param query The search query sent from the media browser. It contains keywords separated
+ * by space.
+ * @param extras The bundle of service-specific arguments sent from the media browser.
+ */
+ public void onSearch(@NonNull ControllerInfo controllerInfo, @NonNull String query,
+ @Nullable Bundle extras) {
+
+ }
+
+ /**
+ * Called to get the search result. Return search result here for the browser which has
+ * requested search previously.
+ * <p>
+ * Return an empty list for no search result, and return {@code null} for the error.
+ *
+ * @param controllerInfo Information of the controller requesting the search result.
+ * @param query The search query which was previously sent through
+ * {@link #onSearch(ControllerInfo, String, Bundle)} call.
+ * @param page page number. Starts from {@code 1}.
+ * @param pageSize page size. Should be greater or equal to {@code 1}.
+ * @param extras The bundle of service-specific arguments sent from the media browser.
+ * @return search result. {@code null} for error.
+ */
+ public @Nullable List<MediaItem2> onLoadSearchResult(@NonNull ControllerInfo controllerInfo,
+ @NonNull String query, int page, int pageSize, @Nullable Bundle extras) {
+ return null;
}
}
diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java
index 49bbc2b..b805eb4 100644
--- a/media/java/android/media/MediaPlayer2Impl.java
+++ b/media/java/android/media/MediaPlayer2Impl.java
@@ -17,7 +17,6 @@
package android.media;
import android.annotation.CallbackExecutor;
-import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityThread;
@@ -26,7 +25,6 @@
import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.net.Uri;
-import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
@@ -48,17 +46,8 @@
import android.view.SurfaceHolder;
import android.widget.VideoView;
import android.graphics.SurfaceTexture;
-import android.media.AudioManager;
-import android.media.MediaDrm;
-import android.media.MediaFormat;
-import android.media.MediaPlayer2;
-import android.media.MediaTimeProvider;
-import android.media.PlaybackParams;
-import android.media.SubtitleController;
import android.media.SubtitleController.Anchor;
-import android.media.SubtitleData;
import android.media.SubtitleTrack.RenderingWidget;
-import android.media.SyncParams;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
@@ -74,16 +63,12 @@
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.lang.AutoCloseable;
import java.lang.Runnable;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.net.CookieHandler;
import java.net.CookieManager;
import java.net.HttpCookie;
import java.net.HttpURLConnection;
-import java.net.InetSocketAddress;
import java.net.URL;
import java.nio.ByteOrder;
import java.util.ArrayList;
@@ -2190,6 +2175,13 @@
private native final void native_setup(Object mediaplayer2_this);
private native final void native_finalize();
+ private static native final void native_stream_event_onTearDown(
+ long nativeCallbackPtr, long userDataPtr);
+ private static native final void native_stream_event_onStreamPresentationEnd(
+ long nativeCallbackPtr, long userDataPtr);
+ private static native final void native_stream_event_onStreamDataRequest(
+ long jAudioTrackPtr, long nativeCallbackPtr, long userDataPtr);
+
/**
* Class for MediaPlayer2 to return each audio/video/subtitle track's metadata.
*
@@ -4228,6 +4220,65 @@
}
+ // Called from the native side
+ @SuppressWarnings("unused")
+ private static boolean setAudioOutputDeviceById(AudioTrack track, int deviceId) {
+ if (track == null) {
+ return false;
+ }
+
+ if (deviceId == 0) {
+ // Use default routing.
+ track.setPreferredDevice(null);
+ return true;
+ }
+
+ // TODO: Unhide AudioManager.getDevicesStatic.
+ AudioDeviceInfo[] outputDevices =
+ AudioManager.getDevicesStatic(AudioManager.GET_DEVICES_OUTPUTS);
+
+ boolean success = false;
+ for (AudioDeviceInfo device : outputDevices) {
+ if (device.getId() == deviceId) {
+ track.setPreferredDevice(device);
+ success = true;
+ break;
+ }
+ }
+ return success;
+ }
+
+ // Instantiated from the native side
+ @SuppressWarnings("unused")
+ private static class StreamEventCallback extends AudioTrack.StreamEventCallback {
+ public long mJAudioTrackPtr;
+ public long mNativeCallbackPtr;
+ public long mUserDataPtr;
+
+ public StreamEventCallback(long jAudioTrackPtr, long nativeCallbackPtr, long userDataPtr) {
+ super();
+ mJAudioTrackPtr = jAudioTrackPtr;
+ mNativeCallbackPtr = nativeCallbackPtr;
+ mUserDataPtr = userDataPtr;
+ }
+
+ @Override
+ public void onTearDown(AudioTrack track) {
+ native_stream_event_onTearDown(mNativeCallbackPtr, mUserDataPtr);
+ }
+
+ @Override
+ public void onStreamPresentationEnd(AudioTrack track) {
+ native_stream_event_onStreamPresentationEnd(mNativeCallbackPtr, mUserDataPtr);
+ }
+
+ @Override
+ public void onStreamDataRequest(AudioTrack track) {
+ native_stream_event_onStreamDataRequest(
+ mJAudioTrackPtr, mNativeCallbackPtr, mUserDataPtr);
+ }
+ }
+
private class ProvisioningThread extends Thread {
public static final int TIMEOUT_MS = 60000;
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index b8184a0..b8d01c4 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -119,7 +119,8 @@
private final ISession mBinder;
private final CallbackStub mCbStub;
- private CallbackMessageHandler mCallbackHandler;
+ // Do not change the name of mCallback. Support lib accesses this by using reflection.
+ private CallbackMessageHandler mCallback;
private VolumeProvider mVolumeProvider;
private PlaybackState mPlaybackState;
@@ -194,13 +195,13 @@
*/
public void setCallback(@Nullable Callback callback, @Nullable Handler handler) {
synchronized (mLock) {
- if (mCallbackHandler != null) {
+ if (mCallback != null) {
// We're updating the callback, clear the session from the old one.
- mCallbackHandler.mCallback.mSession = null;
- mCallbackHandler.removeCallbacksAndMessages(null);
+ mCallback.mCallback.mSession = null;
+ mCallback.removeCallbacksAndMessages(null);
}
if (callback == null) {
- mCallbackHandler = null;
+ mCallback = null;
return;
}
if (handler == null) {
@@ -209,7 +210,7 @@
callback.mSession = this;
CallbackMessageHandler msgHandler = new CallbackMessageHandler(handler.getLooper(),
callback);
- mCallbackHandler = msgHandler;
+ mCallback = msgHandler;
}
}
@@ -634,8 +635,8 @@
private void postToCallback(int what, Object obj, Bundle extras) {
synchronized (mLock) {
- if (mCallbackHandler != null) {
- mCallbackHandler.post(what, obj, extras);
+ if (mCallback != null) {
+ mCallback.post(what, obj, extras);
}
}
}
diff --git a/media/java/android/media/update/MediaBrowser2Provider.java b/media/java/android/media/update/MediaBrowser2Provider.java
index 17256a8..f2e7313 100644
--- a/media/java/android/media/update/MediaBrowser2Provider.java
+++ b/media/java/android/media/update/MediaBrowser2Provider.java
@@ -16,7 +16,6 @@
package android.media.update;
-import android.annotation.SystemApi;
import android.os.Bundle;
/**
@@ -29,6 +28,7 @@
void unsubscribe_impl(String parentId, Bundle options);
void getItem_impl(String mediaId);
- void getChildren_impl(String parentId, int page, int pageSize, Bundle options);
- void search_impl(String query, int page, int pageSize, Bundle extras);
+ void getChildren_impl(String parentId, int page, int pageSize, Bundle extras);
+ void search_impl(String query, Bundle options);
+ void getSearchResult_impl(String query, int page, int pageSize, Bundle extras);
}
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index d7f51d4..3518392 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -20,7 +20,7 @@
#include "android_media_MediaDrm.h"
#include "android_media_MediaMetricsJNI.h"
-
+#include "android_os_Parcel.h"
#include "android_runtime/AndroidRuntime.h"
#include "android_runtime/Log.h"
#include "android_os_Parcel.h"
@@ -29,12 +29,16 @@
#include <binder/IServiceManager.h>
#include <binder/Parcel.h>
+#include <binder/PersistableBundle.h>
#include <cutils/properties.h>
#include <media/IDrm.h>
#include <media/IMediaDrmService.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaErrors.h>
+using ::android::os::PersistableBundle;
+
+
namespace android {
#define FIND_CLASS(var, className) \
@@ -57,6 +61,10 @@
var = env->GetStaticMethodID(clazz, fieldName, fieldDescriptor); \
LOG_FATAL_IF(! (var), "Unable to find static method " fieldName);
+#define GET_STATIC_OBJECT_FIELD(var, clazz, fieldName) \
+ var = env->GetStaticObjectField(clazz, fieldName); \
+ LOG_FATAL_IF(! (var), "Unable to find static object field " fieldName);
+
struct RequestFields {
jfieldID data;
@@ -170,10 +178,58 @@
jclass hashmapClassId;
jclass arraylistClassId;
jclass stringClassId;
+ jobject bundleCreator;
+ jmethodID createFromParcelId;
+ jclass parcelCreatorClassId;
};
static fields_t gFields;
+namespace {
+
+// Helper function to convert a native PersistableBundle to a Java
+// PersistableBundle.
+jobject nativeToJavaPersistableBundle(JNIEnv *env, jobject thiz,
+ PersistableBundle* nativeBundle) {
+ if (env == NULL || thiz == NULL || nativeBundle == NULL) {
+ ALOGE("Unexpected NULL parmeter");
+ return NULL;
+ }
+
+ // Create a Java parcel with the native parcel data.
+ // Then create a new PersistableBundle with that parcel as a parameter.
+ jobject jParcel = android::createJavaParcelObject(env);
+ if (jParcel == NULL) {
+ ALOGE("Failed to create a Java Parcel.");
+ return NULL;
+ }
+
+ android::Parcel* nativeParcel = android::parcelForJavaObject(env, jParcel);
+ if (nativeParcel == NULL) {
+ ALOGE("Failed to get the native Parcel.");
+ return NULL;
+ }
+
+ android::status_t result = nativeBundle->writeToParcel(nativeParcel);
+ nativeParcel->setDataPosition(0);
+ if (result != android::OK) {
+ ALOGE("Failed to write nativeBundle to Parcel: %d.", result);
+ return NULL;
+ }
+
+ jobject newBundle = env->CallObjectMethod(gFields.bundleCreator,
+ gFields.createFromParcelId,
+ jParcel);
+ if (newBundle == NULL) {
+ ALOGE("Failed to create a new PersistableBundle "
+ "from the createFromParcel call.");
+ }
+
+ return newBundle;
+}
+
+} // namespace anonymous
+
// ----------------------------------------------------------------------------
// ref-counted object for callbacks
class JNIDrmListener: public DrmListener
@@ -713,6 +769,19 @@
GET_FIELD_ID(gFields.certificate.certificateData, clazz, "mCertificateData", "[B");
gFields.certificateClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
+ // Metrics-related fields and classes.
+ FIND_CLASS(clazz, "android/os/PersistableBundle");
+ jfieldID bundleCreatorId;
+ GET_STATIC_FIELD_ID(bundleCreatorId, clazz, "CREATOR",
+ "Landroid/os/Parcelable$Creator;");
+ jobject bundleCreator;
+ GET_STATIC_OBJECT_FIELD(bundleCreator, clazz, bundleCreatorId);
+ gFields.bundleCreator = static_cast<jobject>(env->NewGlobalRef(bundleCreator));
+ FIND_CLASS(clazz, "android/os/Parcelable$Creator");
+ GET_METHOD_ID(gFields.createFromParcelId, clazz, "createFromParcel",
+ "(Landroid/os/Parcel;)Ljava/lang/Object;");
+ gFields.parcelCreatorClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
+
FIND_CLASS(clazz, "java/util/ArrayList");
GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z");
@@ -1656,19 +1725,14 @@
}
// Retrieve current metrics snapshot from drm.
- MediaAnalyticsItem item ;
- status_t err = drm->getMetrics(&item);
+ PersistableBundle metrics;
+ status_t err = drm->getMetrics(&metrics);
if (err != OK) {
ALOGE("getMetrics failed: %d", (int)err);
return (jobject) NULL;
}
- jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, &item, NULL);
- if (mybundle == NULL) {
- ALOGE("getMetrics metric conversion failed");
- }
-
- return mybundle;
+ return nativeToJavaPersistableBundle(env, thiz, &metrics);
}
static jbyteArray android_media_MediaDrm_signRSANative(
diff --git a/media/jni/android_media_MediaPlayer2.cpp b/media/jni/android_media_MediaPlayer2.cpp
index e73b2f8..51bc330 100644
--- a/media/jni/android_media_MediaPlayer2.cpp
+++ b/media/jni/android_media_MediaPlayer2.cpp
@@ -28,6 +28,7 @@
#include <media/NdkWrapper.h>
#include <media/stagefright/Utils.h>
#include <media/stagefright/foundation/ByteUtils.h> // for FOURCC definition
+#include <mediaplayer2/JAudioTrack.h>
#include <mediaplayer2/mediaplayer2.h>
#include <stdio.h>
#include <assert.h>
@@ -1387,6 +1388,65 @@
// AudioRouting end
// ----------------------------------------------------------------------------
+/////////////////////////////////////////////////////////////////////////////////////
+// AudioTrack.StreamEventCallback begin
+static void android_media_MediaPlayer2_native_on_tear_down(JNIEnv *env __unused,
+ jobject thiz __unused, jlong callbackPtr, jlong userDataPtr)
+{
+ JAudioTrack::callback_t callback = (JAudioTrack::callback_t) callbackPtr;
+ if (callback != NULL) {
+ callback(JAudioTrack::EVENT_NEW_IAUDIOTRACK, (void *) userDataPtr, NULL);
+ }
+}
+
+static void android_media_MediaPlayer2_native_on_stream_presentation_end(JNIEnv *env __unused,
+ jobject thiz __unused, jlong callbackPtr, jlong userDataPtr)
+{
+ JAudioTrack::callback_t callback = (JAudioTrack::callback_t) callbackPtr;
+ if (callback != NULL) {
+ callback(JAudioTrack::EVENT_STREAM_END, (void *) userDataPtr, NULL);
+ }
+}
+
+static void android_media_MediaPlayer2_native_on_stream_data_request(JNIEnv *env __unused,
+ jobject thiz __unused, jlong jAudioTrackPtr, jlong callbackPtr, jlong userDataPtr)
+{
+ JAudioTrack::callback_t callback = (JAudioTrack::callback_t) callbackPtr;
+ JAudioTrack* track = (JAudioTrack *) jAudioTrackPtr;
+ if (callback != NULL && track != NULL) {
+ JAudioTrack::Buffer* buffer = new JAudioTrack::Buffer();
+
+ size_t bufferSizeInFrames = track->frameCount();
+ audio_format_t format = track->format();
+
+ size_t bufferSizeInBytes;
+ if (audio_has_proportional_frames(format)) {
+ bufferSizeInBytes =
+ bufferSizeInFrames * audio_bytes_per_sample(format) * track->channelCount();
+ } else {
+ // See Javadoc of AudioTrack::getBufferSizeInFrames().
+ bufferSizeInBytes = bufferSizeInFrames;
+ }
+
+ uint8_t* byteBuffer = new uint8_t[bufferSizeInBytes];
+ buffer->mSize = bufferSizeInBytes;
+ buffer->mData = (void *) byteBuffer;
+
+ callback(JAudioTrack::EVENT_MORE_DATA, (void *) userDataPtr, buffer);
+
+ if (buffer->mSize > 0 && buffer->mData == byteBuffer) {
+ track->write(buffer->mData, buffer->mSize, true /* Blocking */);
+ }
+
+ delete[] byteBuffer;
+ delete buffer;
+ }
+}
+
+
+// AudioTrack.StreamEventCallback end
+// ----------------------------------------------------------------------------
+
static const JNINativeMethod gMethods[] = {
{
"nativeSetDataSource",
@@ -1443,6 +1503,11 @@
{"native_setOutputDevice", "(I)Z", (void *)android_media_MediaPlayer2_setOutputDevice},
{"native_getRoutedDeviceId", "()I", (void *)android_media_MediaPlayer2_getRoutedDeviceId},
{"native_enableDeviceCallback", "(Z)V", (void *)android_media_MediaPlayer2_enableDeviceCallback},
+
+ // StreamEventCallback for JAudioTrack
+ {"native_stream_event_onTearDown", "(JJ)V", (void *)android_media_MediaPlayer2_native_on_tear_down},
+ {"native_stream_event_onStreamPresentationEnd", "(JJ)V", (void *)android_media_MediaPlayer2_native_on_stream_presentation_end},
+ {"native_stream_event_onStreamDataRequest", "(JJJ)V", (void *)android_media_MediaPlayer2_native_on_stream_data_request},
};
// This function only registers the native methods
diff --git a/native/android/OWNERS b/native/android/OWNERS
new file mode 100644
index 0000000..11d4be4
--- /dev/null
+++ b/native/android/OWNERS
@@ -0,0 +1,11 @@
+set noparent
+
+per-file libandroid_net.map.txt=ek@google.com
+per-file libandroid_net.map.txt=jchalard@google.com
+per-file libandroid_net.map.txt=lorenzo@google.com
+per-file libandroid_net.map.txt=satk@google.com
+
+per-file net.c=ek@google.com
+per-file net.c=jchalard@google.com
+per-file net.c=lorenzo@google.com
+per-file net.c=satk@google.com
diff --git a/packages/CarrierDefaultApp/OWNERS b/packages/CarrierDefaultApp/OWNERS
new file mode 100644
index 0000000..7057ce6
--- /dev/null
+++ b/packages/CarrierDefaultApp/OWNERS
@@ -0,0 +1,12 @@
+tgunn@google.com
+breadley@google.com
+hallliu@google.com
+rgreenwalt@google.com
+mpq@google.com
+amitmahajan@google.com
+fionaxu@google.com
+jackyu@google.com
+jminjie@google.com
+satk@google.com
+shuoq@google.com
+refuhoo@google.com
\ No newline at end of file
diff --git a/packages/MtpDocumentsProvider/AndroidManifest.xml b/packages/MtpDocumentsProvider/AndroidManifest.xml
index c0a59b3..8d79f62 100644
--- a/packages/MtpDocumentsProvider/AndroidManifest.xml
+++ b/packages/MtpDocumentsProvider/AndroidManifest.xml
@@ -3,7 +3,6 @@
package="com.android.mtp"
android:sharedUserId="android.media">
<uses-feature android:name="android.hardware.usb.host" />
- <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.MANAGE_USB" />
<application android:label="@string/app_label">
<provider
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index 44f68ec..d73a5d7 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -3117,6 +3117,8 @@
private final Consumer<String> mCallback;
+ private boolean mIsTransformationStarted;
+
public DocumentTransformer(Context context, PrintJobInfo printJob,
MutexFileProvider fileProvider, PrintAttributes attributes,
Consumer<String> callback) {
@@ -3144,29 +3146,35 @@
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
- final IPdfEditor editor = IPdfEditor.Stub.asInterface(service);
- new AsyncTask<Void, Void, String>() {
- @Override
- protected String doInBackground(Void... params) {
- // It's OK to access the data members as they are
- // final and this code is the last one to touch
- // them as shredding is the very last step, so the
- // UI is not interactive at this point.
- try {
- doTransform(editor);
- updatePrintJob();
- return null;
- } catch (IOException | RemoteException | IllegalStateException e) {
- return e.toString();
+ // We might get several onServiceConnected if the service crashes and restarts.
+ // mIsTransformationStarted makes sure that we only try once.
+ if (!mIsTransformationStarted) {
+ final IPdfEditor editor = IPdfEditor.Stub.asInterface(service);
+ new AsyncTask<Void, Void, String>() {
+ @Override
+ protected String doInBackground(Void... params) {
+ // It's OK to access the data members as they are
+ // final and this code is the last one to touch
+ // them as shredding is the very last step, so the
+ // UI is not interactive at this point.
+ try {
+ doTransform(editor);
+ updatePrintJob();
+ return null;
+ } catch (IOException | RemoteException | IllegalStateException e) {
+ return e.toString();
+ }
}
- }
- @Override
- protected void onPostExecute(String error) {
- mContext.unbindService(DocumentTransformer.this);
- mCallback.accept(error);
- }
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ @Override
+ protected void onPostExecute(String error) {
+ mContext.unbindService(DocumentTransformer.this);
+ mCallback.accept(error);
+ }
+ }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+
+ mIsTransformationStarted = true;
+ }
}
@Override
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
index 7c2e55f..cf73aac 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
@@ -285,6 +285,11 @@
final int position = ((AdapterContextMenuInfo) menuInfo).position;
PrinterInfo printer = (PrinterInfo) mListView.getAdapter().getItem(position);
+ // Printer is null if this is a context menu for the "add printer" entry
+ if (printer == null) {
+ return;
+ }
+
menu.setHeaderTitle(printer.getName());
// Add the select menu item if applicable.
diff --git a/packages/SettingsLib/res/drawable/ic_bt_hearing_aid.xml b/packages/SettingsLib/res/drawable/ic_bt_hearing_aid.xml
new file mode 100644
index 0000000..e14c99b
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_bt_hearing_aid.xml
@@ -0,0 +1,24 @@
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M17,20c-0.29,0 -0.56,-0.06 -0.76,-0.15 -0.71,-0.37 -1.21,-0.88 -1.71,-2.38 -0.51,-1.56 -1.47,-2.29 -2.39,-3 -0.79,-0.61 -1.61,-1.24 -2.32,-2.53C9.29,10.98 9,9.93 9,9c0,-2.8 2.2,-5 5,-5s5,2.2 5,5h2c0,-3.93 -3.07,-7 -7,-7S7,5.07 7,9c0,1.26 0.38,2.65 1.07,3.9 0.91,1.65 1.98,2.48 2.85,3.15 0.81,0.62 1.39,1.07 1.71,2.05 0.6,1.82 1.37,2.84 2.73,3.55 0.51,0.23 1.07,0.35 1.64,0.35 2.21,0 4,-1.79 4,-4h-2c0,1.1 -0.9,2 -2,2zM7.64,2.64L6.22,1.22C4.23,3.21 3,5.96 3,9s1.23,5.79 3.22,7.78l1.41,-1.41C6.01,13.74 5,11.49 5,9s1.01,-4.74 2.64,-6.36zM11.5,9c0,1.38 1.12,2.5 2.5,2.5s2.5,-1.12 2.5,-2.5 -1.12,-2.5 -2.5,-2.5 -2.5,1.12 -2.5,2.5z"/>
+</vector>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index fa6006e..dda6799 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -53,16 +53,25 @@
<string name="bluetooth_disconnected" msgid="6557104142667339895">"Déconnecté"</string>
<string name="bluetooth_disconnecting" msgid="8913264760027764974">"Déconnexion…"</string>
<string name="bluetooth_connecting" msgid="8555009514614320497">"Connexion en cours…"</string>
- <string name="bluetooth_connected" msgid="6038755206916626419">"Connecté"</string>
+ <!-- no translation found for bluetooth_connected (5427152882755735944) -->
+ <skip />
<string name="bluetooth_pairing" msgid="1426882272690346242">"Association…"</string>
- <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Connecté (sans audio pour appels tél.)"</string>
- <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Connecté (sans audio contenu mutimédia)"</string>
- <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Connecté (sans accès aux messages)"</string>
- <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Connecté (sans audio tel./multimédia)"</string>
- <string name="bluetooth_connected_battery_level" msgid="7049181126136692368">"Connecté. Pile : <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
- <string name="bluetooth_connected_no_headset_battery_level" msgid="5504193961248406027">"Connecté (sans téléphone). Pile : <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
- <string name="bluetooth_connected_no_a2dp_battery_level" msgid="4751724026365870779">"Connecté (sans média). Pile : <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
- <string name="bluetooth_connected_no_headset_no_a2dp_battery_level" msgid="1549265779323455261">"Connecté (sans téléphone ni média). Pile : <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for bluetooth_connected_no_headset (616068069034994802) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp (3736431800395923868) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_map (3200033913678466453) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp (2047403011284187056) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_battery_level (5162924691231307748) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (1610296229139400266) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (3908466636369853652) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1163440823807659316) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Paramètres audio du support"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Appels téléphoniques"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Transfert de fichier"</string>
@@ -327,9 +336,12 @@
<item msgid="8280754435979370728">"Couleurs naturelles, comme l\'œil les voit"</item>
<item msgid="5363960654009010371">"Couleurs optimisées pour le contenu numérique"</item>
</string-array>
- <string name="inactive_apps_title" msgid="1317817863508274533">"Applications inactives"</string>
+ <!-- no translation found for inactive_apps_title (9042996804461901648) -->
+ <skip />
<string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Application inactive. Touchez ici pour l\'activer."</string>
<string name="inactive_app_active_summary" msgid="4174921824958516106">"Application active. Touchez ici pour la désactiver."</string>
+ <!-- no translation found for standby_bucket_summary (6567835350910684727) -->
+ <skip />
<string name="runningservices_settings_title" msgid="8097287939865165213">"Services en cours d\'exécution"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Afficher et contrôler les services en cours d\'exécution"</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"Mise en œuvre WebView"</string>
@@ -351,16 +363,34 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Correction des couleurs"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Cette fonctionnalité est expérimentale et peut affecter les performances."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Remplacé par <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only" msgid="845431008899029842">"Il reste environ <xliff:g id="TIME">^1</xliff:g>"</string>
- <string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Il reste environ <xliff:g id="TIME">^1</xliff:g> en fonction de votre usage"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">^1</xliff:g> jusqu\'à la charge complète"</string>
- <string name="power_remaining_duration_only_short" msgid="5329694252258605547">"Temps restant : <xliff:g id="TIME">^1</xliff:g>"</string>
- <string name="power_remaining_duration_only_short_enhanced" msgid="7450425624026394823">"Il reste <xliff:g id="TIME">^1</xliff:g> en fonction de votre usage"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">^1</xliff:g> : il reste environ <xliff:g id="TIME">^2</xliff:g>"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">^1</xliff:g> : il reste environ <xliff:g id="TIME">^2</xliff:g> en fonction de votre usage"</string>
- <string name="power_discharging_duration_short" msgid="4192244429001842403">"<xliff:g id="LEVEL">^1</xliff:g> – Temps restant : <xliff:g id="TIME">^2</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="845431008899029842">"Il reste environ <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Il reste environ <xliff:g id="TIME">%1$s</xliff:g> en fonction de votre usage"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> jusqu\'à la charge complète"</string>
+ <string name="power_remaining_duration_only_short" msgid="5329694252258605547">"Temps restant : <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_remaining_less_than_duration_only (5996752448813295329) -->
+ <skip />
+ <!-- no translation found for power_remaining_less_than_duration (7967078125657859046) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (6846716609975752316) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8884488700395194194) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (8168317165722752881) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (5957064378548718872) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (9055596817716471373) -->
+ <skip />
+ <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> : il reste environ <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> : il reste environ <xliff:g id="TIME">%2$s</xliff:g> en fonction de votre usage"</string>
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7679005631124015335) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (261050880878965621) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (2020049829798578618) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
- <string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">^1</xliff:g> : <xliff:g id="TIME">^2</xliff:g> jusqu\'à la charge complète"</string>
+ <string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> : <xliff:g id="TIME">%2$s</xliff:g> jusqu\'à la charge complète"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Inconnu"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Charge en cours…"</string>
<string name="battery_info_status_charging_lower" msgid="8689770213898117994">"en cours de charge"</string>
@@ -414,4 +444,12 @@
<string name="zen_mode_settings_summary_off" msgid="6119891445378113334">"Jamais"</string>
<string name="zen_interruption_level_priority" msgid="2078370238113347720">"Priorités seulement"</string>
<string name="zen_mode_and_condition" msgid="4927230238450354412">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
+ <!-- no translation found for zen_alarm_warning_indef (3007988140196673193) -->
+ <skip />
+ <!-- no translation found for zen_alarm_warning (6236690803924413088) -->
+ <skip />
+ <!-- no translation found for alarm_template (4996153414057676512) -->
+ <skip />
+ <!-- no translation found for alarm_template_far (3779172822607461675) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 48c7bec..a1cdb8c 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -53,16 +53,25 @@
<string name="bluetooth_disconnected" msgid="6557104142667339895">"Исклучено"</string>
<string name="bluetooth_disconnecting" msgid="8913264760027764974">"Се исклучува..."</string>
<string name="bluetooth_connecting" msgid="8555009514614320497">"Се поврзува..."</string>
- <string name="bluetooth_connected" msgid="6038755206916626419">"Поврзани"</string>
+ <!-- no translation found for bluetooth_connected (5427152882755735944) -->
+ <skip />
<string name="bluetooth_pairing" msgid="1426882272690346242">"Поврзување..."</string>
- <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Поврзани (без телефон)"</string>
- <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Поврзани (без медиуми)"</string>
- <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Поврзано (без порака за пристап)"</string>
- <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Поврзан (без телефон или медиуми)"</string>
- <string name="bluetooth_connected_battery_level" msgid="7049181126136692368">"Поврзан, ниво на батеријата <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
- <string name="bluetooth_connected_no_headset_battery_level" msgid="5504193961248406027">"Поврзан (освен телефонот), ниво на батеријата <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
- <string name="bluetooth_connected_no_a2dp_battery_level" msgid="4751724026365870779">"Поврзан (освен аудио-визуелните содржини), ниво на батеријата <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
- <string name="bluetooth_connected_no_headset_no_a2dp_battery_level" msgid="1549265779323455261">"Поврзан (освен телефонот и аудио-визуелните содржини), ниво на батеријата <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for bluetooth_connected_no_headset (616068069034994802) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp (3736431800395923868) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_map (3200033913678466453) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp (2047403011284187056) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_battery_level (5162924691231307748) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (1610296229139400266) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (3908466636369853652) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1163440823807659316) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Аудио на медиуми"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Телефонски повици"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Пренос на датотека"</string>
@@ -327,9 +336,12 @@
<item msgid="8280754435979370728">"Природни бои како што со гледаат со голо око"</item>
<item msgid="5363960654009010371">"Оптимизирани бои за дигитална содржина"</item>
</string-array>
- <string name="inactive_apps_title" msgid="1317817863508274533">"Неактивни апликации"</string>
+ <!-- no translation found for inactive_apps_title (9042996804461901648) -->
+ <skip />
<string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Неактивно. Допрете за да смените."</string>
<string name="inactive_app_active_summary" msgid="4174921824958516106">"Активно. Допрете за да смените."</string>
+ <!-- no translation found for standby_bucket_summary (6567835350910684727) -->
+ <skip />
<string name="runningservices_settings_title" msgid="8097287939865165213">"Активни услуги"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Погледнете и контролирајте услуги што се моментално активни"</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"Воведување WebView"</string>
@@ -351,16 +363,34 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Корекција на боја"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Функцијата е експериментална и може да влијае на изведбата."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Прескокнато според <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only" msgid="845431008899029842">"Преостануваат околу <xliff:g id="TIME">^1</xliff:g>"</string>
- <string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Уште околу <xliff:g id="TIME">^1</xliff:g> според користењето"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Преостануваат <xliff:g id="TIME">^1</xliff:g> дури се наполни целосно"</string>
- <string name="power_remaining_duration_only_short" msgid="5329694252258605547">"уште <xliff:g id="TIME">^1</xliff:g>"</string>
- <string name="power_remaining_duration_only_short_enhanced" msgid="7450425624026394823">"Уште <xliff:g id="TIME">^1</xliff:g> според користењето"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">^1</xliff:g> - уште околу <xliff:g id="TIME">^2</xliff:g>"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">^1</xliff:g> - уште околу <xliff:g id="TIME">^2</xliff:g> според користењето"</string>
- <string name="power_discharging_duration_short" msgid="4192244429001842403">"<xliff:g id="LEVEL">^1</xliff:g> - уште <xliff:g id="TIME">^2</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="845431008899029842">"Преостануваат околу <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Уште околу <xliff:g id="TIME">%1$s</xliff:g> според користењето"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Преостануваат <xliff:g id="TIME">%1$s</xliff:g> дури се наполни целосно"</string>
+ <string name="power_remaining_duration_only_short" msgid="5329694252258605547">"уште <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for power_remaining_less_than_duration_only (5996752448813295329) -->
+ <skip />
+ <!-- no translation found for power_remaining_less_than_duration (7967078125657859046) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (6846716609975752316) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8884488700395194194) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (8168317165722752881) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (5957064378548718872) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (9055596817716471373) -->
+ <skip />
+ <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - уште околу <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> - уште околу <xliff:g id="TIME">%2$s</xliff:g> според користењето"</string>
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7679005631124015335) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (261050880878965621) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (2020049829798578618) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
- <string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">^1</xliff:g> - <xliff:g id="TIME">^2</xliff:g> дури се наполни целосно"</string>
+ <string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> дури се наполни целосно"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Непознато"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Се полни"</string>
<string name="battery_info_status_charging_lower" msgid="8689770213898117994">"се полни"</string>
@@ -414,4 +444,12 @@
<string name="zen_mode_settings_summary_off" msgid="6119891445378113334">"Никогаш"</string>
<string name="zen_interruption_level_priority" msgid="2078370238113347720">"Само приоритетно"</string>
<string name="zen_mode_and_condition" msgid="4927230238450354412">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
+ <!-- no translation found for zen_alarm_warning_indef (3007988140196673193) -->
+ <skip />
+ <!-- no translation found for zen_alarm_warning (6236690803924413088) -->
+ <skip />
+ <!-- no translation found for alarm_template (4996153414057676512) -->
+ <skip />
+ <!-- no translation found for alarm_template_far (3779172822607461675) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 0a65c13..ecb73f0 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -53,16 +53,25 @@
<string name="bluetooth_disconnected" msgid="6557104142667339895">"Uzildi"</string>
<string name="bluetooth_disconnecting" msgid="8913264760027764974">"Uzilyapti…"</string>
<string name="bluetooth_connecting" msgid="8555009514614320497">"Ulanmoqda…"</string>
- <string name="bluetooth_connected" msgid="6038755206916626419">"Ulandi"</string>
+ <!-- no translation found for bluetooth_connected (5427152882755735944) -->
+ <skip />
<string name="bluetooth_pairing" msgid="1426882272690346242">"Biriktirilmoqda"</string>
- <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Ulandi (telefondan tashqari)"</string>
- <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Ulanildi (mediadan tashqari)"</string>
- <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Ulangan (xabarlarga kirib bo‘lmaydi)"</string>
- <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Ulangan (telefon yoki media qurilma emas)"</string>
- <string name="bluetooth_connected_battery_level" msgid="7049181126136692368">"Ulangan, batareya quvvati: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
- <string name="bluetooth_connected_no_headset_battery_level" msgid="5504193961248406027">"Ulangan (HSP/HFP dan tashqari), batareya quvvati: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
- <string name="bluetooth_connected_no_a2dp_battery_level" msgid="4751724026365870779">"Ulangan (A2DP dan tashqari), batareya quvvati: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
- <string name="bluetooth_connected_no_headset_no_a2dp_battery_level" msgid="1549265779323455261">"Ulangan (HSP/HFP/A2DP dan tashqari), batareya quvvati: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <!-- no translation found for bluetooth_connected_no_headset (616068069034994802) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp (3736431800395923868) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_map (3200033913678466453) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp (2047403011284187056) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_battery_level (5162924691231307748) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (1610296229139400266) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (3908466636369853652) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1163440823807659316) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Media audio"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Telefon chaqiruvlari"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Fayl uzatish"</string>
@@ -327,9 +336,12 @@
<item msgid="8280754435979370728">"Ko‘zga ko‘rinadigan tabiiy ranglar"</item>
<item msgid="5363960654009010371">"Raqamli kontentga moslashtirilgan ranglar"</item>
</string-array>
- <string name="inactive_apps_title" msgid="1317817863508274533">"Nofaol ilovalar"</string>
+ <!-- no translation found for inactive_apps_title (9042996804461901648) -->
+ <skip />
<string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Nofaol. O‘zgartirish uchun bu yerga bosing."</string>
<string name="inactive_app_active_summary" msgid="4174921824958516106">"Faol. O‘zgartirish uchun bu yerga bosing."</string>
+ <!-- no translation found for standby_bucket_summary (6567835350910684727) -->
+ <skip />
<string name="runningservices_settings_title" msgid="8097287939865165213">"Ishlab turgan ilovalar"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Ishlab turgan ilovalarni ko‘rish va boshqarish"</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView ta’minotchisi"</string>
@@ -351,16 +363,34 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Rangni tuzatish"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Bu funksiya tajribaviy bo‘lib, u qurilma unumdorligiga ta’sir qilishi mumkin."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> bilan almashtirildi"</string>
- <string name="power_remaining_duration_only" msgid="845431008899029842">"Taxminan <xliff:g id="TIME">^1</xliff:g> qoldi"</string>
- <string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Joriy holatda taxminan <xliff:g id="TIME">^1</xliff:g> qoldi"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"To‘lishiga <xliff:g id="TIME">^1</xliff:g> qoldi"</string>
- <string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">^1</xliff:g> qoldi"</string>
- <string name="power_remaining_duration_only_short_enhanced" msgid="7450425624026394823">"Joriy holatda <xliff:g id="TIME">^1</xliff:g> qoldi"</string>
- <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">^1</xliff:g> – taxminan <xliff:g id="TIME">^2</xliff:g> qoldi"</string>
- <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">^1</xliff:g> (joriy holatda taxminan <xliff:g id="TIME">^2</xliff:g> qoldi)"</string>
- <string name="power_discharging_duration_short" msgid="4192244429001842403">"<xliff:g id="LEVEL">^1</xliff:g> – <xliff:g id="TIME">^2</xliff:g> qoldi"</string>
+ <string name="power_remaining_duration_only" msgid="845431008899029842">"Taxminan <xliff:g id="TIME">%1$s</xliff:g> qoldi"</string>
+ <string name="power_remaining_duration_only_enhanced" msgid="5992456722677973678">"Joriy holatda taxminan <xliff:g id="TIME">%1$s</xliff:g> qoldi"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"To‘lishiga <xliff:g id="TIME">%1$s</xliff:g> qoldi"</string>
+ <string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> qoldi"</string>
+ <!-- no translation found for power_remaining_less_than_duration_only (5996752448813295329) -->
+ <skip />
+ <!-- no translation found for power_remaining_less_than_duration (7967078125657859046) -->
+ <skip />
+ <!-- no translation found for power_remaining_more_than_subtext (6846716609975752316) -->
+ <skip />
+ <!-- no translation found for power_remaining_only_more_than_subtext (8884488700395194194) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (8168317165722752881) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (5957064378548718872) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_only_shutdown_imminent (9055596817716471373) -->
+ <skip />
+ <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> – taxminan <xliff:g id="TIME">%2$s</xliff:g> qoldi"</string>
+ <string name="power_discharging_duration_enhanced" msgid="4401782117770255046">"<xliff:g id="LEVEL">%1$s</xliff:g> (joriy holatda taxminan <xliff:g id="TIME">%2$s</xliff:g> qoldi)"</string>
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (7679005631124015335) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (261050880878965621) -->
+ <skip />
+ <!-- no translation found for power_remaining_duration_shutdown_imminent (2020049829798578618) -->
+ <skip />
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
- <string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">^1</xliff:g> – <xliff:g id="TIME">^2</xliff:g> ichida to‘ladi"</string>
+ <string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> ichida to‘ladi"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Noma’lum"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Quvvat olmoqda"</string>
<string name="battery_info_status_charging_lower" msgid="8689770213898117994">"quvvat olmoqda"</string>
@@ -414,4 +444,12 @@
<string name="zen_mode_settings_summary_off" msgid="6119891445378113334">"Hech qachon"</string>
<string name="zen_interruption_level_priority" msgid="2078370238113347720">"Faqat muhimlari"</string>
<string name="zen_mode_and_condition" msgid="4927230238450354412">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
+ <!-- no translation found for zen_alarm_warning_indef (3007988140196673193) -->
+ <skip />
+ <!-- no translation found for zen_alarm_warning (6236690803924413088) -->
+ <skip />
+ <!-- no translation found for alarm_template (4996153414057676512) -->
+ <skip />
+ <!-- no translation found for alarm_template_far (3779172822607461675) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values/dimens.xml b/packages/SettingsLib/res/values/dimens.xml
index ddb49b6..7b09ef7 100644
--- a/packages/SettingsLib/res/values/dimens.xml
+++ b/packages/SettingsLib/res/values/dimens.xml
@@ -83,4 +83,12 @@
<dimen name="zen_mode_condition_detail_item_interline_spacing">4dp</dimen>
<!-- Zen mode panel: bottom padding, a bit less than qs_panel_padding -->
<dimen name="zen_mode_condition_detail_bottom_padding">4dp</dimen>
+
+ <!-- SignalDrawable -->
+ <dimen name="signal_icon_size">17dp</dimen>
+ <!-- How far to inset the rounded edges -->
+ <dimen name="stat_sys_mobile_signal_circle_inset">0.9dp</dimen>
+
+
+
</resources>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index e6f4ec6..c78f454 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -177,6 +177,11 @@
<!-- Bluetooth settings. Similar to bluetooth_profile_a2dp_high_quality, but used when the device supports high quality audio but we don't know which codec that will be used. -->
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec">HD audio</string>
+ <!-- Bluetooth settings. The user-visible string that is used whenever referring to the Hearing Aid profile. -->
+ <string name="bluetooth_profile_hearing_aid">Hearing Aid</string>
+ <!-- Bluetooth settings. Connection options screen. The summary for the Hearing Aid checkbox preference when Hearing Aid is connected. -->
+ <string name="bluetooth_hearing_aid_profile_summary_connected">Connected to Hearing Aid</string>
+
<!-- Bluetooth settings. Connection options screen. The summary for the A2DP checkbox preference when A2DP is connected. -->
<string name="bluetooth_a2dp_profile_summary_connected">Connected to media audio</string>
<!-- Bluetooth settings. Connection options screen. The summary for the headset checkbox preference when headset is connected. -->
@@ -214,6 +219,8 @@
for the HID checkbox preference that describes how checking it
will set the HID profile as preferred. -->
<string name="bluetooth_hid_profile_summary_use_for">Use for input</string>
+ <!-- Bluetooth settings. Connection options screen. The summary for the Hearing Aid checkbox preference that describes how checking it will set the Hearing Aid profile as preferred. -->
+ <string name="bluetooth_hearing_aid_profile_summary_use_for">Use for Hearing Aid</string>
<!-- Button text for accepting an incoming pairing request. [CHAR LIMIT=20] -->
<string name="bluetooth_pairing_accept">Pair</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 1f67dfb..9947dec 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -1,6 +1,7 @@
package com.android.settingslib;
import android.annotation.ColorInt;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
@@ -17,10 +18,13 @@
import android.location.LocationManager;
import android.net.ConnectivityManager;
import android.os.BatteryManager;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.print.PrintManager;
import android.provider.Settings;
+
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.UserIcons;
import com.android.settingslib.drawable.UserIconDrawable;
import com.android.settingslib.wrapper.LocationManagerWrapper;
@@ -30,6 +34,9 @@
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";
private static Signature[] sSystemSignature;
private static String sPermissionControllerPackageName;
@@ -37,11 +44,11 @@
private static String sSharedSystemSharedLibPackageName;
static final int[] WIFI_PIE = {
- com.android.internal.R.drawable.ic_wifi_signal_0,
- com.android.internal.R.drawable.ic_wifi_signal_1,
- com.android.internal.R.drawable.ic_wifi_signal_2,
- com.android.internal.R.drawable.ic_wifi_signal_3,
- com.android.internal.R.drawable.ic_wifi_signal_4
+ com.android.internal.R.drawable.ic_wifi_signal_0,
+ com.android.internal.R.drawable.ic_wifi_signal_1,
+ com.android.internal.R.drawable.ic_wifi_signal_2,
+ com.android.internal.R.drawable.ic_wifi_signal_3,
+ com.android.internal.R.drawable.ic_wifi_signal_4
};
public static void updateLocationEnabled(Context context, boolean enabled, int userId,
@@ -262,7 +269,7 @@
*/
public static boolean isSystemPackage(Resources resources, PackageManager pm, PackageInfo pkg) {
if (sSystemSignature == null) {
- sSystemSignature = new Signature[]{ getSystemSignature(pm) };
+ sSystemSignature = new Signature[]{getSystemSignature(pm)};
}
if (sPermissionControllerPackageName == null) {
sPermissionControllerPackageName = pm.getPermissionControllerPackageName();
@@ -274,7 +281,7 @@
sSharedSystemSharedLibPackageName = pm.getSharedSystemSharedLibraryPackageName();
}
return (sSystemSignature[0] != null
- && sSystemSignature[0].equals(getFirstSignature(pkg)))
+ && sSystemSignature[0].equals(getFirstSignature(pkg)))
|| pkg.packageName.equals(sPermissionControllerPackageName)
|| pkg.packageName.equals(sServicesSystemSharedLibPackageName)
|| pkg.packageName.equals(sSharedSystemSharedLibPackageName)
@@ -312,7 +319,6 @@
* Returns the Wifi icon resource for a given RSSI level.
*
* @param level The number of bars to show (0-4)
- *
* @throws IllegalArgumentException if an invalid RSSI level is given.
*/
public static int getWifiIconResource(int level) {
@@ -342,4 +348,19 @@
return !context.getSystemService(ConnectivityManager.class)
.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
}
+
+ /** Returns if the automatic storage management feature is turned on or not. **/
+ 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);
+ } catch (Resources.NotFoundException e) {
+ isDefaultOn = false;
+ }
+ return Settings.Secure.getInt(context.getContentResolver(),
+ Settings.Secure.AUTOMATIC_STORAGE_MANAGER_ENABLED,
+ isDefaultOn ? 1 : 0)
+ != 0;
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
new file mode 100644
index 0000000..8f9e4635
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
@@ -0,0 +1,235 @@
+/*
+ * 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.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothHearingAid;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothCodecConfig;
+import android.bluetooth.BluetoothCodecStatus;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothUuid;
+import android.content.Context;
+import android.os.ParcelUuid;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.settingslib.R;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class HearingAidProfile implements LocalBluetoothProfile {
+ private static final String TAG = "HearingAidProfile";
+ private static boolean V = true;
+
+ private Context mContext;
+
+ private BluetoothHearingAid mService;
+ private boolean mIsProfileReady;
+
+ private final LocalBluetoothAdapter mLocalAdapter;
+ private final CachedBluetoothDeviceManager mDeviceManager;
+
+ static final String NAME = "HearingAid";
+ private final LocalBluetoothProfileManager mProfileManager;
+
+ // Order of this profile in device profiles list
+ private static final int ORDINAL = 1;
+
+ // These callbacks run on the main thread.
+ private final class HearingAidServiceListener
+ implements BluetoothProfile.ServiceListener {
+
+ public void onServiceConnected(int profile, BluetoothProfile proxy) {
+ if (V) Log.d(TAG,"Bluetooth service connected");
+ mService = (BluetoothHearingAid) proxy;
+ // We just bound to the service, so refresh the UI for any connected HearingAid devices.
+ List<BluetoothDevice> deviceList = mService.getConnectedDevices();
+ while (!deviceList.isEmpty()) {
+ BluetoothDevice nextDevice = deviceList.remove(0);
+ CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice);
+ // we may add a new device here, but generally this should not happen
+ if (device == null) {
+ Log.w(TAG, "HearingAidProfile found new device: " + nextDevice);
+ device = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, nextDevice);
+ }
+ device.onProfileStateChanged(HearingAidProfile.this, BluetoothProfile.STATE_CONNECTED);
+ device.refresh();
+ }
+ mIsProfileReady=true;
+ }
+
+ public void onServiceDisconnected(int profile) {
+ if (V) Log.d(TAG,"Bluetooth service disconnected");
+ mIsProfileReady=false;
+ }
+ }
+
+ public boolean isProfileReady() {
+ return mIsProfileReady;
+ }
+
+ HearingAidProfile(Context context, LocalBluetoothAdapter adapter,
+ CachedBluetoothDeviceManager deviceManager,
+ LocalBluetoothProfileManager profileManager) {
+ mContext = context;
+ mLocalAdapter = adapter;
+ mDeviceManager = deviceManager;
+ mProfileManager = profileManager;
+ mLocalAdapter.getProfileProxy(context, new HearingAidServiceListener(),
+ BluetoothProfile.HEARING_AID);
+ }
+
+ public boolean isConnectable() {
+ return true;
+ }
+
+ public boolean isAutoConnectable() {
+ return true;
+ }
+
+ public List<BluetoothDevice> getConnectedDevices() {
+ if (mService == null) return new ArrayList<BluetoothDevice>(0);
+ return mService.getDevicesMatchingConnectionStates(
+ new int[] {BluetoothProfile.STATE_CONNECTED,
+ BluetoothProfile.STATE_CONNECTING,
+ BluetoothProfile.STATE_DISCONNECTING});
+ }
+
+ public boolean connect(BluetoothDevice device) {
+ if (mService == null) return false;
+ return mService.connect(device);
+ }
+
+ public boolean disconnect(BluetoothDevice device) {
+ if (mService == null) return false;
+ // Downgrade priority as user is disconnecting the hearing aid.
+ if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON){
+ mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+ }
+ return mService.disconnect(device);
+ }
+
+ public int getConnectionStatus(BluetoothDevice device) {
+ if (mService == null) {
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+ return mService.getConnectionState(device);
+ }
+
+ public boolean isPreferred(BluetoothDevice device) {
+ if (mService == null) return false;
+ return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
+ }
+
+ public int getPreferred(BluetoothDevice device) {
+ if (mService == null) return BluetoothProfile.PRIORITY_OFF;
+ return mService.getPriority(device);
+ }
+
+ public void setPreferred(BluetoothDevice device, boolean preferred) {
+ if (mService == null) return;
+ if (preferred) {
+ if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
+ mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+ }
+ } else {
+ mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
+ }
+ }
+
+ public int getVolume() {
+ if (mService == null) {
+ return 0;
+ }
+ return mService.getVolume();
+ }
+
+ public void setVolume(int volume) {
+ if (mService == null) {
+ return;
+ }
+ mService.setVolume(volume);
+ }
+
+ public long getHiSyncId(BluetoothDevice device) {
+ if (mService == null) {
+ return BluetoothHearingAid.HI_SYNC_ID_INVALID;
+ }
+ return mService.getHiSyncId(device);
+ }
+
+ public int getDeviceSide(BluetoothDevice device) {
+ if (mService == null) {
+ return BluetoothHearingAid.SIDE_LEFT;
+ }
+ return mService.getDeviceSide(device);
+ }
+
+ public int getDeviceMode(BluetoothDevice device) {
+ if (mService == null) {
+ return BluetoothHearingAid.MODE_MONAURAL;
+ }
+ return mService.getDeviceMode(device);
+ }
+
+ public String toString() {
+ return NAME;
+ }
+
+ public int getOrdinal() {
+ return ORDINAL;
+ }
+
+ public int getNameResource(BluetoothDevice device) {
+ return R.string.bluetooth_profile_hearing_aid;
+ }
+
+ public int getSummaryResourceForDevice(BluetoothDevice device) {
+ int state = getConnectionStatus(device);
+ switch (state) {
+ case BluetoothProfile.STATE_DISCONNECTED:
+ return R.string.bluetooth_hearing_aid_profile_summary_use_for;
+
+ case BluetoothProfile.STATE_CONNECTED:
+ return R.string.bluetooth_hearing_aid_profile_summary_connected;
+
+ default:
+ return Utils.getConnectionStateSummary(state);
+ }
+ }
+
+ public int getDrawableResource(BluetoothClass btClass) {
+ return R.drawable.ic_bt_hearing_aid;
+ }
+
+ protected void finalize() {
+ if (V) Log.d(TAG, "finalize()");
+ if (mService != null) {
+ try {
+ BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.HEARING_AID,
+ mService);
+ mService = null;
+ }catch (Throwable t) {
+ Log.w(TAG, "Error cleaning up Hearing Aid proxy", t);
+ }
+ }
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index 991d922..34a099c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -21,6 +21,7 @@
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothHeadsetClient;
+import android.bluetooth.BluetoothHearingAid;
import android.bluetooth.BluetoothHidHost;
import android.bluetooth.BluetoothMap;
import android.bluetooth.BluetoothMapClient;
@@ -91,6 +92,7 @@
private final PbapServerProfile mPbapProfile;
private final boolean mUsePbapPce;
private final boolean mUseMapClient;
+ private HearingAidProfile mHearingAidProfile;
/**
* Mapping from profile name, e.g. "HEADSET" to profile object.
@@ -143,10 +145,14 @@
//Create PBAP server profile
if(DEBUG) Log.d(TAG, "Adding local PBAP profile");
+
mPbapProfile = new PbapServerProfile(context);
addProfile(mPbapProfile, PbapServerProfile.NAME,
BluetoothPbap.ACTION_CONNECTION_STATE_CHANGED);
+ mHearingAidProfile = new HearingAidProfile(mContext, mLocalAdapter, mDeviceManager, this);
+ addProfile(mHearingAidProfile, HearingAidProfile.NAME,
+ BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
if (DEBUG) Log.d(TAG, "LocalBluetoothProfileManager construction complete");
}
@@ -254,6 +260,18 @@
"Warning: PBAP Client profile was previously added but the UUID is now missing.");
}
+ //Hearing Aid Client
+ if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HearingAid)) {
+ if (mHearingAidProfile == null) {
+ if(DEBUG) Log.d(TAG, "Adding local Hearing Aid profile");
+ mHearingAidProfile = new HearingAidProfile(mContext, mLocalAdapter, mDeviceManager, this);
+ addProfile(mHearingAidProfile, HearingAidProfile.NAME,
+ BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
+ }
+ } else if (mHearingAidProfile != null) {
+ Log.w(TAG, "Warning: Hearing Aid profile was previously added but the UUID is now missing.");
+ }
+
mEventManager.registerProfileIntentReceiver();
// There is no local SDP record for HID and Settings app doesn't control PBAP Server.
@@ -416,6 +434,10 @@
return mMapClientProfile;
}
+ public HearingAidProfile getHearingAidProfile() {
+ return mHearingAidProfile;
+ }
+
/**
* Fill in a list of LocalBluetoothProfile objects that are supported by
* the local device and the remote device.
@@ -515,6 +537,12 @@
removedProfiles.remove(mPbapClientProfile);
}
+ if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HearingAid) &&
+ mHearingAidProfile != null) {
+ profiles.add(mHearingAidProfile);
+ removedProfiles.remove(mHearingAidProfile);
+ }
+
if (DEBUG) {
Log.d(TAG,"New Profiles" + profiles.toString());
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java b/packages/SettingsLib/src/com/android/settingslib/graph/SignalDrawable.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java
rename to packages/SettingsLib/src/com/android/settingslib/graph/SignalDrawable.java
index 15ef742..846e30d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java
+++ b/packages/SettingsLib/src/com/android/settingslib/graph/SignalDrawable.java
@@ -12,7 +12,7 @@
* permissions and limitations under the License.
*/
-package com.android.systemui.statusbar.phone;
+package com.android.settingslib.graph;
import android.animation.ArgbEvaluator;
import android.annotation.IntRange;
@@ -36,7 +36,6 @@
import com.android.settingslib.R;
import com.android.settingslib.Utils;
-import com.android.systemui.qs.SlashDrawable;
public class SignalDrawable extends Drawable {
@@ -458,6 +457,7 @@
}
private final class SlashArtist {
+ private static final float CORNER_RADIUS = 1f;
// These values are derived in un-rotated (vertical) orientation
private static final float SLASH_WIDTH = 1.8384776f;
private static final float SLASH_HEIGHT = 22f;
@@ -478,7 +478,7 @@
void draw(int height, int width, @NonNull Canvas canvas, Paint paint) {
Matrix m = new Matrix();
- final float radius = scale(SlashDrawable.CORNER_RADIUS, width);
+ final float radius = scale(CORNER_RADIUS, width);
updateRect(
scale(LEFT, width),
scale(TOP, height),
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java b/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java
index 1a54d6a..b98f27e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java
@@ -76,6 +76,8 @@
protected Uri mForeverId;
private int mBucketIndex = -1;
+ @VisibleForTesting
+ protected NotificationManager mNotificationManager;
private AlarmManager mAlarmManager;
private int mUserId;
private boolean mAttached;
@@ -98,7 +100,7 @@
}
public Dialog createDialog() {
- NotificationManager noMan = (NotificationManager) mContext.
+ mNotificationManager = (NotificationManager) mContext.
getSystemService(Context.NOTIFICATION_SERVICE);
mForeverId = Condition.newId(mContext).appendPath("forever").build();
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
@@ -131,7 +133,8 @@
Slog.d(TAG, "Invalid manual condition: " + tag.condition);
}
// always triggers priority-only dnd with chosen condition
- noMan.setZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
+ mNotificationManager.setZenMode(
+ Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
getRealConditionId(tag.condition), TAG);
}
});
@@ -465,7 +468,16 @@
mZenAlarmWarning.setVisibility(warningText == null ? View.GONE : View.VISIBLE);
}
- private String computeAlarmWarningText(Condition condition) {
+ @VisibleForTesting
+ protected String computeAlarmWarningText(Condition condition) {
+ boolean allowAlarms = (mNotificationManager.getNotificationPolicy().priorityCategories
+ & NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS) != 0;
+
+ // don't show alarm warning if alarms are allowed to bypass dnd
+ if (allowAlarms) {
+ return null;
+ }
+
final long now = System.currentTimeMillis();
final long nextAlarm = getNextAlarm();
if (nextAlarm < now) {
@@ -483,14 +495,19 @@
if (warningRes == 0) {
return null;
}
+
+ return mContext.getResources().getString(warningRes, getTime(nextAlarm, now));
+ }
+
+ @VisibleForTesting
+ protected String getTime(long nextAlarm, long now) {
final boolean soon = (nextAlarm - now) < 24 * 60 * 60 * 1000;
final boolean is24 = DateFormat.is24HourFormat(mContext, ActivityManager.getCurrentUser());
final String skeleton = soon ? (is24 ? "Hm" : "hma") : (is24 ? "EEEHm" : "EEEhma");
final String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton);
final CharSequence formattedTime = DateFormat.format(pattern, nextAlarm);
final int templateRes = soon ? R.string.alarm_template : R.string.alarm_template_far;
- final String template = mContext.getResources().getString(templateRes, formattedTime);
- return mContext.getResources().getString(warningRes, template);
+ return mContext.getResources().getString(templateRes, formattedTime);
}
// used as the view tag on condition rows
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index f699440..b380ac5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -17,6 +17,7 @@
package com.android.settingslib.wifi;
import android.annotation.IntDef;
+import android.annotation.MainThread;
import android.annotation.Nullable;
import android.app.AppGlobals;
import android.content.Context;
@@ -42,6 +43,8 @@
import android.net.wifi.WifiNetworkScoreCache;
import android.net.wifi.hotspot2.PasspointConfiguration;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -57,6 +60,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.settingslib.R;
+import com.android.settingslib.utils.ThreadUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -68,7 +72,14 @@
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
-
+/**
+ * Represents a selectable Wifi Network for use in various wifi selection menus backed by
+ * {@link WifiTracker}.
+ *
+ * <p>An AccessPoint, which would be more fittingly named "WifiNetwork", is an aggregation of
+ * {@link ScanResult ScanResults} along with pertinent metadata (e.g. current connection info,
+ * network scores) required to successfully render the network to the user.
+ */
public class AccessPoint implements Comparable<AccessPoint> {
static final String TAG = "SettingsLib.AccessPoint";
@@ -288,11 +299,6 @@
mId = sLastId.incrementAndGet();
}
- AccessPoint(Context context, AccessPoint other) {
- mContext = context;
- copyFrom(other);
- }
-
AccessPoint(Context context, Collection<ScanResult> results) {
mContext = context;
@@ -346,33 +352,6 @@
}
/**
- * Copy accesspoint information. NOTE: We do not copy tag information because that is never
- * set on the internal copy.
- */
- void copyFrom(AccessPoint that) {
- this.ssid = that.ssid;
- this.bssid = that.bssid;
- this.security = that.security;
- this.mKey = that.mKey;
- this.networkId = that.networkId;
- this.pskType = that.pskType;
- this.mConfig = that.mConfig; //TODO: Watch out, this object is mutated.
- this.mRssi = that.mRssi;
- this.mInfo = that.mInfo;
- this.mNetworkInfo = that.mNetworkInfo;
- this.mScanResults.clear();
- this.mScanResults.addAll(that.mScanResults);
- this.mScoredNetworkCache.clear();
- this.mScoredNetworkCache.putAll(that.mScoredNetworkCache);
- this.mId = that.mId;
- this.mSpeed = that.mSpeed;
- this.mIsScoredNetworkMetered = that.mIsScoredNetworkMetered;
- this.mIsCarrierAp = that.mIsCarrierAp;
- this.mCarrierApEapType = that.mCarrierApEapType;
- this.mCarrierName = that.mCarrierName;
- }
-
- /**
* Returns a negative integer, zero, or a positive integer if this AccessPoint is less than,
* equal to, or greater than the other AccessPoint.
*
@@ -467,7 +446,7 @@
}
builder.append(",metered=").append(isMetered());
- if (WifiTracker.sVerboseLogging) {
+ if (isVerboseLoggingEnabled()) {
builder.append(",rssi=").append(mRssi);
builder.append(",scan cache size=").append(mScanResults.size());
}
@@ -546,7 +525,7 @@
mSpeed = generateAverageSpeedForSsid();
boolean changed = oldSpeed != mSpeed;
- if(WifiTracker.sVerboseLogging && changed) {
+ if(isVerboseLoggingEnabled() && changed) {
Log.i(TAG, String.format("%s: Set speed to %d", ssid, mSpeed));
}
return changed;
@@ -577,7 +556,7 @@
}
}
int speed = count == 0 ? Speed.NONE : totalSpeed / count;
- if (WifiTracker.sVerboseLogging) {
+ if (isVerboseLoggingEnabled()) {
Log.i(TAG, String.format("%s generated fallback speed is: %d", getSsidStr(), speed));
}
return roundToClosestSpeedEnum(speed);
@@ -913,7 +892,7 @@
}
}
- if (WifiTracker.sVerboseLogging) {
+ if (isVerboseLoggingEnabled()) {
summary.append(WifiUtils.buildLoggingSummary(this, config));
}
@@ -1070,12 +1049,12 @@
// Only update labels on visible rssi changes
updateSpeed();
if (mAccessPointListener != null) {
- mAccessPointListener.onLevelChanged(this);
+ ThreadUtils.postOnMainThread(() -> mAccessPointListener.onLevelChanged(this));
}
}
if (mAccessPointListener != null) {
- mAccessPointListener.onAccessPointChanged(this);
+ ThreadUtils.postOnMainThread(() -> mAccessPointListener.onAccessPointChanged(this));
}
if (!scanResults.isEmpty()) {
@@ -1123,10 +1102,10 @@
mNetworkInfo = null;
}
if (updated && mAccessPointListener != null) {
- mAccessPointListener.onAccessPointChanged(this);
+ ThreadUtils.postOnMainThread(() -> mAccessPointListener.onAccessPointChanged(this));
if (oldLevel != getLevel() /* current level */) {
- mAccessPointListener.onLevelChanged(this);
+ ThreadUtils.postOnMainThread(() -> mAccessPointListener.onLevelChanged(this));
}
}
@@ -1137,7 +1116,7 @@
mConfig = config;
networkId = config != null ? config.networkId : WifiConfiguration.INVALID_NETWORK_ID;
if (mAccessPointListener != null) {
- mAccessPointListener.onAccessPointChanged(this);
+ ThreadUtils.postOnMainThread(() -> mAccessPointListener.onAccessPointChanged(this));
}
}
@@ -1333,8 +1312,44 @@
return string;
}
+ /**
+ * Callbacks relaying changes to the AccessPoint representation.
+ *
+ * <p>All methods are invoked on the Main Thread.
+ */
public interface AccessPointListener {
- void onAccessPointChanged(AccessPoint accessPoint);
- void onLevelChanged(AccessPoint accessPoint);
+ /**
+ * Indicates a change to the externally visible state of the AccessPoint trigger by an
+ * update of ScanResults, saved configuration state, connection state, or score
+ * (labels/metered) state.
+ *
+ * <p>Clients should refresh their view of the AccessPoint to match the updated state when
+ * this is invoked. Overall this method is extraneous if clients are listening to
+ * {@link WifiTracker.WifiListener#onAccessPointsChanged()} callbacks.
+ *
+ * <p>Examples of changes include signal strength, connection state, speed label, and
+ * generally anything that would impact the summary string.
+ *
+ * @param accessPoint The accessPoint object the listener was registered on which has
+ * changed
+ */
+ @MainThread void onAccessPointChanged(AccessPoint accessPoint);
+
+ /**
+ * Indicates the "wifi pie signal level" has changed, retrieved via calls to
+ * {@link AccessPoint#getLevel()}.
+ *
+ * <p>This call is a subset of {@link #onAccessPointChanged(AccessPoint)} , hence is also
+ * extraneous if the client is already reacting to that or the
+ * {@link WifiTracker.WifiListener#onAccessPointsChanged()} callbacks.
+ *
+ * @param accessPoint The accessPoint object the listener was registered on whose level has
+ * changed
+ */
+ @MainThread void onLevelChanged(AccessPoint accessPoint);
+ }
+
+ private static boolean isVerboseLoggingEnabled() {
+ return WifiTracker.sVerboseLogging || Log.isLoggable(TAG, Log.VERBOSE);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index fac585e..ae544dd 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -15,6 +15,7 @@
*/
package com.android.settingslib.wifi;
+import android.annotation.AnyThread;
import android.annotation.MainThread;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -48,8 +49,6 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
-import android.util.SparseArray;
-import android.util.SparseIntArray;
import android.widget.Toast;
import com.android.settingslib.R;
@@ -58,6 +57,7 @@
import com.android.settingslib.core.lifecycle.events.OnDestroy;
import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;
+import com.android.settingslib.utils.ThreadUtils;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -88,8 +88,17 @@
return Log.isLoggable(TAG, Log.DEBUG);
}
- /** verbose logging flag. this flag is set thru developer debugging options
- * and used so as to assist with in-the-field WiFi connectivity debugging */
+ private static boolean isVerboseLoggingEnabled() {
+ return WifiTracker.sVerboseLogging || Log.isLoggable(TAG, Log.VERBOSE);
+ }
+
+ /**
+ * Verbose logging flag set thru developer debugging options and used so as to assist with
+ * in-the-field WiFi connectivity debugging.
+ *
+ * <p>{@link #isVerboseLoggingEnabled()} should be read rather than referencing this value
+ * directly, to ensure adb TAG level verbose settings are respected.
+ */
public static boolean sVerboseLogging;
// TODO: Allow control of this?
@@ -104,7 +113,6 @@
private final NetworkRequest mNetworkRequest;
private final AtomicBoolean mConnected = new AtomicBoolean(false);
private final WifiListener mListener;
- @VisibleForTesting MainHandler mMainHandler;
@VisibleForTesting WorkHandler mWorkHandler;
private HandlerThread mWorkThread;
@@ -113,35 +121,17 @@
@GuardedBy("mLock")
private boolean mRegistered;
- /**
- * The externally visible access point list.
- *
- * Updated using main handler. Clone of this collection is returned from
- * {@link #getAccessPoints()}
- */
- private final List<AccessPoint> mAccessPoints = new ArrayList<>();
-
- /**
- * The internal list of access points, synchronized on itself.
- *
- * Never exposed outside this class.
- */
+ /** The list of AccessPoints, aggregated visible ScanResults with metadata. */
@GuardedBy("mLock")
private final List<AccessPoint> mInternalAccessPoints = new ArrayList<>();
/**
* Synchronization lock for managing concurrency between main and worker threads.
*
- * <p>This lock should be held for all background work.
- * TODO(b/37674366): Remove the worker thread so synchronization is no longer necessary.
+ * <p>This lock should be held for all modifications to {@link #mInternalAccessPoints}.
*/
private final Object mLock = new Object();
- //visible to both worker and main thread.
- @GuardedBy("mLock")
- private final AccessPointListenerAdapter mAccessPointListenerAdapter
- = new AccessPointListenerAdapter();
-
private final HashMap<String, Integer> mSeenBssids = new HashMap<>();
// TODO(sghuman): Change this to be keyed on AccessPoint.getKey
@@ -161,6 +151,12 @@
@VisibleForTesting
Scanner mScanner;
+ /**
+ * Tracks whether fresh scan results have been received since scanning start.
+ *
+ * <p>If this variable is false, we will not evict the scan result cache or invoke callbacks
+ * so that we do not update the UI with stale data / clear out existing UI elements prematurely.
+ */
@GuardedBy("mLock")
private boolean mStaleScanResults = true;
@@ -209,12 +205,11 @@
NetworkScoreManager networkScoreManager,
IntentFilter filter) {
mContext = context;
- mMainHandler = new MainHandler(Looper.getMainLooper());
mWifiManager = wifiManager;
mListener = new WifiListenerWrapper(wifiListener);
mConnectivityManager = connectivityManager;
- // check if verbose logging has been turned on or off
+ // check if verbose logging developer option has been turned on or off
sVerboseLogging = (mWifiManager.getVerboseLoggingLevel() > 0);
mFilter = filter;
@@ -226,6 +221,7 @@
mNetworkScoreManager = networkScoreManager;
+ // TODO(sghuman): Remove this and create less hacky solution for testing
final HandlerThread workThread = new HandlerThread(TAG
+ "{" + Integer.toHexString(System.identityHashCode(this)) + "}",
Process.THREAD_PRIORITY_BACKGROUND);
@@ -238,6 +234,8 @@
* @param workThread substitute Handler thread, for testing purposes only
*/
@VisibleForTesting
+ // TODO(sghuman): Remove this method, this needs to happen in a factory method and be passed in
+ // during construction
void setWorkThread(HandlerThread workThread) {
mWorkThread = workThread;
mWorkHandler = new WorkHandler(workThread.getLooper());
@@ -270,32 +268,29 @@
mLastNetworkInfo = mConnectivityManager.getNetworkInfo(mWifiManager.getCurrentNetwork());
final List<ScanResult> newScanResults = mWifiManager.getScanResults();
- if (sVerboseLogging) {
+ if (isVerboseLoggingEnabled()) {
Log.i(TAG, "Fetched scan results: " + newScanResults);
}
List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
mInternalAccessPoints.clear();
updateAccessPointsLocked(newScanResults, configs);
-
- // Synchronously copy access points
- mMainHandler.removeMessages(MainHandler.MSG_ACCESS_POINT_CHANGED);
- mMainHandler.handleMessage(
- Message.obtain(mMainHandler, MainHandler.MSG_ACCESS_POINT_CHANGED));
- if (sVerboseLogging) {
- Log.i(TAG, "force update - external access point list:\n" + mAccessPoints);
- }
}
}
/**
* Temporarily stop scanning for wifi networks.
+ *
+ * <p>Sets {@link #mStaleScanResults} to true.
*/
- public void pauseScanning() {
+ private void pauseScanning() {
if (mScanner != null) {
mScanner.pause();
mScanner = null;
}
+ synchronized (mLock) {
+ mStaleScanResults = true;
+ }
}
/**
@@ -387,11 +382,9 @@
mRegistered = false;
}
unregisterScoreCache();
- pauseScanning();
+ pauseScanning(); // and set mStaleScanResults
mWorkHandler.removePendingMessages();
- mMainHandler.removePendingMessages();
- mStaleScanResults = true;
}
}
@@ -409,12 +402,19 @@
}
/**
- * Gets the current list of access points. Should be called from main thread, otherwise
- * expect inconsistencies
+ * Gets the current list of access points.
+ *
+ * <p>This method is can be called on an abitrary thread by clients, but is normally called on
+ * the UI Thread by the rendering App.
*/
- @MainThread
+ @AnyThread
public List<AccessPoint> getAccessPoints() {
- return new ArrayList<>(mAccessPoints);
+ // TODO(sghuman): Investigate how to eliminate or reduce the need for locking now that we
+ // have transitioned to a single worker thread model.
+
+ synchronized (mLock) {
+ return new ArrayList<>(mInternalAccessPoints);
+ }
}
public WifiManager getManager() {
@@ -447,6 +447,8 @@
}
private void handleResume() {
+ // TODO(sghuman): Investigate removing this and replacing it with a cache eviction call
+ // instead.
mScanResultCache.clear();
mSeenBssids.clear();
}
@@ -509,7 +511,7 @@
private void updateAccessPoints() {
List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
final List<ScanResult> newScanResults = mWifiManager.getScanResults();
- if (sVerboseLogging) {
+ if (isVerboseLoggingEnabled()) {
Log.i(TAG, "Fetched scan results: " + newScanResults);
}
@@ -524,11 +526,15 @@
* Update the internal list of access points.
*
* <p>Do not call directly (except for forceUpdate), use {@link #updateAccessPoints()} which
- * respects {@link #mStaleScanResults}.
+ * acquires the lock first.
*/
@GuardedBy("mLock")
private void updateAccessPointsLocked(final List<ScanResult> newScanResults,
List<WifiConfiguration> configs) {
+ // TODO(sghuman): Reduce the synchronization time by only holding the lock when
+ // modifying lists exposed to operations on the MainThread (getAccessPoints, stopTracking,
+ // startTracking, etc).
+
WifiConfiguration connectionConfig = null;
if (mLastInfo != null) {
connectionConfig = getWifiConfigurationForNetworkId(
@@ -634,7 +640,7 @@
mInternalAccessPoints.clear();
mInternalAccessPoints.addAll(accessPoints);
- mMainHandler.sendEmptyMessage(MainHandler.MSG_ACCESS_POINT_CHANGED);
+ conditionallyNotifyListeners();
}
@VisibleForTesting
@@ -650,7 +656,6 @@
}
}
final AccessPoint accessPoint = new AccessPoint(mContext, scanResults);
- accessPoint.setListener(mAccessPointListenerAdapter);
return accessPoint;
}
@@ -661,16 +666,17 @@
if (cache.get(i).matches(config)) {
AccessPoint ret = cache.remove(i);
ret.loadConfig(config);
+
return ret;
}
}
final AccessPoint accessPoint = new AccessPoint(mContext, config);
- accessPoint.setListener(mAccessPointListenerAdapter);
return accessPoint;
}
private void updateNetworkInfo(NetworkInfo networkInfo) {
- /* sticky broadcasts can call this when wifi is disabled */
+
+ /* Sticky broadcasts can call this when wifi is disabled */
if (!mWifiManager.isWifiEnabled()) {
clearAccessPointsAndConditionallyUpdate();
return;
@@ -681,6 +687,10 @@
if (DBG()) {
Log.d(TAG, "mLastNetworkInfo set: " + mLastNetworkInfo);
}
+
+ if(networkInfo.isConnected() != mConnected.getAndSet(networkInfo.isConnected())) {
+ mListener.onConnectedChanged();
+ }
}
WifiConfiguration connectionConfig = null;
@@ -711,18 +721,25 @@
}
}
- if (reorder) Collections.sort(mInternalAccessPoints);
- if (updated) mMainHandler.sendEmptyMessage(MainHandler.MSG_ACCESS_POINT_CHANGED);
+ if (reorder) {
+ Collections.sort(mInternalAccessPoints);
+ }
+ if (updated) {
+ conditionallyNotifyListeners();
+ }
}
}
+ /**
+ * Clears the access point list and conditionally invokes
+ * {@link WifiListener#onAccessPointsChanged()} if required (i.e. the list was not already
+ * empty).
+ */
private void clearAccessPointsAndConditionallyUpdate() {
synchronized (mLock) {
if (!mInternalAccessPoints.isEmpty()) {
mInternalAccessPoints.clear();
- if (!mMainHandler.hasMessages(MainHandler.MSG_ACCESS_POINT_CHANGED)) {
- mMainHandler.sendEmptyMessage(MainHandler.MSG_ACCESS_POINT_CHANGED);
- }
+ mListener.onAccessPointsChanged();
}
}
}
@@ -745,27 +762,26 @@
}
if (updated) {
Collections.sort(mInternalAccessPoints);
- mMainHandler.sendEmptyMessage(MainHandler.MSG_ACCESS_POINT_CHANGED);
+ conditionallyNotifyListeners();
}
}
}
- private void updateWifiState(int state) {
- mWorkHandler.obtainMessage(WorkHandler.MSG_UPDATE_WIFI_STATE, state, 0).sendToTarget();
- if (!mWifiManager.isWifiEnabled()) {
- clearAccessPointsAndConditionallyUpdate();
- }
- }
-
@VisibleForTesting
final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
+ // No work should be performed in this Receiver, instead all operations should be passed
+ // off to the WorkHandler to avoid concurrent modification exceptions.
+
String action = intent.getAction();
if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
- updateWifiState(intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
- WifiManager.WIFI_STATE_UNKNOWN));
+ mWorkHandler.obtainMessage(
+ WorkHandler.MSG_UPDATE_WIFI_STATE,
+ intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
+ WifiManager.WIFI_STATE_UNKNOWN),
+ 0).sendToTarget();
} else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action)) {
mWorkHandler
.obtainMessage(
@@ -778,12 +794,6 @@
mWorkHandler.sendEmptyMessage(WorkHandler.MSG_UPDATE_ACCESS_POINTS);
} else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
-
- if(mConnected.get() != info.isConnected()) {
- mConnected.set(info.isConnected());
- mMainHandler.sendEmptyMessage(MainHandler.MSG_CONNECTED_CHANGED);
- }
-
mWorkHandler.obtainMessage(WorkHandler.MSG_UPDATE_NETWORK_INFO, info)
.sendToTarget();
mWorkHandler.sendEmptyMessage(WorkHandler.MSG_UPDATE_ACCESS_POINTS);
@@ -808,68 +818,8 @@
}
@VisibleForTesting
- final class MainHandler extends Handler {
- @VisibleForTesting static final int MSG_CONNECTED_CHANGED = 0;
- @VisibleForTesting static final int MSG_WIFI_STATE_CHANGED = 1;
- @VisibleForTesting static final int MSG_ACCESS_POINT_CHANGED = 2;
- private static final int MSG_RESUME_SCANNING = 3;
- private static final int MSG_PAUSE_SCANNING = 4;
-
- public MainHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- if (mListener == null) {
- return;
- }
- switch (msg.what) {
- case MSG_CONNECTED_CHANGED:
- mListener.onConnectedChanged();
- break;
- case MSG_WIFI_STATE_CHANGED:
- mListener.onWifiStateChanged(msg.arg1);
- break;
- case MSG_ACCESS_POINT_CHANGED:
- // Only notify listeners of changes if we have fresh scan results, otherwise the
- // UI will be updated with stale results. We want to copy the APs regardless,
- // for instances where forceUpdate was invoked by the caller.
- if (mStaleScanResults) {
- copyAndNotifyListeners(false /*notifyListeners*/);
- } else {
- copyAndNotifyListeners(true /*notifyListeners*/);
- mListener.onAccessPointsChanged();
- }
- break;
- case MSG_RESUME_SCANNING:
- if (mScanner != null) {
- mScanner.resume();
- }
- break;
- case MSG_PAUSE_SCANNING:
- if (mScanner != null) {
- mScanner.pause();
- }
- synchronized (mLock) {
- mStaleScanResults = true;
- }
- break;
- }
- }
-
- void removePendingMessages() {
- removeMessages(MSG_ACCESS_POINT_CHANGED);
- removeMessages(MSG_CONNECTED_CHANGED);
- removeMessages(MSG_WIFI_STATE_CHANGED);
- removeMessages(MSG_PAUSE_SCANNING);
- removeMessages(MSG_RESUME_SCANNING);
- }
- }
-
- @VisibleForTesting
final class WorkHandler extends Handler {
- private static final int MSG_UPDATE_ACCESS_POINTS = 0;
+ @VisibleForTesting static final int MSG_UPDATE_ACCESS_POINTS = 0;
private static final int MSG_UPDATE_NETWORK_INFO = 1;
private static final int MSG_RESUME = 2;
private static final int MSG_UPDATE_WIFI_STATE = 3;
@@ -882,6 +832,8 @@
@Override
public void handleMessage(Message msg) {
+ // TODO(sghuman): Clean up synchronization to only be used when modifying collections
+ // exposed to the MainThread (through onStart, onStop, forceUpdate).
synchronized (mLock) {
processMessage(msg);
}
@@ -911,6 +863,7 @@
mScanner.resume();
}
} else {
+ clearAccessPointsAndConditionallyUpdate();
mLastInfo = null;
mLastNetworkInfo = null;
if (mScanner != null) {
@@ -920,8 +873,7 @@
mStaleScanResults = true;
}
}
- mMainHandler.obtainMessage(MainHandler.MSG_WIFI_STATE_CHANGED, msg.arg1, 0)
- .sendToTarget();
+ mListener.onWifiStateChanged(msg.arg1);
break;
}
}
@@ -1010,16 +962,26 @@
@Override
public void onWifiStateChanged(int state) {
+ if (isVerboseLoggingEnabled()) {
+ Log.i(TAG,
+ String.format("Invoking onWifiStateChanged callback with state %d", state));
+ }
mHandler.post(() -> mDelegatee.onWifiStateChanged(state));
}
@Override
public void onConnectedChanged() {
+ if (isVerboseLoggingEnabled()) {
+ Log.i(TAG, "Invoking onConnectedChanged callback");
+ }
mHandler.post(() -> mDelegatee.onConnectedChanged());
}
@Override
public void onAccessPointsChanged() {
+ if (isVerboseLoggingEnabled()) {
+ Log.i(TAG, "Invoking onAccessPointsChanged callback");
+ }
mHandler.post(() -> mDelegatee.onAccessPointsChanged());
}
}
@@ -1041,101 +1003,27 @@
void onWifiStateChanged(int state);
/**
- * Called when the connection state of wifi has changed and isConnected
- * should be called to get the updated state.
+ * Called when the connection state of wifi has changed and
+ * {@link WifiTracker#isConnected()} should be called to get the updated state.
*/
void onConnectedChanged();
/**
* Called to indicate the list of AccessPoints has been updated and
- * getAccessPoints should be called to get the latest information.
+ * {@link WifiTracker#getAccessPoints()} should be called to get the updated list.
*/
void onAccessPointsChanged();
}
/**
- * Helps capture notifications that were generated during AccessPoint modification. Used later
- * on by {@link #copyAndNotifyListeners(boolean)} to send notifications.
+ * Invokes {@link WifiListenerWrapper#onAccessPointsChanged()} if {@link #mStaleScanResults}
+ * is false.
*/
- private static class AccessPointListenerAdapter implements AccessPoint.AccessPointListener {
- static final int AP_CHANGED = 1;
- static final int LEVEL_CHANGED = 2;
-
- final SparseIntArray mPendingNotifications = new SparseIntArray();
-
- @Override
- public void onAccessPointChanged(AccessPoint accessPoint) {
- int type = mPendingNotifications.get(accessPoint.mId);
- mPendingNotifications.put(accessPoint.mId, type | AP_CHANGED);
+ private void conditionallyNotifyListeners() {
+ if (mStaleScanResults) {
+ return;
}
- @Override
- public void onLevelChanged(AccessPoint accessPoint) {
- int type = mPendingNotifications.get(accessPoint.mId);
- mPendingNotifications.put(accessPoint.mId, type | LEVEL_CHANGED);
- }
- }
-
- /**
- * Responsible for copying access points from {@link #mInternalAccessPoints} and notifying
- * accesspoint listeners.
- *
- * @param notifyListeners if true, accesspoint listeners are notified, otherwise notifications
- * dropped.
- */
- @MainThread
- private void copyAndNotifyListeners(boolean notifyListeners) {
- // Need to watch out for memory allocations on main thread.
- SparseArray<AccessPoint> oldAccessPoints = new SparseArray<>();
- SparseIntArray notificationMap = null;
- List<AccessPoint> updatedAccessPoints = new ArrayList<>();
-
- for (AccessPoint accessPoint : mAccessPoints) {
- oldAccessPoints.put(accessPoint.mId, accessPoint);
- }
-
- synchronized (mLock) {
- if (DBG()) {
- Log.d(TAG, "Starting to copy AP items on the MainHandler. Internal APs: "
- + mInternalAccessPoints);
- }
-
- if (notifyListeners) {
- notificationMap = mAccessPointListenerAdapter.mPendingNotifications.clone();
- }
-
- mAccessPointListenerAdapter.mPendingNotifications.clear();
-
- for (AccessPoint internalAccessPoint : mInternalAccessPoints) {
- AccessPoint accessPoint = oldAccessPoints.get(internalAccessPoint.mId);
- if (accessPoint == null) {
- accessPoint = new AccessPoint(mContext, internalAccessPoint);
- } else {
- accessPoint.copyFrom(internalAccessPoint);
- }
- updatedAccessPoints.add(accessPoint);
- }
- }
-
- mAccessPoints.clear();
- mAccessPoints.addAll(updatedAccessPoints);
-
- if (notificationMap != null && notificationMap.size() > 0) {
- for (AccessPoint accessPoint : updatedAccessPoints) {
- int notificationType = notificationMap.get(accessPoint.mId);
- AccessPoint.AccessPointListener listener = accessPoint.mAccessPointListener;
- if (notificationType == 0 || listener == null) {
- continue;
- }
-
- if ((notificationType & AccessPointListenerAdapter.AP_CHANGED) != 0) {
- listener.onAccessPointChanged(accessPoint);
- }
-
- if ((notificationType & AccessPointListenerAdapter.LEVEL_CHANGED) != 0) {
- listener.onLevelChanged(accessPoint);
- }
- }
- }
+ ThreadUtils.postOnMainThread(() -> mListener.onAccessPointsChanged());
}
}
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
index 1440311..54c02a2 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
@@ -113,38 +113,6 @@
}
@Test
- public void testCopyAccessPoint_dataShouldMatch() {
- WifiConfiguration configuration = createWifiConfiguration();
- configuration.meteredHint = true;
-
- NetworkInfo networkInfo =
- new NetworkInfo(ConnectivityManager.TYPE_WIFI, 2, "WIFI", "WIFI_SUBTYPE");
- AccessPoint originalAccessPoint = new AccessPoint(mContext, configuration);
- WifiInfo wifiInfo = new WifiInfo();
- wifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(configuration.SSID));
- wifiInfo.setBSSID(configuration.BSSID);
- originalAccessPoint.update(configuration, wifiInfo, networkInfo);
- AccessPoint copy = new AccessPoint(mContext, originalAccessPoint);
-
- assertThat(originalAccessPoint.getSsid().toString()).isEqualTo(copy.getSsid().toString());
- assertThat(originalAccessPoint.getBssid()).isEqualTo(copy.getBssid());
- assertThat(originalAccessPoint.getConfig()).isEqualTo(copy.getConfig());
- assertThat(originalAccessPoint.getSecurity()).isEqualTo(copy.getSecurity());
- assertThat(originalAccessPoint.isMetered()).isEqualTo(copy.isMetered());
- assertThat(originalAccessPoint.compareTo(copy) == 0).isTrue();
- }
-
- @Test
- public void testThatCopyAccessPoint_scanCacheShouldMatch() {
- AccessPoint original = createAccessPointWithScanResultCache();
- assertThat(original.getRssi()).isEqualTo(4);
- AccessPoint copy = new AccessPoint(mContext, createWifiConfiguration());
- assertThat(copy.getRssi()).isEqualTo(AccessPoint.UNREACHABLE_RSSI);
- copy.copyFrom(original);
- assertThat(original.getRssi()).isEqualTo(copy.getRssi());
- }
-
- @Test
public void testCompareTo_GivesActiveBeforeInactive() {
AccessPoint activeAp = new TestAccessPointBuilder(mContext).setActive(true).build();
AccessPoint inactiveAp = new TestAccessPointBuilder(mContext).setActive(false).build();
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
index 6be4936..0c49bb6 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
@@ -356,19 +356,14 @@
private void waitForHandlersToProcessCurrentlyEnqueuedMessages(WifiTracker tracker)
throws InterruptedException {
+ // TODO(sghuman): This should no longer be necessary in a single work handler model
+
CountDownLatch workerLatch = new CountDownLatch(1);
tracker.mWorkHandler.post(() -> {
workerLatch.countDown();
});
assertTrue("Latch timed out while waiting for WorkerHandler",
workerLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
-
- CountDownLatch mainLatch = new CountDownLatch(1);
- tracker.mMainHandler.post(() -> {
- mainLatch.countDown();
- });
- assertTrue("Latch timed out while waiting for MainHandler",
- mainLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
}
private void switchToNetwork2(WifiTracker tracker) throws InterruptedException {
@@ -390,38 +385,6 @@
}
@Test
- public void testAccessPointListenerSetWhenLookingUpUsingScanResults() {
- ScanResult scanResult = new ScanResult();
- scanResult.level = 123;
- scanResult.BSSID = "bssid-" + 111;
- scanResult.timestamp = SystemClock.elapsedRealtime() * 1000;
- scanResult.capabilities = "";
-
- WifiTracker tracker = new WifiTracker(
- InstrumentationRegistry.getTargetContext(), null, true, true);
-
- AccessPoint result = tracker.getCachedOrCreate(
- Collections.singletonList(scanResult), new ArrayList<AccessPoint>());
- assertTrue(result.mAccessPointListener != null);
- }
-
- @Test
- public void testAccessPointListenerSetWhenLookingUpUsingWifiConfiguration() {
- WifiConfiguration configuration = new WifiConfiguration();
- configuration.SSID = "test123";
- configuration.BSSID="bssid";
- configuration.networkId = 123;
- configuration.allowedKeyManagement = new BitSet();
- configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
-
- WifiTracker tracker = new WifiTracker(
- InstrumentationRegistry.getTargetContext(), null, true, true);
-
- AccessPoint result = tracker.getCachedOrCreate(configuration, new ArrayList<AccessPoint>());
- assertTrue(result.mAccessPointListener != null);
- }
-
- @Test
public void startAndStopTrackingShouldRegisterAndUnregisterScoreCache()
throws InterruptedException {
WifiTracker tracker = createMockedWifiTracker();
@@ -534,7 +497,6 @@
waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
}
- @FlakyTest
@Test
public void scoreCacheUpdateScoresShouldChangeSortOrder() throws InterruptedException {
WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
@@ -634,9 +596,9 @@
public void scoresShouldBeRequestedForNewScanResultOnly() throws InterruptedException {
// Scores can be requested together or serially depending on how the scan results are
// processed.
- mRequestScoresLatch = new CountDownLatch(2);
+ mRequestScoresLatch = new CountDownLatch(1);
WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
- mRequestScoresLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS);
+ assertTrue(mRequestScoresLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
mRequestedKeys.clear();
String ssid = "ssid3";
@@ -770,7 +732,7 @@
CountDownLatch ready = new CountDownLatch(1);
CountDownLatch latch = new CountDownLatch(1);
CountDownLatch lock = new CountDownLatch(1);
- tracker.mMainHandler.post(() -> {
+ tracker.mWorkHandler.post(() -> {
try {
ready.countDown();
lock.await();
@@ -781,12 +743,7 @@
});
// Enqueue messages
- tracker.mMainHandler.sendEmptyMessage(
- WifiTracker.MainHandler.MSG_ACCESS_POINT_CHANGED);
- tracker.mMainHandler.sendEmptyMessage(
- WifiTracker.MainHandler.MSG_CONNECTED_CHANGED);
- tracker.mMainHandler.sendEmptyMessage(
- WifiTracker.MainHandler.MSG_WIFI_STATE_CHANGED);
+ tracker.mWorkHandler.sendEmptyMessage(WifiTracker.WorkHandler.MSG_UPDATE_ACCESS_POINTS);
try {
ready.await(); // Make sure we have entered the first message handler
@@ -800,12 +757,9 @@
lock.countDown();
assertTrue("Latch timed out", latch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
- assertThat(tracker.mMainHandler.hasMessages(
- WifiTracker.MainHandler.MSG_ACCESS_POINT_CHANGED)).isFalse();
- assertThat(tracker.mMainHandler.hasMessages(
- WifiTracker.MainHandler.MSG_CONNECTED_CHANGED)).isFalse();
- assertThat(tracker.mMainHandler.hasMessages(
- WifiTracker.MainHandler.MSG_WIFI_STATE_CHANGED)).isFalse();
+ assertThat(tracker.mWorkHandler.hasMessages(
+ WifiTracker.WorkHandler.MSG_UPDATE_ACCESS_POINTS)).isFalse();
+ waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
verifyNoMoreInteractions(mockWifiListener);
}
@@ -862,7 +816,7 @@
mAccessPointsChangedLatch = new CountDownLatch(1);
tracker.mReceiver.onReceive(mContext, new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION));
- mAccessPointsChangedLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS);
+ assertTrue(mAccessPointsChangedLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
assertThat(tracker.getAccessPoints()).isEmpty();
diff --git a/packages/SettingsLib/tests/robotests/Android.mk b/packages/SettingsLib/tests/robotests/Android.mk
index 7cf7163..f5c42b6 100644
--- a/packages/SettingsLib/tests/robotests/Android.mk
+++ b/packages/SettingsLib/tests/robotests/Android.mk
@@ -12,12 +12,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-
############################################################
# SettingsLib Shell app just for Robolectric test target. #
############################################################
LOCAL_PATH := $(call my-dir)
-
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := SettingsLibShell
@@ -25,8 +23,7 @@
LOCAL_PRIVILEGED_MODULE := true
-LOCAL_RESOURCE_DIR := \
- $(LOCAL_PATH)/res
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_USE_AAPT2 := true
@@ -35,43 +32,44 @@
include $(BUILD_PACKAGE)
#############################################
-# SettingsLib Robolectric test target. #
+# SettingsLib Robolectric test target. #
#############################################
include $(CLEAR_VARS)
+LOCAL_MODULE := SettingsLibRoboTests
+
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-# Include the testing libraries (JUnit4 + Robolectric libs).
-LOCAL_STATIC_JAVA_LIBRARIES := \
- mockito-robolectric-prebuilt \
- platform-robolectric-android-all-stubs \
- truth-prebuilt
+LOCAL_JAVA_RESOURCE_DIRS := config
LOCAL_JAVA_LIBRARIES := \
- junit \
- platform-robolectric-3.6.1-prebuilt
+ robolectric_android-all-stub \
+ Robolectric_all-target \
+ mockito-robolectric-prebuilt \
+ truth-prebuilt
LOCAL_INSTRUMENTATION_FOR := SettingsLibShell
-LOCAL_MODULE := SettingsLibRoboTests
LOCAL_MODULE_TAGS := optional
include $(BUILD_STATIC_JAVA_LIBRARY)
#############################################################
-# SettingsLib runner target to run the previous target. #
+# SettingsLib runner target to run the previous target. #
#############################################################
include $(CLEAR_VARS)
LOCAL_MODULE := RunSettingsLibRoboTests
-LOCAL_SDK_VERSION := current
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- SettingsLibRoboTests
+LOCAL_JAVA_LIBRARIES := \
+ SettingsLibRoboTests \
+ robolectric_android-all-stub \
+ Robolectric_all-target \
+ mockito-robolectric-prebuilt \
+ truth-prebuilt
LOCAL_TEST_PACKAGE := SettingsLibShell
LOCAL_ROBOTEST_TIMEOUT := 36000
-include prebuilts/misc/common/robolectric/3.6.1/run_robotests.mk
+include external/robolectric-shadows/run_robotests.mk
\ No newline at end of file
diff --git a/packages/SettingsLib/tests/robotests/config/robolectric.properties b/packages/SettingsLib/tests/robotests/config/robolectric.properties
new file mode 100644
index 0000000..34a2a1a
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/config/robolectric.properties
@@ -0,0 +1,2 @@
+manifest=frameworks/base/packages/SettingsLib/tests/robotests/AndroidManifest.xml
+sdk=NEWEST_SDK
\ No newline at end of file
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/CustomEditTextPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/CustomEditTextPreferenceTest.java
index 7e37493..9d7f59a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/CustomEditTextPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/CustomEditTextPreferenceTest.java
@@ -31,11 +31,9 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
import org.robolectric.util.ReflectionHelpers;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class CustomEditTextPreferenceTest {
@Mock
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/DeviceInfoUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/DeviceInfoUtilsTest.java
index 82604f7..19a916c 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/DeviceInfoUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/DeviceInfoUtilsTest.java
@@ -25,10 +25,8 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class DeviceInfoUtilsTest {
private Context mContext;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/HelpUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/HelpUtilsTest.java
index fdc42bf..e153c3e 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/HelpUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/HelpUtilsTest.java
@@ -16,6 +16,13 @@
package com.android.settingslib;
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
@@ -27,6 +34,7 @@
import android.content.res.TypedArray;
import android.provider.Settings;
import android.view.MenuItem;
+
import com.android.internal.R;
import org.junit.Before;
@@ -37,20 +45,11 @@
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
/**
* Tests for {@link HelpUtils}.
*/
@RunWith(RobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class HelpUtilsTest {
private static final String TEST_HELP_URL = "intent:#Intent;action=com.android.test;end";
private static final String PACKAGE_NAME_KEY = "package-name-key";
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
index 64de635..5f60868 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
@@ -20,11 +20,8 @@
import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT;
import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_REMOTE_INPUT;
import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS;
-
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
-
import static com.google.common.truth.Truth.assertThat;
-
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doReturn;
@@ -43,12 +40,10 @@
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.robolectric.annotation.Config;
import java.util.Arrays;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class RestrictedLockUtilsTest {
@Mock
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedPreferenceHelperTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedPreferenceHelperTest.java
index 79d99f7..a8821ba 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedPreferenceHelperTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedPreferenceHelperTest.java
@@ -17,6 +17,12 @@
package com.android.settingslib;
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
import android.content.Context;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceViewHolder;
@@ -28,19 +34,10 @@
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.robolectric.annotation.Config;
-
-import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class RestrictedPreferenceHelperTest {
-
@Mock
private Context mContext;
@Mock
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SettingsLibRobolectricTestRunner.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SettingsLibRobolectricTestRunner.java
index df850be..8778ae9 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SettingsLibRobolectricTestRunner.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SettingsLibRobolectricTestRunner.java
@@ -15,6 +15,8 @@
*/
package com.android.settingslib;
+import android.annotation.NonNull;
+
import org.junit.runners.model.InitializationError;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
@@ -22,6 +24,8 @@
import org.robolectric.res.Fs;
import org.robolectric.res.ResourcePath;
+import java.net.MalformedURLException;
+import java.net.URL;
import java.util.List;
public class SettingsLibRobolectricTestRunner extends RobolectricTestRunner {
@@ -30,33 +34,40 @@
super(testClass);
}
+ /**
+ * We are going to create our own custom manifest so we can add multiple resource paths to it.
+ */
@Override
protected AndroidManifest getAppManifest(Config config) {
- // Using the manifest file's relative path, we can figure out the application directory.
- final String appRoot = "frameworks/base/packages/SettingsLib";
- final String manifestPath = appRoot + "/AndroidManifest.xml";
- final String resDir = appRoot + "/tests/robotests/res";
- final String assetsDir = appRoot + config.assetDir();
+ try {
+ // Using the manifest file's relative path, we can figure out the application directory.
+ final URL appRoot =
+ new URL("file:frameworks/base/packages/SettingsLib/tests/robotests");
+ final URL manifestPath = new URL(appRoot, "AndroidManifest.xml");
+ final URL resDir = new URL(appRoot, "res");
+ final URL assetsDir = new URL(appRoot, "assets");
- return new AndroidManifest(Fs.fileFromPath(manifestPath), Fs.fileFromPath(resDir),
- Fs.fileFromPath(assetsDir), "com.android.settingslib") {
- @Override
- public List<ResourcePath> getIncludedResourcePaths() {
- List<ResourcePath> paths = super.getIncludedResourcePaths();
- paths.add(new ResourcePath(
- null,
- Fs.fileFromPath("./frameworks/base/packages/SettingsLib/res"),
- null));
- paths.add(new ResourcePath(
- null,
- Fs.fileFromPath("./frameworks/base/core/res/res"),
- null));
- paths.add(new ResourcePath(
- null,
- Fs.fileFromPath("./frameworks/support/v7/appcompat/res"),
- null));
- return paths;
- }
- };
+ return new AndroidManifest(Fs.fromURL(manifestPath), Fs.fromURL(resDir),
+ Fs.fromURL(assetsDir), "com.android.settingslib") {
+ @Override
+ public List<ResourcePath> getIncludedResourcePaths() {
+ final List<ResourcePath> paths = super.getIncludedResourcePaths();
+ paths.add(resourcePath("file:frameworks/base/packages/SettingsLib/res"));
+ paths.add(resourcePath("file:frameworks/base/core/res/res"));
+ paths.add(resourcePath("file:frameworks/support/v7/appcompat/res"));
+ return paths;
+ }
+ };
+ } catch (MalformedURLException e) {
+ throw new RuntimeException("SettingsLibRobolectricTestRunner failure", e);
+ }
+ }
+
+ private static ResourcePath resourcePath(@NonNull String spec) {
+ try {
+ return new ResourcePath(null, Fs.fromURL(new URL(spec)), null);
+ } catch (MalformedURLException e) {
+ throw new RuntimeException("SettingsLibRobolectricTestRunner failure", e);
+ }
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TestConfig.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TestConfig.java
deleted file mode 100644
index 1f9070c..0000000
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TestConfig.java
+++ /dev/null
@@ -1,25 +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.settingslib;
-
-import android.os.Build;
-
-public class TestConfig {
- public static final int SDK_VERSION = Build.VERSION_CODES.O;
- public static final String MANIFEST_PATH =
- "frameworks/base/packages/SettingsLib/tests/robotests/AndroidManifest.xml";
-}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TetherUtilTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TetherUtilTest.java
index 8bd31d4..0109f48 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TetherUtilTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TetherUtilTest.java
@@ -16,6 +16,8 @@
package com.android.settingslib;
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.when;
import android.content.Context;
@@ -24,13 +26,8 @@
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.robolectric.annotation.Config;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.when;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class TetherUtilTest {
@Mock
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TwoTargetPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TwoTargetPreferenceTest.java
index b5ee5ad..c5e93f0 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TwoTargetPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TwoTargetPreferenceTest.java
@@ -31,10 +31,8 @@
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class TwoTargetPreferenceTest {
private PreferenceViewHolder mViewHolder;
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 5459fb7..706d0c0 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
@@ -16,6 +16,9 @@
package com.android.settingslib;
import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
+
+import static com.android.settingslib.Utils.STORAGE_MANAGER_SHOW_OPT_IN_PROPERTY;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Matchers.eq;
@@ -30,13 +33,14 @@
import android.content.Intent;
import android.content.res.Resources;
import android.location.LocationManager;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;
import android.provider.Settings.Secure;
import android.text.TextUtils;
+
import com.android.settingslib.wrapper.LocationManagerWrapper;
-import java.util.HashMap;
-import java.util.Map;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -50,11 +54,11 @@
import org.robolectric.annotation.Implements;
import org.robolectric.shadows.ShadowSettings;
+import java.util.HashMap;
+import java.util.Map;
+
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(
- manifest = TestConfig.MANIFEST_PATH,
- sdk = TestConfig.SDK_VERSION,
- shadows = {
+@Config(shadows = {
UtilsTest.ShadowSecure.class,
UtilsTest.ShadowLocationManagerWrapper.class})
public class UtilsTest {
@@ -136,7 +140,7 @@
}
@Test
- public void testStorageManagerDaysToRetainUsesResources() {
+ public void testGetDefaultStorageManagerDaysToRetain_storageManagerDaysToRetainUsesResources() {
Resources resources = mock(Resources.class);
when(resources.getInteger(
eq(
@@ -149,6 +153,12 @@
assertThat(Utils.getDefaultStorageManagerDaysToRetain(resources)).isEqualTo(60);
}
+ @Test
+ public void testIsStorageManagerEnabled_UsesSystemProperties() {
+ SystemProperties.set(STORAGE_MANAGER_SHOW_OPT_IN_PROPERTY, "false");
+ assertThat(Utils.isStorageManagerEnabled(mContext)).isTrue();
+ }
+
private static ArgumentMatcher<Intent> actionMatches(String expected) {
return intent -> TextUtils.equals(expected, intent.getAction());
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ServiceListingTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ServiceListingTest.java
index fa31a7d..060b716 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ServiceListingTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ServiceListingTest.java
@@ -17,7 +17,6 @@
package com.android.settingslib.applications;
import static com.google.common.truth.Truth.assertThat;
-
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
@@ -27,24 +26,17 @@
import android.provider.Settings;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
-import com.android.settingslib.TestConfig;
-import com.android.settingslib.testutils.shadow.ShadowPackageManagerWrapper;
-import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION,
- shadows = {ShadowPackageManagerWrapper.class})
public class ServiceListingTest {
private static final String TEST_SETTING = "testSetting";
private static final String TEST_INTENT = "com.example.intent";
- private static final String TEST_PERMISSION = "testPermission";
private ServiceListing mServiceListing;
@@ -59,11 +51,6 @@
.build();
}
- @After
- public void tearDown() {
- ShadowPackageManagerWrapper.reset();
- }
-
@Test
public void testCallback() {
ServiceListing.Callback callback = mock(ServiceListing.Callback.class);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java
index 590bc90..334ea16 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java
@@ -15,6 +15,13 @@
*/
package com.android.settingslib.bluetooth;
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothCodecConfig;
import android.bluetooth.BluetoothCodecStatus;
@@ -24,30 +31,16 @@
import android.content.res.Resources;
import com.android.settingslib.R;
-import com.android.settingslib.TestConfig;
import com.android.settingslib.wrapper.BluetoothA2dpWrapper;
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 org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
@RunWith(RobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class A2dpProfileTest {
@Mock Context mContext;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index 1481161..92c68e6 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -16,7 +16,6 @@
package com.android.settingslib.bluetooth;
import static com.google.common.truth.Truth.assertThat;
-
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doAnswer;
@@ -30,9 +29,6 @@
import android.bluetooth.BluetoothProfile;
import android.content.Context;
-import com.android.settingslib.R;
-import com.android.settingslib.TestConfig;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -43,8 +39,7 @@
import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION, resourceDir =
- "../../res")
+@Config(resourceDir = "../../res")
public class CachedBluetoothDeviceTest {
private final static String DEVICE_NAME = "TestName";
private final static String DEVICE_ALIAS = "TestAlias";
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/UtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/UtilsTest.java
index 5eb543b..baba267 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/UtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/UtilsTest.java
@@ -22,18 +22,13 @@
import com.android.settingslib.R;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
-import com.android.settingslib.TestConfig;
import com.android.settingslib.graph.BluetoothDeviceLayerDrawable;
-import com.android.settingslib.testutils.shadow.SettingsLibShadowResources;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION,
- shadows = SettingsLibShadowResources.class)
public class UtilsTest {
@Test
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/AbstractPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/AbstractPreferenceControllerTest.java
index 26970e1..8767923 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/AbstractPreferenceControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/AbstractPreferenceControllerTest.java
@@ -22,8 +22,6 @@
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
-import com.android.settingslib.TestConfig;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -31,10 +29,8 @@
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class AbstractPreferenceControllerTest {
@Mock
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java
index 8bea51d..5c19e61 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java
@@ -28,7 +28,6 @@
import android.util.Pair;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.settingslib.TestConfig;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
import org.junit.Before;
@@ -39,14 +38,12 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
import org.robolectric.util.ReflectionHelpers;
import java.util.ArrayList;
import java.util.List;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class MetricsFeatureProviderTest {
private static int CATEGORY = 10;
private static boolean SUBTYPE_BOOLEAN = true;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SharedPreferenceLoggerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SharedPreferenceLoggerTest.java
index d558a64..ebafc59 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SharedPreferenceLoggerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SharedPreferenceLoggerTest.java
@@ -30,9 +30,7 @@
import android.content.SharedPreferences;
import android.util.Pair;
-import com.android.settingslib.TestConfig;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
-
import com.google.common.truth.Platform;
import org.junit.Before;
@@ -42,10 +40,8 @@
import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.robolectric.annotation.Config;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class SharedPreferenceLoggerTest {
private static final String TEST_TAG = "tag";
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixinTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixinTest.java
index 1ab6afe..8b31450 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixinTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixinTest.java
@@ -16,7 +16,6 @@
package com.android.settingslib.core.instrumentation;
import static com.android.settingslib.core.instrumentation.Instrumentable.METRICS_CATEGORY_UNKNOWN;
-
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
@@ -30,12 +29,11 @@
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
-
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
+
import com.android.internal.logging.nano.MetricsProto;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
-import com.android.settingslib.TestConfig;
import org.junit.Before;
import org.junit.Test;
@@ -44,11 +42,9 @@
import org.mockito.MockitoAnnotations;
import org.robolectric.Robolectric;
import org.robolectric.android.controller.ActivityController;
-import org.robolectric.annotation.Config;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class VisibilityLoggerMixinTest {
@Mock
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java
index ae24c07..2b2bf5b 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java
@@ -25,7 +25,6 @@
import android.view.MenuItem;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
-import com.android.settingslib.TestConfig;
import com.android.settingslib.core.lifecycle.events.OnAttach;
import com.android.settingslib.core.lifecycle.events.OnCreateOptionsMenu;
import com.android.settingslib.core.lifecycle.events.OnDestroy;
@@ -42,10 +41,8 @@
import org.robolectric.Robolectric;
import org.robolectric.android.controller.ActivityController;
import org.robolectric.android.controller.FragmentController;
-import org.robolectric.annotation.Config;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class LifecycleTest {
private LifecycleOwner mLifecycleOwner;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/DevelopmentSettingsEnablerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/DevelopmentSettingsEnablerTest.java
index 708353e..a15f5fc 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/DevelopmentSettingsEnablerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/DevelopmentSettingsEnablerTest.java
@@ -22,7 +22,6 @@
import android.provider.Settings;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
-import com.android.settingslib.TestConfig;
import com.android.settingslib.testutils.shadow.ShadowUserManager;
import org.junit.After;
@@ -33,9 +32,7 @@
import org.robolectric.annotation.Config;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION, shadows = {
- ShadowUserManager.class
-})
+@Config(shadows = ShadowUserManager.class)
public class DevelopmentSettingsEnablerTest {
private Context mContext;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/EnableAdbPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/EnableAdbPreferenceControllerTest.java
index aac736a..475e7d8 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/EnableAdbPreferenceControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/EnableAdbPreferenceControllerTest.java
@@ -31,18 +31,15 @@
import android.support.v7.preference.PreferenceScreen;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
-import com.android.settingslib.TestConfig;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowApplication;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class EnableAdbPreferenceControllerTest {
@Mock(answer = RETURNS_DEEP_STUBS)
private PreferenceScreen mScreen;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogdSizePreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogdSizePreferenceControllerTest.java
index 26d3570..72c8d1a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogdSizePreferenceControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogdSizePreferenceControllerTest.java
@@ -45,20 +45,15 @@
import com.android.settingslib.R;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
-import com.android.settingslib.TestConfig;
-import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION,
- shadows = SystemPropertiesTestImpl.class)
public class LogdSizePreferenceControllerTest {
@Mock
@@ -95,11 +90,6 @@
mController.displayPreference(mPreferenceScreen);
}
- @After
- public void tearDown() {
- SystemPropertiesTestImpl.clear();
- }
-
@Test
public void testUpdateLogdSizeValues_lowRamEntries() {
SystemProperties.set(LOW_RAM_CONFIG_PROPERTY_KEY, "true");
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogpersistPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogpersistPreferenceControllerTest.java
index 050877d..4b9bfc3 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogpersistPreferenceControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogpersistPreferenceControllerTest.java
@@ -28,7 +28,6 @@
import android.support.v7.preference.PreferenceScreen;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
-import com.android.settingslib.TestConfig;
import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.Before;
@@ -37,11 +36,8 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION,
- shadows = SystemPropertiesTestImpl.class)
public class LogpersistPreferenceControllerTest {
private LifecycleOwner mLifecycleOwner;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/SystemPropPokerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/SystemPropPokerTest.java
index fa7961b..40db478 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/SystemPropPokerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/SystemPropPokerTest.java
@@ -20,7 +20,6 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -29,7 +28,6 @@
import android.os.Parcel;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
-import com.android.settingslib.TestConfig;
import org.junit.Before;
import org.junit.Test;
@@ -37,10 +35,8 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
-import org.robolectric.annotation.Config;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class SystemPropPokerTest {
@Spy
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/SystemPropertiesTestImpl.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/SystemPropertiesTestImpl.java
deleted file mode 100644
index 6977e09..0000000
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/SystemPropertiesTestImpl.java
+++ /dev/null
@@ -1,61 +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.settingslib.development;
-
-import android.text.TextUtils;
-import android.util.ArrayMap;
-
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-import org.robolectric.shadows.ShadowSystemProperties;
-
-import java.util.Map;
-
-@Implements(className = "android.os.SystemProperties")
-public class SystemPropertiesTestImpl extends ShadowSystemProperties {
-
- private static Map<String, String> sProperties = new ArrayMap<>();
-
- @Implementation
- public static String get(String key) {
- String value = sProperties.get(key);
- if (!TextUtils.isEmpty(value)) {
- return value;
- } else {
- return ShadowSystemProperties.get(key);
- }
- }
-
- @Implementation
- public static String get(String key, String def) {
- String value = sProperties.get(key);
- if (!TextUtils.isEmpty(value)) {
- return value;
- } else {
- return ShadowSystemProperties.get(key, def);
- }
- }
-
- @Implementation
- public static void set(String key, String val) {
- sProperties.put(key, val);
- }
-
- public static synchronized void clear() {
- sProperties.clear();
- }
-}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/BluetoothAddressPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/BluetoothAddressPreferenceControllerTest.java
index 1de7a7a..0385f4b 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/BluetoothAddressPreferenceControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/BluetoothAddressPreferenceControllerTest.java
@@ -26,7 +26,6 @@
import android.support.v7.preference.PreferenceScreen;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
-import com.android.settingslib.TestConfig;
import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.Before;
@@ -39,7 +38,6 @@
import org.robolectric.annotation.Implements;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class BluetoothAddressPreferenceControllerTest {
@Mock
private Context mContext;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/ConnectivityPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/ConnectivityPreferenceControllerTest.java
index 362dbd9..7c127e5 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/ConnectivityPreferenceControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/ConnectivityPreferenceControllerTest.java
@@ -17,7 +17,6 @@
package com.android.settingslib.deviceinfo;
import static com.google.common.truth.Truth.assertWithMessage;
-
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.doReturn;
@@ -31,7 +30,6 @@
import android.os.Handler;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
-import com.android.settingslib.TestConfig;
import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.Before;
@@ -40,10 +38,8 @@
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.robolectric.annotation.Config;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class ConnectivityPreferenceControllerTest {
@Mock
private Context mContext;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/ImsStatusPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/ImsStatusPreferenceControllerTest.java
index 112ee64..d600c20 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/ImsStatusPreferenceControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/ImsStatusPreferenceControllerTest.java
@@ -17,7 +17,6 @@
package com.android.settingslib.deviceinfo;
import static com.google.common.truth.Truth.assertWithMessage;
-
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -30,7 +29,6 @@
import android.telephony.SubscriptionManager;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
-import com.android.settingslib.TestConfig;
import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.Before;
@@ -43,7 +41,6 @@
import org.robolectric.annotation.Implements;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class ImsStatusPreferenceControllerTest {
@Mock
private Context mContext;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/IpAddressPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/IpAddressPreferenceControllerTest.java
index d0ecae3..99e582c 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/IpAddressPreferenceControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/IpAddressPreferenceControllerTest.java
@@ -27,7 +27,6 @@
import android.support.v7.preference.PreferenceScreen;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
-import com.android.settingslib.TestConfig;
import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.Before;
@@ -35,13 +34,11 @@
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.robolectric.annotation.Config;
import java.util.Arrays;
import java.util.List;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class IpAddressPreferenceControllerTest {
@Mock
private Context mContext;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SerialNumberPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SerialNumberPreferenceControllerTest.java
index 34bbf4f..a4fa7aa 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SerialNumberPreferenceControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SerialNumberPreferenceControllerTest.java
@@ -24,7 +24,6 @@
import android.support.v7.preference.PreferenceScreen;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
-import com.android.settingslib.TestConfig;
import org.junit.Before;
import org.junit.Test;
@@ -32,10 +31,8 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class SerialNumberPreferenceControllerTest {
@Mock
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SimStatusImeiInfoPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SimStatusImeiInfoPreferenceControllerTest.java
index 28409fa..eaae405 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SimStatusImeiInfoPreferenceControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SimStatusImeiInfoPreferenceControllerTest.java
@@ -17,7 +17,6 @@
package com.android.settingslib.deviceinfo;
import static com.google.common.truth.Truth.assertThat;
-
import static org.robolectric.shadow.api.Shadow.extract;
import android.net.ConnectivityManager;
@@ -25,7 +24,6 @@
import android.util.SparseBooleanArray;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
-import com.android.settingslib.TestConfig;
import org.junit.Before;
import org.junit.Test;
@@ -36,8 +34,7 @@
import org.robolectric.annotation.Implements;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION,
- shadows = {SimStatusImeiInfoPreferenceControllerTest.ShadowUserManager.class,
+@Config(shadows = {SimStatusImeiInfoPreferenceControllerTest.ShadowUserManager.class,
SimStatusImeiInfoPreferenceControllerTest.ShadowConnectivityManager.class})
public class SimStatusImeiInfoPreferenceControllerTest {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/UptimePreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/UptimePreferenceControllerTest.java
index f68533b..39e05fa 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/UptimePreferenceControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/UptimePreferenceControllerTest.java
@@ -28,7 +28,6 @@
import android.text.format.DateUtils;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
-import com.android.settingslib.TestConfig;
import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.Before;
@@ -36,11 +35,9 @@
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowLooper;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class UptimePreferenceControllerTest {
@Mock
private Context mContext;
@@ -98,5 +95,4 @@
super(context, lifecycle);
}
}
-
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/WifiMacAddressPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/WifiMacAddressPreferenceControllerTest.java
index 265a60b..d546f11 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/WifiMacAddressPreferenceControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/WifiMacAddressPreferenceControllerTest.java
@@ -17,7 +17,6 @@
package com.android.settingslib.deviceinfo;
import static com.google.common.truth.Truth.assertWithMessage;
-
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -32,7 +31,6 @@
import com.android.settingslib.R;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
-import com.android.settingslib.TestConfig;
import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.Before;
@@ -40,14 +38,12 @@
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.robolectric.annotation.Config;
import java.util.Arrays;
import java.util.List;
@SuppressLint("HardwareIds")
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class WifiMacAddressPreferenceControllerTest {
@Mock
private Context mContext;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java
index 6be44cc..b90f37a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java
@@ -16,21 +16,17 @@
package com.android.settingslib.drawer;
-import android.util.ArraySet;
+import static com.google.common.truth.Truth.assertThat;
-import com.android.settingslib.TestConfig;
+import android.util.ArraySet;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
import java.util.Set;
-import static com.google.common.truth.Truth.assertThat;
-
@RunWith(RobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class CategoryKeyTest {
@Test
@@ -64,5 +60,4 @@
assertThat(allKeys.size()).isEqualTo(15);
}
-
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryManagerTest.java
index f099c90..4efcb7e 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryManagerTest.java
@@ -16,27 +16,24 @@
package com.android.settingslib.drawer;
+import static com.google.common.truth.Truth.assertThat;
+
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.util.Pair;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
-import com.android.settingslib.TestConfig;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowApplication;
import java.util.HashMap;
import java.util.Map;
-import static com.google.common.truth.Truth.assertThat;
-
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class CategoryManagerTest {
private Context mContext;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
index a395a4a..fc1b2238 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
@@ -17,7 +17,6 @@
package com.android.settingslib.drawer;
import static com.google.common.truth.Truth.assertThat;
-
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
@@ -54,7 +53,6 @@
import android.widget.RemoteViews;
import com.android.settingslib.R;
-import com.android.settingslib.TestConfig;
import com.android.settingslib.suggestions.SuggestionParser;
import org.junit.Before;
@@ -74,9 +72,7 @@
import java.util.Map;
@RunWith(RobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH,
- sdk = TestConfig.SDK_VERSION,
- shadows = {TileUtilsTest.TileUtilsShadowRemoteViews.class})
+@Config(shadows = TileUtilsTest.TileUtilsShadowRemoteViews.class)
public class TileUtilsTest {
private Context mContext;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
index fc0019d..c6a1428 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
@@ -17,7 +17,6 @@
package com.android.settingslib.fuelgauge;
import static com.google.common.truth.Truth.assertThat;
-
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doNothing;
@@ -27,17 +26,14 @@
import android.os.IDeviceIdleController;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
-import com.android.settingslib.TestConfig;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.robolectric.annotation.Config;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class PowerWhitelistBackendTest {
private static final String PACKAGE_ONE = "com.example.packageone";
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java
index e022232..49dde0e 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java
@@ -26,8 +26,6 @@
import android.graphics.Paint;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
-import com.android.settingslib.TestConfig;
-import com.android.settingslib.testutils.shadow.SettingsLibShadowResources;
import org.junit.Before;
import org.junit.Test;
@@ -35,12 +33,9 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
import org.robolectric.util.ReflectionHelpers;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION,
- shadows = SettingsLibShadowResources.class)
public class BatteryMeterDrawableBaseTest {
private static final int CRITICAL_LEVEL = 5;
private static final int PADDING = 5;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BluetoothDeviceLayerDrawableTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BluetoothDeviceLayerDrawableTest.java
index 94f80d3..37d4d1d 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BluetoothDeviceLayerDrawableTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BluetoothDeviceLayerDrawableTest.java
@@ -19,23 +19,17 @@
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
-import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.VectorDrawable;
import com.android.settingslib.R;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
-import com.android.settingslib.TestConfig;
-import com.android.settingslib.testutils.shadow.SettingsLibShadowResources;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION,
- shadows = SettingsLibShadowResources.class)
public class BluetoothDeviceLayerDrawableTest {
private static final int RES_ID = R.drawable.ic_bt_cellphone;
private static final int BATTERY_LEVEL = 15;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java
index c7e9262..96b2a14 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java
@@ -18,12 +18,10 @@
import static com.google.common.truth.Truth.assertThat;
-import com.android.settingslib.TestConfig;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.robolectric.annotation.Config;
import org.xmlpull.v1.XmlPullParserException;
import java.io.ByteArrayInputStream;
@@ -35,7 +33,6 @@
import java.util.Map;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class LicenseHtmlGeneratorFromXmlTest {
private static final String VALILD_XML_STRING =
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlLoaderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlLoaderTest.java
index 1a6f30c..5095f50 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlLoaderTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlLoaderTest.java
@@ -17,7 +17,6 @@
package com.android.settingslib.license;
import static com.google.common.truth.Truth.assertThat;
-
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
@@ -26,7 +25,6 @@
import android.content.Context;
-import com.android.settingslib.TestConfig;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
import org.junit.Before;
@@ -34,13 +32,11 @@
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.robolectric.annotation.Config;
import java.io.File;
import java.util.ArrayList;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class LicenseHtmlLoaderTest {
@Mock
private Context mContext;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAppsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAppsTest.java
index 226166b..5e0fcef 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAppsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAppsTest.java
@@ -1,8 +1,8 @@
package com.android.settingslib.location;
+import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.when;
-import static com.google.common.truth.Truth.assertThat;
import android.app.AppOpsManager;
import android.app.AppOpsManager.OpEntry;
@@ -15,23 +15,21 @@
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
+
import com.android.settingslib.SettingsLibRobolectricTestRunner;
-import com.android.settingslib.TestConfig;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.robolectric.annotation.Config;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(
- manifest = TestConfig.MANIFEST_PATH,
- sdk = TestConfig.SDK_VERSION)
public class RecentLocationAppsTest {
private static final int TEST_UID = 1234;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/EnableZenModeDialogTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/EnableZenModeDialogTest.java
index 777cd98..ccd2f53 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/EnableZenModeDialogTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/EnableZenModeDialogTest.java
@@ -17,22 +17,26 @@
package com.android.settingslib.notification;
import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
-
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
-import android.app.Activity;
import android.app.Fragment;
+import android.app.NotificationManager;
import android.content.Context;
+import android.content.res.Resources;
import android.net.Uri;
import android.service.notification.Condition;
import android.view.LayoutInflater;
-import com.android.settingslib.TestConfig;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
import org.junit.Before;
@@ -41,17 +45,19 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class EnableZenModeDialogTest {
private EnableZenModeDialog mController;
@Mock
private Context mContext;
@Mock
+ private Resources mResources;
+ @Mock
private Fragment mFragment;
+ @Mock
+ private NotificationManager mNotificationManager;
private Context mShadowContext;
private LayoutInflater mLayoutInflater;
@@ -63,6 +69,7 @@
MockitoAnnotations.initMocks(this);
mShadowContext = RuntimeEnvironment.application;
when(mContext.getApplicationContext()).thenReturn(mContext);
+ when(mContext.getResources()).thenReturn(mResources);
when(mFragment.getContext()).thenReturn(mShadowContext);
mLayoutInflater = LayoutInflater.from(mShadowContext);
@@ -72,6 +79,10 @@
mController.mForeverId = Condition.newId(mContext).appendPath("forever").build();
when(mContext.getString(com.android.internal.R.string.zen_mode_forever))
.thenReturn("testSummary");
+ NotificationManager.Policy alarmsEnabledPolicy = new NotificationManager.Policy(
+ NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS, 0, 0, 0);
+ doReturn(alarmsEnabledPolicy).when(mNotificationManager).getNotificationPolicy();
+ mController.mNotificationManager = mNotificationManager;
mController.getContentView();
// these methods use static calls to ZenModeConfig which would normally fail in robotests,
@@ -146,4 +157,38 @@
assertFalse(mController.getConditionTagAt(
EnableZenModeDialog.COUNTDOWN_ALARM_CONDITION_INDEX).rb.isChecked());
}
+
+ @Test
+ public void testNoAlarmWarning() {
+ // setup alarm
+ long now = System.currentTimeMillis();
+ doReturn(now + 100000).when(mController).getNextAlarm();
+ doReturn("").when(mController).getTime(anyLong(), anyLong());
+
+ // allow alarms
+ when(mNotificationManager.getNotificationPolicy()).thenReturn(
+ new NotificationManager.Policy(
+ NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS, 0, 0, 0));
+
+ // alarm warning should be null
+ assertNull(mController.computeAlarmWarningText(null));
+ }
+
+ @Test
+ public void testAlarmWarning() {
+ // setup alarm
+ long now = System.currentTimeMillis();
+ doReturn(now + 1000000).when(mController).getNextAlarm();
+ doReturn("").when(mController).getTime(anyLong(), anyLong());
+
+ // don't allow alarms to bypass dnd
+ when(mNotificationManager.getNotificationPolicy()).thenReturn(
+ new NotificationManager.Policy(0, 0, 0, 0));
+
+ // return a string if mResources is asked to retrieve a string
+ when(mResources.getString(anyInt(), anyString())).thenReturn("");
+
+ // alarm warning should NOT be null
+ assertNotNull(mController.computeAlarmWarningText(null));
+ }
}
\ No newline at end of file
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/suggestions/SuggestionControllerMixinTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/suggestions/SuggestionControllerMixinTest.java
index ed1c405..cfa16b8 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/suggestions/SuggestionControllerMixinTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/suggestions/SuggestionControllerMixinTest.java
@@ -18,9 +18,7 @@
import static android.arch.lifecycle.Lifecycle.Event.ON_START;
import static android.arch.lifecycle.Lifecycle.Event.ON_STOP;
-
import static com.google.common.truth.Truth.assertThat;
-
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -30,7 +28,6 @@
import android.content.ComponentName;
import android.content.Context;
-import com.android.settingslib.TestConfig;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
import com.android.settingslib.core.lifecycle.Lifecycle;
@@ -44,10 +41,7 @@
import org.robolectric.annotation.Config;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION,
- shadows = {
- ShadowSuggestionController.class
- })
+@Config(shadows = ShadowSuggestionController.class)
public class SuggestionControllerMixinTest {
@Mock
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/suggestions/SuggestionParserTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/suggestions/SuggestionParserTest.java
index db599a7..d05bcfd 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/suggestions/SuggestionParserTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/suggestions/SuggestionParserTest.java
@@ -17,11 +17,9 @@
package com.android.settingslib.suggestions;
import static com.google.common.truth.Truth.assertThat;
-
import static org.robolectric.RuntimeEnvironment.application;
import static org.robolectric.shadow.api.Shadow.extract;
-import android.app.ApplicationPackageManager;
import android.content.ComponentName;
import android.content.Intent;
import android.content.SharedPreferences;
@@ -30,28 +28,22 @@
import android.preference.PreferenceManager;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
-import com.android.settingslib.TestConfig;
import com.android.settingslib.drawer.Tile;
import com.android.settingslib.drawer.TileUtilsTest;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.robolectric.annotation.Config;
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-import org.robolectric.shadows.ShadowApplicationPackageManager;
+import org.robolectric.shadows.ShadowPackageManager;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION,
- shadows = SuggestionParserTest.TestPackageManager.class)
public class SuggestionParserTest {
- private TestPackageManager mPackageManager;
+ private ShadowPackageManager mPackageManager;
private SuggestionParser mSuggestionParser;
private SuggestionCategory mMultipleCategory;
private SuggestionCategory mExclusiveCategory;
@@ -205,13 +197,4 @@
mSuggestionParser.readSuggestions(
mMultipleCategory, mSuggestionsAfterDismiss, isSmartSuggestionEnabled);
}
-
- @Implements(ApplicationPackageManager.class)
- public static class TestPackageManager extends ShadowApplicationPackageManager {
-
- @Implementation
- public List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent, int flags, int userId) {
- return super.queryIntentActivities(intent, flags);
- }
- }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/SettingsLibShadowResources.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/SettingsLibShadowResources.java
deleted file mode 100644
index b53cc37..0000000
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/SettingsLibShadowResources.java
+++ /dev/null
@@ -1,49 +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.settingslib.testutils.shadow;
-
-import static org.robolectric.shadow.api.Shadow.directlyOn;
-
-import android.content.res.Resources;
-import android.content.res.Resources.NotFoundException;
-import android.support.annotation.ArrayRes;
-
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-import org.robolectric.annotation.RealObject;
-import org.robolectric.shadows.ShadowResources;
-
-/**
- * Shadow Resources to handle resource references that Robolectric shadows cannot
- * handle because they are too new or private.
- */
-@Implements(Resources.class)
-public class SettingsLibShadowResources extends ShadowResources {
-
- @RealObject
- public Resources realResources;
-
- @Implementation
- public int[] getIntArray(@ArrayRes int id) throws NotFoundException {
- // The Robolectric has resource mismatch for these values, so we need to stub it here
- if (id == com.android.settingslib.R.array.batterymeter_bolt_points
- || id == com.android.settingslib.R.array.batterymeter_plus_points) {
- return new int[2];
- }
- return directlyOn(realResources, Resources.class).getIntArray(id);
- }
-}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowPackageManagerWrapper.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowPackageManagerWrapper.java
deleted file mode 100644
index 1fdca27..0000000
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowPackageManagerWrapper.java
+++ /dev/null
@@ -1,54 +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.settingslib.testutils.shadow;
-
-import android.content.Intent;
-import android.content.pm.ResolveInfo;
-import android.util.ArrayMap;
-
-import com.android.settingslib.wrapper.PackageManagerWrapper;
-
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Shadow for {@link PackageManagerWrapper} to allow stubbing hidden methods.
- */
-@Implements(PackageManagerWrapper.class)
-public class ShadowPackageManagerWrapper {
- private static final Map<Intent, List<ResolveInfo>> intentServices = new ArrayMap<>();
-
- @Implementation
- public List<ResolveInfo> queryIntentServicesAsUser(Intent intent, int i, int user) {
- List<ResolveInfo> list = intentServices.get(intent);
- return list != null ? list : Collections.emptyList();
- }
-
- public static void addResolveInfoForIntent(Intent intent, ResolveInfo info) {
- List<ResolveInfo> infoList = intentServices.computeIfAbsent(intent, k -> new ArrayList<>());
- infoList.add(info);
- }
-
- public static void reset() {
- intentServices.clear();
- }
-}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowUserManager.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowUserManager.java
index c8b3269..a3e1bc8 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowUserManager.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowUserManager.java
@@ -25,7 +25,7 @@
import org.robolectric.annotation.Resetter;
import org.robolectric.shadow.api.Shadow;
-@Implements(UserManager.class)
+@Implements(value = UserManager.class, inheritImplementationMethods = true)
public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager {
private boolean mAdminUser;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java
index f93210f..9285148f 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java
@@ -20,20 +20,19 @@
import static org.mockito.Mockito.spy;
import android.content.Context;
+
import com.android.settingslib.R;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
-import com.android.settingslib.TestConfig;
-import com.android.settingslib.utils.PowerUtil;
-import java.time.Duration;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
+
+import java.time.Duration;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class PowerUtilTest {
public static final String TEST_BATTERY_LEVEL_10 = "10%";
public static final String FIFTEEN_MIN_FORMATTED = "15m";
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/StringUtilTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/StringUtilTest.java
index d5e3cdb..47dd022 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/StringUtilTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/StringUtilTest.java
@@ -23,16 +23,15 @@
import android.text.SpannableStringBuilder;
import android.text.format.DateUtils;
import android.text.style.TtsSpan;
+
import com.android.settingslib.SettingsLibRobolectricTestRunner;
-import com.android.settingslib.TestConfig;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class StringUtilTest {
private Context mContext;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/ThreadUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/ThreadUtilsTest.java
index 5f6a5c8..83a9d5b 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/ThreadUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/ThreadUtilsTest.java
@@ -19,16 +19,12 @@
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
-import com.android.settingslib.TestConfig;
-
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowLooper;
@RunWith(RobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class ThreadUtilsTest {
@Test
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AnimatedImageViewTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AnimatedImageViewTest.java
index 2c9c868..36abd20 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AnimatedImageViewTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AnimatedImageViewTest.java
@@ -16,21 +16,19 @@
package com.android.settingslib.widget;
+import static com.google.common.truth.Truth.assertThat;
+
import android.app.Activity;
import android.graphics.drawable.AnimatedRotateDrawable;
import android.view.View;
-import com.android.settingslib.TestConfig;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-import static com.google.common.truth.Truth.assertThat;
@RunWith(RobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class AnimatedImageViewTest {
private AnimatedImageView mAnimatedImageView;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceMixinTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceMixinTest.java
index 88c57b5..8071c6db 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceMixinTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceMixinTest.java
@@ -29,7 +29,6 @@
import android.support.v7.preference.PreferenceScreen;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
-import com.android.settingslib.TestConfig;
import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.Before;
@@ -37,11 +36,9 @@
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowApplication;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class FooterPreferenceMixinTest {
@Mock
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java
index 5d01027..ff11b80 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java
@@ -16,6 +16,8 @@
package com.android.settingslib.widget;
+import static com.google.common.truth.Truth.assertThat;
+
import android.content.Context;
import android.support.v7.preference.PreferenceViewHolder;
import android.text.method.LinkMovementMethod;
@@ -24,18 +26,13 @@
import com.android.settingslib.R;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
-import com.android.settingslib.TestConfig;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowApplication;
-import static com.google.common.truth.Truth.assertThat;
-
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class FooterPreferenceTest {
private Context mContext;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/AccessPointPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/AccessPointPreferenceTest.java
index 3fee16b..ee2c2ff 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/AccessPointPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/AccessPointPreferenceTest.java
@@ -25,7 +25,6 @@
import android.graphics.drawable.ColorDrawable;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
-import com.android.settingslib.TestConfig;
import org.junit.Before;
import org.junit.Test;
@@ -33,10 +32,8 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class AccessPointPreferenceTest {
private Context mContext = RuntimeEnvironment.application;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/TimestampedScoredNetworkTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/TimestampedScoredNetworkTest.java
index b2d9d67b..f0e8c66 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/TimestampedScoredNetworkTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/TimestampedScoredNetworkTest.java
@@ -23,16 +23,14 @@
import android.os.Parcel;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
-import com.android.settingslib.TestConfig;
-import java.util.Date;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
+
+import java.util.Date;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class TimestampedScoredNetworkTest {
private TimestampedScoredNetwork impl;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java
index 9310b73..ea8ecba 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java
@@ -16,7 +16,6 @@
package com.android.settingslib.wifi;
import static com.google.common.truth.Truth.assertThat;
-
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.when;
@@ -35,7 +34,6 @@
import com.android.settingslib.R;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
-import com.android.settingslib.TestConfig;
import org.junit.Before;
import org.junit.Test;
@@ -43,12 +41,10 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
import java.util.ArrayList;
@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class WifiUtilsTest {
private static final String TEST_SSID = "\"test_ssid\"";
private static final String TEST_BSSID = "00:00:00:00:00:00";
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index 91957e1..ad422d8 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -76,11 +76,10 @@
*/
private static final ArraySet<String> sBroadcastOnRestore;
static {
- sBroadcastOnRestore = new ArraySet<String>(5);
+ sBroadcastOnRestore = new ArraySet<String>(4);
sBroadcastOnRestore.add(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
sBroadcastOnRestore.add(Settings.Secure.ENABLED_VR_LISTENERS);
sBroadcastOnRestore.add(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
- sBroadcastOnRestore.add(Settings.Secure.ENABLED_INPUT_METHODS);
sBroadcastOnRestore.add(Settings.Global.BLUETOOTH_ON);
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 1551b8e..1e8c523 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -870,6 +870,12 @@
dumpSetting(s, p,
Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING,
GlobalSettingsProto.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING);
+ dumpSetting(s, p,
+ Settings.Global.INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT,
+ GlobalSettingsProto.INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT);
+ dumpSetting(s, p,
+ Settings.Global.INSTALL_CARRIER_APP_NOTIFICATION_SLEEP_MILLIS,
+ GlobalSettingsProto.INSTALL_CARRIER_APP_NOTIFICATION_SLEEP_MILLIS);
// Settings.Global.SHOW_PROCESSES intentionally excluded since it's deprecated.
dumpSetting(s, p,
Settings.Global.LOW_POWER_MODE,
@@ -1055,6 +1061,9 @@
Global.CHAINED_BATTERY_ATTRIBUTION_ENABLED,
GlobalSettingsProto.CHAINED_BATTERY_ATTRIBUTION_ENABLED);
dumpSetting(s, p,
+ Global.HIDDEN_API_BLACKLIST_EXEMPTIONS,
+ GlobalSettingsProto.HIDDEN_API_BLACKLIST_EXEMPTIONS);
+ dumpSetting(s, p,
Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION,
GlobalSettingsProto.MULTI_SIM_VOICE_CALL_SUBSCRIPTION);
dumpSetting(s, p,
@@ -1123,6 +1132,9 @@
dumpSetting(s, p,
Settings.Global.SHOW_MUTE_IN_CRASH_DIALOG,
GlobalSettingsProto.SHOW_MUTE_IN_CRASH_DIALOG);
+ dumpSetting(s, p,
+ Settings.Global.SHOW_ZEN_UPGRADE_NOTIFICATION,
+ GlobalSettingsProto.SHOW_ZEN_UPGRADE_NOTIFICATION);
// Please insert new settings using the same order as in Settings.Global.
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 85a579d..87ea382 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -1591,6 +1591,7 @@
private boolean isGlobalOrSecureSettingRestrictedForUser(String setting, int userId,
String value, int callingUid) {
String restriction;
+ boolean checkAllUser = false;
switch (setting) {
case Settings.Secure.LOCATION_MODE:
// Note LOCATION_MODE will be converted into LOCATION_PROVIDERS_ALLOWED
@@ -1656,6 +1657,12 @@
restriction = UserManager.DISALLOW_AMBIENT_DISPLAY;
break;
+ case Global.LOCATION_GLOBAL_KILL_SWITCH:
+ if ("0".equals(value)) return false;
+ restriction = UserManager.DISALLOW_CONFIG_LOCATION;
+ checkAllUser = true;
+ break;
+
default:
if (setting != null && setting.startsWith(Settings.Global.DATA_ROAMING)) {
if ("0".equals(value)) return false;
@@ -1665,7 +1672,11 @@
return false;
}
- return mUserManager.hasUserRestriction(restriction, UserHandle.of(userId));
+ if (checkAllUser) {
+ return mUserManager.hasUserRestrictionOnAnyUser(restriction);
+ } else {
+ return mUserManager.hasUserRestriction(restriction, UserHandle.of(userId));
+ }
}
private int resolveOwningUserIdForSecureSettingLocked(int userId, String setting) {
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 4d49899..5c8d745 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -44,7 +44,6 @@
<uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
<uses-permission android:name="android.permission.MANAGE_USB" />
<uses-permission android:name="android.permission.USE_RESERVED_DISK" />
- <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<!-- System tool permissions granted to the shell. -->
<uses-permission android:name="android.permission.REAL_GET_TASKS" />
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
diff --git a/packages/SimAppDialog/Android.mk b/packages/SimAppDialog/Android.mk
new file mode 100644
index 0000000..00a2e60
--- /dev/null
+++ b/packages/SimAppDialog/Android.mk
@@ -0,0 +1,18 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := SimAppDialog
+LOCAL_CERTIFICATE := platform
+
+
+LOCAL_STATIC_ANDROID_LIBRARIES := \
+ android-support-v4
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+include frameworks/opt/setupwizard/library/common-platform-deprecated.mk
+
+include $(BUILD_PACKAGE)
diff --git a/packages/SimAppDialog/AndroidManifest.xml b/packages/SimAppDialog/AndroidManifest.xml
new file mode 100644
index 0000000..873f6c5
--- /dev/null
+++ b/packages/SimAppDialog/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * 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.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.simappdialog">
+ <application android:label="@string/app_name">
+ <activity
+ android:name=".InstallCarrierAppActivity"
+ android:exported="true"
+ android:permission="android.permission.NETWORK_SETTINGS"
+ android:theme="@style/SuwThemeGlif.Light">
+ </activity>
+ </application>
+</manifest>
diff --git a/packages/SimAppDialog/res/drawable/ic_signal_cellular_alt_rounded_24px.xml b/packages/SimAppDialog/res/drawable/ic_signal_cellular_alt_rounded_24px.xml
new file mode 100644
index 0000000..85896e8
--- /dev/null
+++ b/packages/SimAppDialog/res/drawable/ic_signal_cellular_alt_rounded_24px.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="21dp"
+ android:height="22dp"
+ android:viewportWidth="21"
+ android:viewportHeight="22">
+
+ <group
+ android:translateX="-196.000000"
+ android:translateY="-77.000000">
+ <group
+ android:translateX="190.000000"
+ android:translateY="72.000000">
+ <path
+ android:fillType="evenOdd"
+ android:strokeWidth="1"
+ android:pathData="M 0 0 H 32 V 32 H 0 V 0 Z"/>
+ <group
+ android:translateX="6.666667"
+ android:translateY="5.333333">
+ <path
+ android:fillColor="#4285F4"
+ android:strokeWidth="1"
+ android:pathData="M 17 0 L 19 0 Q 20 0 20 1 L 20 20.3333333 Q 20 21.3333333 19 21.3333333 L 17 21.3333333 Q 16 21.3333333 16 20.3333333 L 16 1 Q 16 0 17 0 Z"/>
+ <path
+ android:fillColor="#4285F4"
+ android:strokeWidth="1"
+ android:pathData="M 1 13.3333333 L 3 13.3333333 Q 4 13.3333333 4 14.3333333 L 4 20.3333333 Q 4 21.3333333 3 21.3333333 L 1 21.3333333 Q 0 21.3333333 0 20.3333333 L 0 14.3333333 Q 0 13.3333333 1 13.3333333 Z"/>
+ <path
+ android:fillColor="#4285F4"
+ android:strokeWidth="1"
+ android:pathData="M 9 6.66666667 L 11 6.66666667 Q 12 6.66666667 12 7.66666667 L 12 20.33333337 Q 12 21.33333337 11 21.33333337 L 9 21.33333337 Q 8 21.33333337 8 20.33333337 L 8 7.66666667 Q 8 6.66666667 9 6.66666667 Z"/>
+ </group>
+ </group>
+ </group>
+</vector>
\ No newline at end of file
diff --git a/packages/SimAppDialog/res/drawable/placeholder.xml b/packages/SimAppDialog/res/drawable/placeholder.xml
new file mode 100644
index 0000000..53eee74
--- /dev/null
+++ b/packages/SimAppDialog/res/drawable/placeholder.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<!-- TODO(b/72511181): replace when illustration is finished -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="270dp"
+ android:height="270dp"
+ android:viewportHeight="270.0"
+ android:viewportWidth="270.0">
+ <path android:fillColor="#E8EAED"
+ android:pathData="M183.54,265H84.88c-7.63,0 -13.81,-6.18 -13.81,-13.81V18.81C71.07,11.18 77.25,5 84.88,5h98.66c7.63,0 13.81,6.18 13.81,13.81v232.38C197.35,258.82 191.17,265 183.54,265z"/>
+ <path android:fillColor="#BDC1C6"
+ android:pathData="M183.54,6.63c6.72,0 12.18,5.46 12.18,12.18v232.38c0,6.72 -5.46,12.18 -12.18,12.18H84.88c-6.72,0 -12.18,-5.46 -12.18,-12.18V18.81c0,-6.72 5.46,-12.18 12.18,-12.18H183.54M183.54,5H84.88c-7.63,0 -13.81,6.18 -13.81,13.81v232.38c0,7.63 6.18,13.81 13.81,13.81h98.66c7.63,0 13.81,-6.18 13.81,-13.81V18.81C197.35,11.18 191.17,5 183.54,5L183.54,5z"/>
+ <path android:fillColor="#FFFFFF"
+ android:pathData="M186.34,243.74H82.08c-2.41,0 -4.36,-1.95 -4.36,-4.36V30.61c0,-2.41 1.95,-4.36 4.36,-4.36h104.26c2.41,0 4.36,1.95 4.36,4.36v208.78C190.7,241.79 188.75,243.74 186.34,243.74z"/>
+ <path android:fillColor="#BDC1C6"
+ android:pathData="M156.07,254.78h-43.72c-0.65,0 -1.18,-0.53 -1.18,-1.18v-0.08c0,-0.65 0.53,-1.18 1.18,-1.18h43.72c0.65,0 1.18,0.53 1.18,1.18v0.08C157.25,254.25 156.72,254.78 156.07,254.78z"/>
+ <path android:fillColor="#BDC1C6"
+ android:pathData="M156.07,17.67h-43.72c-0.65,0 -1.18,-0.53 -1.18,-1.18V16.4c0,-0.65 0.53,-1.18 1.18,-1.18l43.72,0c0.65,0 1.18,0.53 1.18,1.18v0.08C157.25,17.14 156.72,17.67 156.07,17.67z"/>
+ <path android:fillColor="#BDC1C6"
+ android:pathData="M197.85,84.16h-0.5V67.51h0.5c0.6,0 1.08,0.48 1.08,1.08v14.5C198.93,83.68 198.45,84.16 197.85,84.16z"/>
+ <path android:fillColor="#BDC1C6"
+ android:pathData="M197.41,136.45h-0.06v-32.87h0.06c0.84,0 1.52,0.68 1.52,1.52v29.84C198.93,135.77 198.25,136.45 197.41,136.45z"/>
+ <path android:fillColor="#BDC1C6"
+ android:pathData="M119.3,74.73l2.71,2.71c6.74,-6.74 17.67,-6.74 24.4,0l2.71,-2.71C140.89,66.49 127.54,66.49 119.3,74.73zM130.15,85.57l4.07,4.07l4.07,-4.07C136.04,83.33 132.39,83.33 130.15,85.57zM124.72,80.15l2.71,2.71c3.74,-3.74 9.82,-3.74 13.56,0l2.71,-2.71C138.46,74.91 129.96,74.91 124.72,80.15z"/>
+ <path android:fillColor="#BDC1C6"
+ android:pathData="M143.7,179h-1.36v-2.71h-2.71V179h-10.85v-2.71h-2.71V179h-1.36c-1.5,0 -2.7,1.21 -2.7,2.71l-0.01,18.98c0,1.5 1.21,2.71 2.71,2.71h18.98c1.5,0 2.71,-1.21 2.71,-2.71v-18.98C146.41,180.22 145.2,179 143.7,179zM143.7,200.7h-18.98v-14.91h18.98V200.7zM127.43,188.49h6.78v6.78h-6.78V188.49z"/>
+ <path android:fillColor="#BDC1C6"
+ android:pathData="M146.41,144.49v-18.98c0,-1.5 -1.21,-2.71 -2.71,-2.71h-18.98c-1.5,0 -2.71,1.21 -2.71,2.71v18.98c0,1.5 1.21,2.71 2.71,2.71h18.98C145.2,147.2 146.41,145.99 146.41,144.49zM129.47,137.03l3.39,4.07l4.75,-6.11l6.1,8.13h-18.98L129.47,137.03z"/>
+</vector>
diff --git a/packages/SimAppDialog/res/layout/install_carrier_app_activity.xml b/packages/SimAppDialog/res/layout/install_carrier_app_activity.xml
new file mode 100644
index 0000000..0462a93
--- /dev/null
+++ b/packages/SimAppDialog/res/layout/install_carrier_app_activity.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+<com.android.setupwizardlib.GlifLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/setup_wizard_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:icon="@drawable/ic_signal_cellular_alt_rounded_24px"
+ app:suwHeaderText="@string/install_carrier_app_title"
+ app:suwFooter="@layout/install_carrier_app_footer">
+
+ <LinearLayout
+ style="@style/SuwContentFrame"
+ android:id="@+id/content_frame"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/install_carrier_app_description"
+ style="@style/SuwDescription.Glif"
+ android:text="@string/install_carrier_app_description_default"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+
+ <com.android.setupwizardlib.view.FillContentLayout
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1">
+
+ <!-- TODO(b/72511181): final illo and content description update -->
+ <ImageView
+ android:src="@drawable/placeholder"
+ style="@style/SuwContentIllustration"
+ android:contentDescription="@null"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+
+ </com.android.setupwizardlib.view.FillContentLayout>
+ </LinearLayout>
+
+</com.android.setupwizardlib.GlifLayout>
diff --git a/packages/SimAppDialog/res/layout/install_carrier_app_footer.xml b/packages/SimAppDialog/res/layout/install_carrier_app_footer.xml
new file mode 100644
index 0000000..10dcb77
--- /dev/null
+++ b/packages/SimAppDialog/res/layout/install_carrier_app_footer.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+
+<com.android.setupwizardlib.view.ButtonBarLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/footer"
+ style="@style/SuwGlifButtonBar.Stackable"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <Button
+ android:id="@+id/skip_button"
+ style="@style/SuwGlifButton.Secondary"
+ android:text="@string/install_carrier_app_defer_action"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+
+ <Space
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_weight="1"/>
+
+ <Button
+ android:id="@+id/download_button"
+ style="@style/SuwGlifButton.Primary"
+ android:text="@string/install_carrier_app_download_action"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+</com.android.setupwizardlib.view.ButtonBarLayout>
diff --git a/packages/SimAppDialog/res/values/strings.xml b/packages/SimAppDialog/res/values/strings.xml
new file mode 100644
index 0000000..0c3930d
--- /dev/null
+++ b/packages/SimAppDialog/res/values/strings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- TODO character limits -->
+ <!-- The name of this application -->
+ <string name="app_name">Sim App Dialog</string>
+ <!-- Install Carrier App Activity -->
+ <!-- Title of screen asking user to download the carrier app to match the inserted SIM card -->
+ <string name="install_carrier_app_title">Activate mobile service</string>
+ <!-- Description of screen asking user to download the carrier app to match the inserted SIM card if we know the name of the carrier-->
+ <string name="install_carrier_app_description">To get your new SIM working properly, you\'ll
+ need to install the <xliff:g name="carrier_name" example="Project Fi">%1$s</xliff:g> app
+ </string>
+ <!-- Description of screen asking user to download the carrier app to match the inserted SIM card if we don't know the name of the carrier-->
+ <string name="install_carrier_app_description_default">To get your new SIM working properly,
+ you\'ll need to install the carrier app
+ </string>
+ <!-- Name of the button used to defer downloading the carrier app -->
+ <string name="install_carrier_app_defer_action">Not now</string>
+ <!-- Name of the button for downloading the carrier app -->
+ <string name="install_carrier_app_download_action">Download app</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SimAppDialog/src/com/android/simappdialog/InstallCarrierAppActivity.java b/packages/SimAppDialog/src/com/android/simappdialog/InstallCarrierAppActivity.java
new file mode 100644
index 0000000..9e9b80d
--- /dev/null
+++ b/packages/SimAppDialog/src/com/android/simappdialog/InstallCarrierAppActivity.java
@@ -0,0 +1,95 @@
+/*
+ * 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.simappdialog;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.SystemProperties;
+import android.text.TextUtils;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+
+import com.android.setupwizardlib.util.WizardManagerHelper;
+
+/**
+ * Activity that gives a user the choice to download the SIM app or defer until a later time
+ *
+ * Will finish with result {@link #DEFER_RESULT} on defer button press or {@link #DOWNLOAD_RESULT}
+ * if the download button is pressed
+ *
+ * Can display the carrier app name if its passed into the intent with key
+ * {@link #BUNDLE_KEY_CARRIER_NAME}
+ */
+public class InstallCarrierAppActivity extends Activity implements View.OnClickListener {
+ /**
+ * Key for the carrier app name that will be displayed as the app to download. If unset, a
+ * default description will be used
+ */
+ public static final String BUNDLE_KEY_CARRIER_NAME = "carrier_name";
+ /** Result code when the defer button is pressed */
+ public static final int DEFER_RESULT = 1;
+ /** Result code when the download button is pressed */
+ public static final int DOWNLOAD_RESULT = 2;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ // Setup theme for aosp/pixel
+ setTheme(
+ WizardManagerHelper.getThemeRes(
+ SystemProperties.get("setupwizard.theme"),
+ R.style.SuwThemeGlif_Light
+ )
+ );
+
+ super.onCreate(icicle);
+ setContentView(R.layout.install_carrier_app_activity);
+
+ Button notNowButton = findViewById(R.id.skip_button);
+ notNowButton.setOnClickListener(this);
+
+ Button downloadButton = findViewById(R.id.download_button);
+ downloadButton.setOnClickListener(this);
+
+ // Include carrier name in description text if its present in the intent
+ Intent intent = getIntent();
+ if (intent != null) {
+ String carrierName = intent.getStringExtra(BUNDLE_KEY_CARRIER_NAME);
+ if (!TextUtils.isEmpty(carrierName)) {
+ TextView subtitle = findViewById(R.id.install_carrier_app_description);
+ subtitle.setText(getString(R.string.install_carrier_app_description, carrierName));
+ }
+ }
+ }
+
+ @Override
+ public void onClick(View v) {
+ switch (v.getId()) {
+ case R.id.skip_button:
+ finish(DEFER_RESULT);
+ break;
+ case R.id.download_button:
+ finish(DOWNLOAD_RESULT);
+ break;
+ }
+ }
+
+ private void finish(int resultCode) {
+ setResult(resultCode);
+ finish();
+ }
+}
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index cbb3e8f..35c4d59 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -110,7 +110,7 @@
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
<!-- Keyguard -->
- <uses-permission android:name="com.android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS" />
+ <uses-permission android:name="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS" />
<uses-permission android:name="android.permission.CONTROL_KEYGUARD" />
<uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
@@ -381,6 +381,12 @@
android:finishOnCloseSystemDialogs="true"
android:excludeFromRecents="true">
</activity>
+ <activity-alias
+ android:name=".UsbDebuggingActivityAlias"
+ android:permission="android.permission.DUMP"
+ android:targetActivity=".usb.UsbDebuggingActivity"
+ android:exported="true">
+ </activity-alias>
<activity android:name=".usb.UsbDebuggingSecondaryUserActivity"
android:theme="@style/Theme.SystemUI.Dialog.Alert"
android:finishOnCloseSystemDialogs="true"
diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS
index af6dd77..7c97ca61 100644
--- a/packages/SystemUI/OWNERS
+++ b/packages/SystemUI/OWNERS
@@ -2,19 +2,23 @@
dsandler@google.com
+adamcohen@google.com
asc@google.com
ashaikh@google.com
beverlyt@google.com
cinek@google.com
cwren@google.com
+dupin@google.com
evanlaird@google.com
jmonk@google.com
jaggies@google.com
jjaggi@google.com
juliacr@google.com
-dupin@google.com
madym@google.com
+ngmatthew@google.com
roosa@google.com
shahrk@google.com
+sunnygoyal@google.com
+twickham@google.com
winsonc@google.com
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml
index faa2c17..31635a5 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml
@@ -33,6 +33,23 @@
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/widget_vertical_padding"
android:orientation="vertical">
+ <TextView
+ android:id="@+id/logout"
+ android:layout_height="@dimen/logout_button_layout_height"
+ android:layout_width="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_centerHorizontal="true"
+ android:layout_marginBottom="@dimen/logout_button_margin_bottom"
+ android:gravity="center"
+ android:paddingLeft="@dimen/logout_button_padding_horizontal"
+ android:paddingRight="@dimen/logout_button_padding_horizontal"
+ android:background="@drawable/logout_button_background"
+ android:fontFamily="roboto-medium"
+ android:textAllCaps="true"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="13sp"
+ android:text="@*android:string/global_action_logout" />
+
<RelativeLayout
android:id="@+id/keyguard_clock_container"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res-keyguard/values-da/strings.xml b/packages/SystemUI/res-keyguard/values-da/strings.xml
index 156da2e..d9075aa 100644
--- a/packages/SystemUI/res-keyguard/values-da/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-da/strings.xml
@@ -53,6 +53,8 @@
<string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"Næste alarm er indstillet til <xliff:g id="ALARM">%1$s</xliff:g>"</string>
<string name="keyboardview_keycode_delete" msgid="6883116827512721630">"Slet"</string>
<string name="disable_carrier_button_text" msgid="6914341927421916114">"Deaktiver eSIM"</string>
+ <string name="error_disable_esim_title" msgid="4852978431156228006">"eSIM kan ikke deaktiveres"</string>
+ <string name="error_disable_esim_msg" msgid="676694908770135639">"eSIM kan ikke deaktiveres på grund af en fejl."</string>
<string name="keyboardview_keycode_enter" msgid="4505833604411016668">"Enter"</string>
<string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"Har du glemt mønsteret?"</string>
<string name="kg_wrong_pattern" msgid="7620081431514773802">"Forkert mønster"</string>
@@ -65,7 +67,7 @@
<string name="kg_pattern_instructions" msgid="5547646893001491340">"Tegn dit mønster"</string>
<string name="kg_sim_pin_instructions" msgid="6389000973113699187">"Angiv pinkoden til SIM-kortet."</string>
<string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"Angiv pinkoden til SIM-kortet fra \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string>
- <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"Deaktiver eSIM for at bruge enheden uden mobiltjeneste."</string>
+ <string name="kg_sim_lock_esim_instructions" msgid="4416732549172148542">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Deaktiver eSIM for at bruge enheden uden mobiltjeneste."</string>
<string name="kg_pin_instructions" msgid="4069609316644030034">"Indtast pinkode"</string>
<string name="kg_password_instructions" msgid="136952397352976538">"Angiv adgangskode"</string>
<string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"SIM-kortet er nu deaktiveret. Indtast PUK-koden for at fortsætte. Kontakt mobilselskabet for at få flere oplysninger."</string>
diff --git a/packages/SystemUI/res-keyguard/values-eu/strings.xml b/packages/SystemUI/res-keyguard/values-eu/strings.xml
index 3d79ae2..a5aa06e 100644
--- a/packages/SystemUI/res-keyguard/values-eu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-eu/strings.xml
@@ -53,6 +53,8 @@
<string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"Hurrengo alarmak ordu honetan joko du: <xliff:g id="ALARM">%1$s</xliff:g>"</string>
<string name="keyboardview_keycode_delete" msgid="6883116827512721630">"Ezabatu"</string>
<string name="disable_carrier_button_text" msgid="6914341927421916114">"Desgaitu eSIM txartela"</string>
+ <string name="error_disable_esim_title" msgid="4852978431156228006">"Ezin da desgaitu eSIM txartela"</string>
+ <string name="error_disable_esim_msg" msgid="676694908770135639">"Errore bat gertatu da eta ezin da desgaitu eSIM txartela."</string>
<string name="keyboardview_keycode_enter" msgid="4505833604411016668">"Sartu"</string>
<string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"Eredua ahaztu zaizu"</string>
<string name="kg_wrong_pattern" msgid="7620081431514773802">"Eredu hori ez da zuzena"</string>
@@ -65,7 +67,7 @@
<string name="kg_pattern_instructions" msgid="5547646893001491340">"Marraztu eredua"</string>
<string name="kg_sim_pin_instructions" msgid="6389000973113699187">"Idatzi SIM txartelaren PIN kodea."</string>
<string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"Idatzi \"<xliff:g id="CARRIER">%1$s</xliff:g>\" operadorearen SIM txartelaren PIN kodea."</string>
- <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"Desgaitu eSIM txartela gailua zerbitzu mugikorrik gabe erabiltzeko."</string>
+ <string name="kg_sim_lock_esim_instructions" msgid="4416732549172148542">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Desgaitu eSIM txartela gailua zerbitzu mugikorrik gabe erabiltzeko."</string>
<string name="kg_pin_instructions" msgid="4069609316644030034">"Idatzi PIN kodea"</string>
<string name="kg_password_instructions" msgid="136952397352976538">"Idatzi pasahitza"</string>
<string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"Desgaitu egin da SIM txartela. Aurrera egiteko, idatzi PUK kodea. Xehetasunak lortzeko, jarri operadorearekin harremanetan."</string>
diff --git a/packages/SystemUI/res-keyguard/values-hy/strings.xml b/packages/SystemUI/res-keyguard/values-hy/strings.xml
index 2936935..fec903e 100644
--- a/packages/SystemUI/res-keyguard/values-hy/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hy/strings.xml
@@ -53,6 +53,8 @@
<string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"Հաջորդ զարթուցիչը դրված է <xliff:g id="ALARM">%1$s</xliff:g>-ի վրա"</string>
<string name="keyboardview_keycode_delete" msgid="6883116827512721630">"Ջնջել"</string>
<string name="disable_carrier_button_text" msgid="6914341927421916114">"Անջատել էլեկտրոնային SIM քարտը"</string>
+ <string name="error_disable_esim_title" msgid="4852978431156228006">"Չհաջողվեց անջատել eSIM-ը"</string>
+ <string name="error_disable_esim_msg" msgid="676694908770135639">"Սխալի պատճառով չհաջողվեց անջատել eSIM-ը։"</string>
<string name="keyboardview_keycode_enter" msgid="4505833604411016668">"Մուտքի ստեղն"</string>
<string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"Մոռացել եմ նախշը"</string>
<string name="kg_wrong_pattern" msgid="7620081431514773802">"Նախշը սխալ է"</string>
@@ -65,7 +67,7 @@
<string name="kg_pattern_instructions" msgid="5547646893001491340">"Մուտքագրեք նախշը"</string>
<string name="kg_sim_pin_instructions" msgid="6389000973113699187">"Մուտքագրեք SIM քարտի PIN կոդը։"</string>
<string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"Մուտքագրեք SIM քարտի PIN կոդը «<xliff:g id="CARRIER">%1$s</xliff:g>»-ի համար:"</string>
- <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"Անջատել էլեկտրոնային SIM քարտը՝ սարքն առանց բջջային ծառայությունների օգտագործելու համար:"</string>
+ <string name="kg_sim_lock_esim_instructions" msgid="4416732549172148542">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Անջատեք eSIM-ը՝ սարքն առանց բջջային կապի օգտագործելու համար։"</string>
<string name="kg_pin_instructions" msgid="4069609316644030034">"Մուտքագրեք PIN-ը"</string>
<string name="kg_password_instructions" msgid="136952397352976538">"Մուտքագրեք գաղտնաբառը"</string>
<string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"SIM քարտն այժմ անջատված է: Շարունակելու համար մուտքագրեք PUK կոդը: Մանրամասն տեղեկություններ ստանալու համար դիմեք օպերատորին:"</string>
diff --git a/packages/SystemUI/res-keyguard/values-uz/strings.xml b/packages/SystemUI/res-keyguard/values-uz/strings.xml
index 3272cb2..07198c7c 100644
--- a/packages/SystemUI/res-keyguard/values-uz/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-uz/strings.xml
@@ -53,10 +53,8 @@
<string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"Signal <xliff:g id="ALARM">%1$s</xliff:g> da chalinadi."</string>
<string name="keyboardview_keycode_delete" msgid="6883116827512721630">"O‘chirib tashlash"</string>
<string name="disable_carrier_button_text" msgid="6914341927421916114">"eSIMni faolsizlantirish"</string>
- <!-- no translation found for error_disable_esim_title (4852978431156228006) -->
- <skip />
- <!-- no translation found for error_disable_esim_msg (676694908770135639) -->
- <skip />
+ <string name="error_disable_esim_title" msgid="4852978431156228006">"eSIM faolsizlantirilmadi"</string>
+ <string name="error_disable_esim_msg" msgid="676694908770135639">"Xatolik tufayli eSIM faolsizlantirilmadi."</string>
<string name="keyboardview_keycode_enter" msgid="4505833604411016668">"Enter tugmasi"</string>
<string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"Grafik kalit esimdan chiqdi"</string>
<string name="kg_wrong_pattern" msgid="7620081431514773802">"Grafik kalit xato"</string>
@@ -69,8 +67,7 @@
<string name="kg_pattern_instructions" msgid="5547646893001491340">"Grafik kalit chizing"</string>
<string name="kg_sim_pin_instructions" msgid="6389000973113699187">"SIM karta PIN kodini kiriting."</string>
<string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"“<xliff:g id="CARRIER">%1$s</xliff:g>” SIM kartasi PIN kodini kiriting."</string>
- <!-- no translation found for kg_sim_lock_esim_instructions (4416732549172148542) -->
- <skip />
+ <string name="kg_sim_lock_esim_instructions" msgid="4416732549172148542">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Qurilmadan mobil xizmatlarsiz foydalanish uchun eSIMni faolsizlantiring."</string>
<string name="kg_pin_instructions" msgid="4069609316644030034">"PIN kodni kiriting"</string>
<string name="kg_password_instructions" msgid="136952397352976538">"Parol kiriting"</string>
<string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"SIM karta hozir o‘chirilgan. Davom etish uchun PUK kodni kiriting. Batafsil axborot olish uchun tarmoq operatori bilan bog‘laning."</string>
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_quick_step.png
new file mode 100644
index 0000000..2d62a80
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_quick_step_dark.png
new file mode 100644
index 0000000..a52e5b1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_quick_step.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_quick_step.png
new file mode 100644
index 0000000..d13c730
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_quick_step_dark.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_quick_step_dark.png
new file mode 100644
index 0000000..31c602e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_quick_step.png
new file mode 100644
index 0000000..ddbcb07
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_quick_step_dark.png
new file mode 100644
index 0000000..ce91fcbb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_quick_step.png
new file mode 100644
index 0000000..c606a58
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_quick_step_dark.png
new file mode 100644
index 0000000..c2a5fef
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/car_ic_hvac.xml b/packages/SystemUI/res/drawable/car_ic_hvac.xml
new file mode 100644
index 0000000..bdc44b3
--- /dev/null
+++ b/packages/SystemUI/res/drawable/car_ic_hvac.xml
@@ -0,0 +1,51 @@
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="37dp"
+ android:height="31dp"
+ android:viewportWidth="37"
+ android:viewportHeight="31">
+
+ <group
+ android:translateX="-4.000000"
+ android:translateY="-6.000000">
+ <group
+ android:translateX="5.000000"
+ android:translateY="5.000000">
+ <path
+ android:fillType="evenOdd"
+ android:strokeColor="#FAFAFA"
+ android:strokeWidth="3.5"
+ android:pathData="M0.320769938,6.07518051 C6.46754647,1.46509811 12.4222362,1.46509811
+18.1848392,6.07518051 C23.9474422,10.6852629 29.3258717,10.4931761
+34.3201276,5.49892021" />
+ <path
+ android:fillType="evenOdd"
+ android:strokeColor="#FAFAFA"
+ android:strokeWidth="3.5"
+ android:pathData="M0.320769938,17.0751805 C6.46754647,12.4650981 12.4222362,12.4650981
+18.1848392,17.0751805 C23.9474422,21.6852629 29.3258717,21.4931761
+34.3201276,16.4989202" />
+ <path
+ android:fillType="evenOdd"
+ android:strokeColor="#FAFAFA"
+ android:strokeWidth="3.5"
+ android:pathData="M0.320769938,28.0751805 C6.46754647,23.4650981 12.4222362,23.4650981
+18.1848392,28.0751805 C23.9474422,32.6852629 29.3258717,32.4931761
+34.3201276,27.4989202" />
+ </group>
+ </group>
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/car_ic_notification.xml b/packages/SystemUI/res/drawable/car_ic_notification.xml
new file mode 100644
index 0000000..61d937b90
--- /dev/null
+++ b/packages/SystemUI/res/drawable/car_ic_notification.xml
@@ -0,0 +1,28 @@
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="56dp"
+ android:height="56dp"
+ android:viewportWidth="48"
+ android:viewportHeight="48">
+
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M24 44c2.21 0 4-1.79 4-4h-8c0 2.21 1.79 4 4
+4zm12-12V22c0-6.15-3.27-11.28-9-12.64V8c0-1.66-1.34-3-3-3s-3 1.34-3 3v1.36c-5.73
+1.36-9 6.49-9 12.64v10l-4 4v2h32v-2l-4-4zm-4 2H16V22c0-4.97 3.03-9 8-9s8 4.03 8
+9v12z" />
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/car_ic_overview.xml b/packages/SystemUI/res/drawable/car_ic_overview.xml
new file mode 100644
index 0000000..4651dcb
--- /dev/null
+++ b/packages/SystemUI/res/drawable/car_ic_overview.xml
@@ -0,0 +1,28 @@
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="56dp"
+ android:height="56dp"
+ android:viewportWidth="48"
+ android:viewportHeight="48">
+
+ <path
+ android:pathData="M0 0h48v48H0z" />
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M24 4C12.95 4 4 12.95 4 24s8.95 20 20 20 20-8.95 20-20S35.05 4 24 4zm0 36c-8.82
+0-16-7.18-16-16S15.18 8 24 8s16 7.18 16 16-7.18 16-16 16z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_lock_lockdown.xml b/packages/SystemUI/res/drawable/ic_lock_lockdown.xml
new file mode 100644
index 0000000..b517fc8
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_lock_lockdown.xml
@@ -0,0 +1,25 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+
+ <path
+ android:fillColor="#757575"
+ android:pathData="M18.0,8.0l-1.0,0.0L17.0,6.0c0.0,-2.8 -2.2,-5.0 -5.0,-5.0C9.2,1.0 7.0,3.2 7.0,6.0l0.0,2.0L6.0,8.0c-1.1,0.0 -2.0,0.9 -2.0,2.0l0.0,10.0c0.0,1.1 0.9,2.0 2.0,2.0l12.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L20.0,10.0C20.0,8.9 19.1,8.0 18.0,8.0zM12.0,17.0c-1.1,0.0 -2.0,-0.9 -2.0,-2.0s0.9,-2.0 2.0,-2.0c1.1,0.0 2.0,0.9 2.0,2.0S13.1,17.0 12.0,17.0zM15.1,8.0L8.9,8.0L8.9,6.0c0.0,-1.7 1.4,-3.1 3.1,-3.1c1.7,0.0 3.1,1.4 3.1,3.1L15.1,8.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/logout_button_background.xml b/packages/SystemUI/res/drawable/logout_button_background.xml
new file mode 100644
index 0000000..eafd663
--- /dev/null
+++ b/packages/SystemUI/res/drawable/logout_button_background.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ 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
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="@color/logout_button_bg_color"/>
+ <corners android:radius="@dimen/logout_button_corner_radius"/>
+</shape>
diff --git a/packages/SystemUI/res/layout/car_facet_button.xml b/packages/SystemUI/res/layout/car_facet_button.xml
new file mode 100644
index 0000000..f432d36
--- /dev/null
+++ b/packages/SystemUI/res/layout/car_facet_button.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 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.
+*/
+-->
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+ <LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/car_facet_button"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:gravity="center"
+ android:animateLayoutChanges="true"
+ android:orientation="vertical">
+
+ <com.android.keyguard.AlphaOptimizedImageButton
+ android:id="@+id/car_nav_button_icon"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:animateLayoutChanges="true"
+ android:background="@android:color/transparent"
+ android:scaleType="fitCenter">
+ </com.android.keyguard.AlphaOptimizedImageButton>
+
+ <com.android.keyguard.AlphaOptimizedImageButton
+ android:id="@+id/car_nav_button_more_icon"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:animateLayoutChanges="true"
+ android:background="@android:color/transparent"
+ android:scaleType="fitCenter">
+ </com.android.keyguard.AlphaOptimizedImageButton>
+
+ </LinearLayout>
+</merge>
diff --git a/packages/SystemUI/res/layout/car_left_navigation_bar.xml b/packages/SystemUI/res/layout/car_left_navigation_bar.xml
new file mode 100644
index 0000000..866b5a5
--- /dev/null
+++ b/packages/SystemUI/res/layout/car_left_navigation_bar.xml
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 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.
+*/
+-->
+
+<com.android.systemui.statusbar.car.CarNavigationBarView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res-auto"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:orientation="vertical"
+ android:background="@drawable/system_bar_background">
+
+ <LinearLayout
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:id="@+id/nav_buttons"
+ android:orientation="vertical"
+ android:gravity="top"
+ android:paddingTop="30dp"
+ android:layout_weight="1"
+ android:background="@drawable/system_bar_background"
+ android:animateLayoutChanges="true">
+
+ <com.android.systemui.statusbar.car.CarNavigationButton
+ android:id="@+id/home"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;end"
+ android:src="@drawable/car_ic_overview"
+ android:background="?android:attr/selectableItemBackground"
+ android:paddingTop="30dp"
+ android:paddingBottom="30dp"
+ />
+
+ <com.android.systemui.statusbar.car.CarNavigationButton
+ android:id="@+id/hvac"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ systemui:intent="intent:#Intent;action=android.car.intent.action.SHOW_HVAC_CONTROLS;end"
+ systemui:broadcast="true"
+ android:src="@drawable/car_ic_hvac"
+ android:background="?android:attr/selectableItemBackground"
+ android:paddingTop="30dp"
+ android:paddingBottom="30dp"
+ />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:gravity="bottom"
+ android:orientation="vertical">
+
+ <com.android.keyguard.AlphaOptimizedImageButton
+ android:id="@+id/notifications"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:src="@drawable/car_ic_notification"
+ android:background="?android:attr/selectableItemBackground"
+ android:paddingTop="20dp"
+ android:paddingBottom="20dp"
+ android:alpha="0.7"
+ />
+
+ <com.android.systemui.statusbar.policy.Clock
+ android:id="@+id/clock"
+ android:textAppearance="@style/TextAppearance.StatusBar.Clock"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:singleLine="true"
+ android:paddingStart="@dimen/status_bar_clock_starting_padding"
+ android:paddingEnd="@dimen/status_bar_clock_end_padding"
+ android:gravity="center_horizontal"
+ android:paddingBottom="20dp"
+ />
+
+ <Space
+ android:layout_height="10dp"
+ android:layout_width="match_parent"/>
+
+ </LinearLayout>
+
+</com.android.systemui.statusbar.car.CarNavigationBarView>
diff --git a/packages/SystemUI/res/layout/car_navigation_bar.xml b/packages/SystemUI/res/layout/car_navigation_bar.xml
index 999dbac..4666c60 100644
--- a/packages/SystemUI/res/layout/car_navigation_bar.xml
+++ b/packages/SystemUI/res/layout/car_navigation_bar.xml
@@ -19,34 +19,80 @@
<com.android.systemui.statusbar.car.CarNavigationBarView
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res-auto"
android:layout_height="match_parent"
android:layout_width="match_parent"
- android:gravity="center"
android:background="@drawable/system_bar_background">
- <!-- phone.NavigationBarView has rot0 and rot90 but we expect the car head unit to have a fixed
- rotation so skip this level of the heirarchy.
- -->
<LinearLayout
android:layout_height="match_parent"
- android:layout_width="@dimen/car_navigation_bar_width"
+ android:layout_width="wrap_content"
android:orientation="horizontal"
- android:clipChildren="false"
- android:clipToPadding="false"
android:id="@+id/nav_buttons"
+ android:gravity="left"
+ android:paddingLeft="30dp"
+ android:layout_weight="1"
android:animateLayoutChanges="true">
- <!-- Buttons get populated here from a car_arrays.xml. -->
+ <com.android.systemui.statusbar.car.CarNavigationButton
+ android:id="@+id/home"
+ android:layout_height="match_parent"
+ android:layout_width="wrap_content"
+ systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;end"
+ android:src="@drawable/car_ic_overview"
+ android:background="?android:attr/selectableItemBackground"
+ android:paddingLeft="30dp"
+ android:paddingRight="30dp"
+ />
+
+ <com.android.systemui.statusbar.car.CarNavigationButton
+ android:id="@+id/hvac"
+ android:layout_height="match_parent"
+ android:layout_width="wrap_content"
+ systemui:intent="intent:#Intent;action=android.car.intent.action.SHOW_HVAC_CONTROLS;end"
+ systemui:broadcast="true"
+ android:src="@drawable/car_ic_hvac"
+ android:background="?android:attr/selectableItemBackground"
+ android:paddingLeft="30dp"
+ android:paddingRight="30dp"
+ />
</LinearLayout>
- <!-- lights out layout to match exactly -->
<LinearLayout
+ android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:layout_width="match_parent"
- android:orientation="horizontal"
- android:id="@+id/lights_out"
- android:visibility="gone">
- <!-- Must match nav_buttons. -->
+ android:layout_weight="1"
+ android:gravity="right"
+ android:orientation="horizontal">
+
+ <com.android.keyguard.AlphaOptimizedImageButton
+ android:id="@+id/notifications"
+ android:layout_height="match_parent"
+ android:layout_width="wrap_content"
+ android:src="@drawable/car_ic_notification"
+ android:background="?android:attr/selectableItemBackground"
+ android:paddingLeft="20dp"
+ android:paddingRight="20dp"
+ android:alpha="0.7"
+ />
+
+ <com.android.systemui.statusbar.policy.Clock
+ android:id="@+id/clock"
+ android:textAppearance="@style/TextAppearance.StatusBar.Clock"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:singleLine="true"
+ android:paddingStart="@dimen/status_bar_clock_starting_padding"
+ android:paddingEnd="@dimen/status_bar_clock_end_padding"
+ android:gravity="center_vertical"
+ android:paddingRight="20dp"
+ />
+
+ <Space
+ android:layout_width="10dp"
+ android:layout_height="match_parent"/>
+
</LinearLayout>
</com.android.systemui.statusbar.car.CarNavigationBarView>
+
diff --git a/packages/SystemUI/res/layout/car_navigation_button.xml b/packages/SystemUI/res/layout/car_navigation_button.xml
index 7677646..4062eb8 100644
--- a/packages/SystemUI/res/layout/car_navigation_button.xml
+++ b/packages/SystemUI/res/layout/car_navigation_button.xml
@@ -17,28 +17,13 @@
*/
-->
-<com.android.systemui.statusbar.car.CarNavigationButton
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_height="match_parent"
- android:layout_width="wrap_content"
- android:orientation="horizontal"
- android:background="?android:attr/selectableItemBackground">
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
<com.android.keyguard.AlphaOptimizedImageButton
- android:id="@+id/car_nav_button_icon"
- android:layout_height="match_parent"
- android:layout_width="@dimen/car_navigation_button_width"
- android:layout_centerInParent="true"
- android:animateLayoutChanges="true"
- android:scaleType="fitCenter">
+ android:id="@+id/car_nav_button_icon"
+ android:layout_height="wrap_content"
+ android:layout_width="@dimen/car_navigation_button_width"
+ android:layout_centerInParent="true"
+ android:animateLayoutChanges="true"
+ android:scaleType="fitCenter">
</com.android.keyguard.AlphaOptimizedImageButton>
-
- <com.android.keyguard.AlphaOptimizedImageButton
- android:id="@+id/car_nav_button_more_icon"
- android:layout_height="match_parent"
- android:layout_width="wrap_content"
- android:layout_centerVertical="true"
- android:layout_toRightOf="@+id/car_nav_button_icon"
- android:animateLayoutChanges="true"
- android:scaleType="fitCenter">
- </com.android.keyguard.AlphaOptimizedImageButton>
-</com.android.systemui.statusbar.car.CarNavigationButton>
+</merge>
diff --git a/packages/SystemUI/res/layout/car_right_navigation_bar.xml b/packages/SystemUI/res/layout/car_right_navigation_bar.xml
new file mode 100644
index 0000000..99ab802
--- /dev/null
+++ b/packages/SystemUI/res/layout/car_right_navigation_bar.xml
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 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.
+*/
+-->
+
+<com.android.systemui.statusbar.car.CarNavigationBarView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res-auto"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:orientation="vertical"
+ android:background="@drawable/system_bar_background">
+
+ <LinearLayout
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:id="@+id/nav_buttons"
+ android:orientation="vertical"
+ android:gravity="top"
+ android:paddingTop="30dp"
+ android:layout_weight="1"
+ android:background="@drawable/system_bar_background"
+ android:animateLayoutChanges="true">
+
+ <com.android.systemui.statusbar.car.CarNavigationButton
+ android:id="@+id/home"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;end"
+ android:src="@drawable/car_ic_overview"
+ android:background="?android:attr/selectableItemBackground"
+ android:paddingTop="30dp"
+ android:paddingBottom="30dp"
+ />
+
+ <com.android.systemui.statusbar.car.CarNavigationButton
+ android:id="@+id/hvac"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ systemui:intent="intent:#Intent;action=android.car.intent.action.SHOW_HVAC_CONTROLS;end"
+ systemui:broadcast="true"
+ android:src="@drawable/car_ic_hvac"
+ android:background="?android:attr/selectableItemBackground"
+ android:paddingTop="30dp"
+ android:paddingBottom="30dp"
+ />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:gravity="bottom"
+ android:orientation="vertical">
+
+ <com.android.keyguard.AlphaOptimizedImageButton
+ android:id="@+id/notifications"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:src="@drawable/car_ic_notification"
+ android:background="?android:attr/selectableItemBackground"
+ android:paddingTop="20dp"
+ android:paddingBottom="20dp"
+ android:alpha="0.7"
+ />
+
+
+ <com.android.systemui.statusbar.policy.Clock
+ android:id="@+id/clock"
+ android:textAppearance="@style/TextAppearance.StatusBar.Clock"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:singleLine="true"
+ android:paddingStart="@dimen/status_bar_clock_starting_padding"
+ android:paddingEnd="@dimen/status_bar_clock_end_padding"
+ android:gravity="center_horizontal"
+ android:paddingBottom="20dp"
+ />
+
+ <Space
+ android:layout_height="10dp"
+ android:layout_width="match_parent"/>
+
+ </LinearLayout>
+
+</com.android.systemui.statusbar.car.CarNavigationBarView>
diff --git a/packages/SystemUI/res/layout/menu_ime.xml b/packages/SystemUI/res/layout/menu_ime.xml
index 8078c41..2470947 100644
--- a/packages/SystemUI/res/layout/menu_ime.xml
+++ b/packages/SystemUI/res/layout/menu_ime.xml
@@ -41,6 +41,15 @@
android:scaleType="centerInside"
/>
<com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/rotate_suggestion"
+ android:layout_width="@dimen/navigation_extra_key_width"
+ android:layout_height="match_parent"
+ android:layout_marginEnd="2dp"
+ android:visibility="invisible"
+ android:scaleType="centerInside"
+ android:contentDescription="@string/accessibility_rotate_button"
+ />
+ <com.android.systemui.statusbar.policy.KeyButtonView
android:id="@+id/accessibility_button"
android:layout_width="@dimen/navigation_extra_key_width"
android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/qs_footer_impl.xml b/packages/SystemUI/res/layout/qs_footer_impl.xml
index 97472a4..cf88ade 100644
--- a/packages/SystemUI/res/layout/qs_footer_impl.xml
+++ b/packages/SystemUI/res/layout/qs_footer_impl.xml
@@ -71,23 +71,19 @@
android:singleLine="true" />
</LinearLayout>
- <FrameLayout
+ <View
+ android:id="@+id/qs_drag_handle_view"
android:layout_width="24dp"
- android:layout_height="match_parent" >
- <View
- android:id="@+id/qs_drag_handle_view"
- android:layout_width="match_parent"
- android:layout_height="4dp"
- android:layout_marginTop="28dp"
- android:background="@drawable/qs_footer_drag_handle" />
- </FrameLayout>
+ android:layout_height="4dp"
+ android:layout_gravity="center"
+ android:background="@drawable/qs_footer_drag_handle" />
- <LinearLayout
+ <com.android.keyguard.AlphaOptimizedLinearLayout
android:id="@+id/qs_footer_actions_container"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
- android:gravity="end" >
+ android:gravity="center_vertical|end" >
<com.android.systemui.statusbar.phone.MultiUserSwitch
android:id="@+id/multi_user_switch"
android:layout_width="48dp"
@@ -113,7 +109,7 @@
android:clipToPadding="false"
android:contentDescription="@string/accessibility_quick_settings_edit"
android:focusable="true"
- android:padding="16dp"
+ android:padding="15dp"
android:src="@drawable/ic_mode_edit"
android:tint="?android:attr/colorForeground"/>
@@ -131,6 +127,7 @@
android:layout_height="match_parent"
android:background="@drawable/ripple_drawable"
android:contentDescription="@string/accessibility_quick_settings_settings"
+ android:padding="15dp"
android:src="@drawable/ic_settings_16dp"
android:tint="?android:attr/colorForeground"/>
@@ -145,7 +142,7 @@
android:visibility="invisible"/>
</com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
- </LinearLayout>
+ </com.android.keyguard.AlphaOptimizedLinearLayout>
</LinearLayout>
</com.android.systemui.qs.QSFooterImpl>
diff --git a/packages/SystemUI/res/layout/quick_settings_header.xml b/packages/SystemUI/res/layout/quick_settings_header.xml
new file mode 100644
index 0000000..43197c4
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_settings_header.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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
+ -->
+<com.android.systemui.qs.QSTooltipView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/qs_header_tooltip_height"
+ android:alpha="0"
+ android:gravity="center_horizontal|bottom"
+ android:visibility="invisible">
+
+ <TextView
+ android:id="@+id/header_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/quick_settings_header_onboarding_text"
+ android:textAppearance="@style/TextAppearance.QS.TileLabel"
+ android:textColor="?android:attr/colorAccent" />
+
+</com.android.systemui.qs.QSTooltipView>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 39895acb..9ebd492 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -103,12 +103,9 @@
<string name="camera_label" msgid="7261107956054836961">"åbn kamera"</string>
<string name="recents_caption_resize" msgid="3517056471774958200">"Vælg nyt opgavelayout"</string>
<string name="cancel" msgid="6442560571259935130">"Annuller"</string>
- <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
- <skip />
- <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
- <skip />
- <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
- <skip />
+ <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ikon for fingeraftryk"</string>
+ <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Appens ikon"</string>
+ <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Område med hjælpemeddelelse"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Knap for kompatibilitetszoom."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom mindre til større skærm."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth tilsluttet."</string>
@@ -311,6 +308,7 @@
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi slået fra"</string>
<string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"Wi-Fi er slået til"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Der er ingen tilgængelige Wi-Fi-netværk"</string>
+ <string name="quick_settings_alarm_title" msgid="2416759007342260676">"Alarm"</string>
<string name="quick_settings_cast_title" msgid="7709016546426454729">"Cast"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Caster"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Enhed uden navn"</string>
@@ -327,9 +325,11 @@
<string name="quick_settings_connecting" msgid="47623027419264404">"Opretter forbindelse…"</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Netdeling"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
- <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
- <skip />
- <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+ <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"Aktiverer…"</string>
+ <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+ <item quantity="one">%d enhed</item>
+ <item quantity="other">%d enheder</item>
+ </plurals>
<string name="quick_settings_notifications_label" msgid="4818156442169154523">"Underretninger"</string>
<string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Lommelygte"</string>
<string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"Mobildata"</string>
@@ -339,10 +339,8 @@
<string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> brugt"</string>
<string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Grænse: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Advarsel ved <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_work_mode_on_label (3421274215098764735) -->
- <skip />
- <!-- no translation found for quick_settings_work_mode_off_label (8856918707867192186) -->
- <skip />
+ <string name="quick_settings_work_mode_on_label" msgid="3421274215098764735">"Arbejdsprofil"</string>
+ <string name="quick_settings_work_mode_off_label" msgid="8856918707867192186">"Underretninger og apps er slået fra"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Nattelys"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"Tænd ved solnedgang"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"Indtil solopgang"</string>
@@ -360,8 +358,6 @@
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> er deaktiveret i sikker tilstand."</string>
<string name="recents_stack_action_button_label" msgid="6593727103310426253">"Ryd alle"</string>
<string name="recents_drag_hint_message" msgid="2649739267073203985">"Træk hertil for at bruge delt skærm"</string>
- <!-- no translation found for recents_swipe_up_onboarding (3824607135920170001) -->
- <skip />
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Opdel vandret"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Opdel lodret"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Opdel brugerdefineret"</string>
@@ -502,11 +498,18 @@
<string name="volume_zen_end_now" msgid="6930243045593601084">"Deaktiver nu"</string>
<string name="accessibility_volume_expand" msgid="5946812790999244205">"Udvid"</string>
<string name="accessibility_volume_collapse" msgid="3609549593031810875">"Skjul"</string>
+ <string name="accessibility_output_chooser" msgid="8185317493017988680">"Skift enhed til lydudgang"</string>
<string name="screen_pinning_title" msgid="3273740381976175811">"Skærmen er fastgjort"</string>
<string name="screen_pinning_description" msgid="8909878447196419623">"Dette fastholder skærmen i visningen, indtil du frigør den. Tryk på Tilbage og Overblik, og hold fingeren nede for at frigøre skærmen."</string>
+ <string name="screen_pinning_description_recents_invisible" msgid="8281145542163727971">"Dette fastholder skærmen i visningen, indtil du frigør den. Hold Tilbage og Startskærm nede for at frigøre skærmen."</string>
<string name="screen_pinning_description_accessible" msgid="426190689254018656">"Dette fastholder skærmen i visningen, indtil du frigør den. Tryk på Tilbage, og hold fingeren nede for at frigøre skærmen."</string>
+ <string name="screen_pinning_description_recents_invisible_accessible" msgid="6134833683151189507">"Dette fastholder skærmen i visningen, indtil du frigør den. Hold Startskærm nede for at frigøre skærmen."</string>
+ <string name="screen_pinning_toast" msgid="2266705122951934150">"Hold knapperne Tilbage og Oversigt nede for at frigøre skærmen"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="8252402309499161281">"Hold knapperne Tilbage og Startskærm nede for at frigøre skærmen"</string>
<string name="screen_pinning_positive" msgid="3783985798366751226">"OK, det er forstået"</string>
<string name="screen_pinning_negative" msgid="3741602308343880268">"Nej tak"</string>
+ <string name="screen_pinning_start" msgid="1022122128489278317">"Skærmen blev fastgjort"</string>
+ <string name="screen_pinning_exit" msgid="5187339744262325372">"Skærmen blev frigjort"</string>
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Vil du skjule <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Den vises igen, næste gang du aktiverer den i indstillingerne."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Skjul"</string>
@@ -586,8 +589,7 @@
<string name="power_notification_controls_description" msgid="4372459941671353358">"Med kontrolelementer til underretninger om strøm kan du konfigurere et vigtighedsniveau fra 0 til 5 for en apps underretninger. \n\n"<b>"Niveau 5"</b>\n"- Vis øverst på listen over underretninger \n- Tillad afbrydelse af fuld skærm \n- Se altid smugkig \n\n"<b>"Niveau 4"</b>\n"- Ingen afbrydelse af fuld skærm \n- Se altid smugkig \n\n"<b>"Niveau 3"</b>\n"- Ingen afbrydelse af fuld skærm \n- Se aldrig smugkig \n\n"<b>"Niveau 2"</b>\n"- Ingen afbrydelse af fuld skærm \n Se aldrig smugkig \n- Ingen lyd og vibration \n\n"<b>"Niveau 1"</b>\n"- Ingen afbrydelse af fuld skærm \n- Se aldrig smugkig \n- Ingen lyd eller vibration \n- Skjul fra låseskærm og statusbjælke \n- Vis nederst på listen over underretninger \n\n"<b>"Niveau 0"</b>\n"- Bloker alle underretninger fra appen."</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Underretninger"</string>
<string name="notification_channel_disabled" msgid="344536703863700565">"Du får ikke længere vist disse underretninger"</string>
- <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
- <skip />
+ <string name="inline_blocking_helper" msgid="3055064577771478591">"Du afviser som regel disse underretninger. \nVil du blive ved med at se dem?"</string>
<string name="inline_keep_showing" msgid="8945102997083836858">"Vil du fortsætte med at se disse underretninger?"</string>
<string name="inline_stop_button" msgid="4172980096860941033">"Stop underretninger"</string>
<string name="inline_keep_button" msgid="6665940297019018232">"Fortsæt med at vise underretninger"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 1c46eba..9b52656 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -103,12 +103,9 @@
<string name="camera_label" msgid="7261107956054836961">"ireki kamera"</string>
<string name="recents_caption_resize" msgid="3517056471774958200">"Hautatu zereginen diseinua"</string>
<string name="cancel" msgid="6442560571259935130">"Utzi"</string>
- <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
- <skip />
- <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
- <skip />
- <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
- <skip />
+ <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Hatz-markaren ikonoa"</string>
+ <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Aplikazioaren ikonoa"</string>
+ <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Laguntza-mezuaren eremua"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Zoom-bateragarritasunaren botoia."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Handiagotu pantaila txikia."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetootha konektatuta."</string>
@@ -313,6 +310,7 @@
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi konexioa desaktibatuta"</string>
<string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"Aktibatuta dago Wi-Fi konexioa"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Ez dago Wi-Fi sarerik erabilgarri"</string>
+ <string name="quick_settings_alarm_title" msgid="2416759007342260676">"Alarma"</string>
<string name="quick_settings_cast_title" msgid="7709016546426454729">"Cast"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Igortzen"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Izenik gabeko gailua"</string>
@@ -329,9 +327,11 @@
<string name="quick_settings_connecting" msgid="47623027419264404">"Konektatzen…"</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Konexioa partekatzea"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Sare publikoa"</string>
- <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
- <skip />
- <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+ <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"Aktibatzen…"</string>
+ <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+ <item quantity="other">%d gailu</item>
+ <item quantity="one">%d gailu</item>
+ </plurals>
<string name="quick_settings_notifications_label" msgid="4818156442169154523">"Jakinarazpenak"</string>
<string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Linterna"</string>
<string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"Datu mugikorrak"</string>
@@ -341,10 +341,8 @@
<string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> erabilita"</string>
<string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Muga: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Abisua: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_work_mode_on_label (3421274215098764735) -->
- <skip />
- <!-- no translation found for quick_settings_work_mode_off_label (8856918707867192186) -->
- <skip />
+ <string name="quick_settings_work_mode_on_label" msgid="3421274215098764735">"Laneko profila"</string>
+ <string name="quick_settings_work_mode_off_label" msgid="8856918707867192186">"Jakinarazpenak eta aplikazioak desaktibatuta daude"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Gaueko argia"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"Ilunabarrean"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"Ilunabarrera arte"</string>
@@ -362,8 +360,6 @@
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> desgaituta dago modu seguruan."</string>
<string name="recents_stack_action_button_label" msgid="6593727103310426253">"Garbitu guztiak"</string>
<string name="recents_drag_hint_message" msgid="2649739267073203985">"Arrastatu hau pantaila zatitzeko"</string>
- <!-- no translation found for recents_swipe_up_onboarding (3824607135920170001) -->
- <skip />
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Zatitze horizontala"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Zatitze bertikala"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Zatitze pertsonalizatua"</string>
@@ -504,11 +500,18 @@
<string name="volume_zen_end_now" msgid="6930243045593601084">"Desaktibatu"</string>
<string name="accessibility_volume_expand" msgid="5946812790999244205">"Zabaldu"</string>
<string name="accessibility_volume_collapse" msgid="3609549593031810875">"Tolestu"</string>
+ <string name="accessibility_output_chooser" msgid="8185317493017988680">"Aldatu irteerako gailua"</string>
<string name="screen_pinning_title" msgid="3273740381976175811">"Pantaila ainguratuta dago"</string>
<string name="screen_pinning_description" msgid="8909878447196419623">"Horrela, ikusgai egongo da aingura kendu arte. Aingura kentzeko, eduki sakatuta \"Atzera\" eta \"Ikuspegi orokorra\" botoiak."</string>
+ <string name="screen_pinning_description_recents_invisible" msgid="8281145542163727971">"Horrela, ikusgai egongo da aingura kendu arte. Aingura kentzeko, eduki sakatuta Atzera eta Hasiera botoiak."</string>
<string name="screen_pinning_description_accessible" msgid="426190689254018656">"Horrela, ikusgai egongo da aingura kendu arte. Aingura kentzeko, eduki sakatuta \"Ikuspegi orokorra\" botoia."</string>
+ <string name="screen_pinning_description_recents_invisible_accessible" msgid="6134833683151189507">"Horrela, ikusgai egongo da aingura kendu arte. Aingura kentzeko, eduki sakatuta Hasiera botoia."</string>
+ <string name="screen_pinning_toast" msgid="2266705122951934150">"Pantailari aingura kentzeko, eduki sakatuta Atzera eta Ikuspegi orokorra botoiak"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="8252402309499161281">"Pantailari aingura kentzeko, eduki sakatuta Atzera eta Hasiera botoiak"</string>
<string name="screen_pinning_positive" msgid="3783985798366751226">"Ados"</string>
<string name="screen_pinning_negative" msgid="3741602308343880268">"Ez, eskerrik asko"</string>
+ <string name="screen_pinning_start" msgid="1022122128489278317">"Ainguratu da pantaila"</string>
+ <string name="screen_pinning_exit" msgid="5187339744262325372">"Kendu zaio aingura pantailari"</string>
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ezkutatu nahi duzu?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Ezarpenetan aktibatzen duzun hurrengoan agertuko da berriro."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Ezkutatu"</string>
@@ -588,8 +591,7 @@
<string name="power_notification_controls_description" msgid="4372459941671353358">"Bateria-mailaren arabera jakinarazpenak kontrolatzeko aukerekin, 0 eta 5 bitarteko garrantzi-mailetan sailka ditzakezu aplikazioen jakinarazpenak. \n\n"<b>"5. maila"</b>" \n- Erakutsi jakinarazpenen zerrendaren goialdean. \n- Baimendu etetea pantaila osoko moduan zaudenean. \n- Agerrarazi beti jakinarazpenak. \n\n"<b>"4. maila"</b>" \n- Galarazi etetea pantaila osoko moduan zaudenean. \n- Agerrarazi beti jakinarazpenak. \n\n"<b>"3. maila"</b>" \n- Galarazi etetea pantaila osoko moduan zaudenean. \n- Ez agerrarazi jakinarazpenik inoiz. \n\n"<b>"2. maila"</b>" \n- Galarazi etetea pantaila osoko moduan zaudenean. \n- Ez agerrarazi jakinarazpenik inoiz. \n- Ez egin soinurik edo dardararik inoiz. \n\n"<b>"1. maila"</b>" \n- Galarazi etetea pantaila osoko moduan zaudenean. \n- Ez agerrarazi jakinarazpenik inoiz. \n- Ez egin soinurik edo dardararik inoiz. \n- Ezkutatu pantaila blokeatutik eta egoera-barratik. \n- Erakutsi jakinarazpenen zerrendaren behealdean. \n\n"<b>"0. maila"</b>" \n- Blokeatu aplikazioaren jakinarazpen guztiak."</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Jakinarazpenak"</string>
<string name="notification_channel_disabled" msgid="344536703863700565">"Aurrerantzean ez duzu ikusiko horrelako jakinarazpenik"</string>
- <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
- <skip />
+ <string name="inline_blocking_helper" msgid="3055064577771478591">"Baztertu egin ohi dituzu jakinarazpen hauek. \nHaiek erakusten jarraitzea nahi duzu?"</string>
<string name="inline_keep_showing" msgid="8945102997083836858">"Jakinarazpenak erakusten jarraitzea nahi duzu?"</string>
<string name="inline_stop_button" msgid="4172980096860941033">"Blokeatu jakinarazpenak"</string>
<string name="inline_keep_button" msgid="6665940297019018232">"Jarraitu erakusten"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 56ca97c..fe8f6d5 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -310,8 +310,7 @@
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi désactivé"</string>
<string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"Wi-Fi activé"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Aucun réseau Wi-Fi à proximité"</string>
- <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
- <skip />
+ <string name="quick_settings_alarm_title" msgid="2416759007342260676">"Alarme"</string>
<string name="quick_settings_cast_title" msgid="7709016546426454729">"Diffuser"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Diffusion"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Appareil sans nom"</string>
@@ -361,7 +360,6 @@
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> est désactivée en mode sans échec."</string>
<string name="recents_stack_action_button_label" msgid="6593727103310426253">"Effacer tout"</string>
<string name="recents_drag_hint_message" msgid="2649739267073203985">"Glissez l\'élément ici pour utiliser l\'écran partagé"</string>
- <string name="recents_swipe_up_onboarding" msgid="3824607135920170001">"Balayez vers le haut pour changer d\'application"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Séparation horizontale"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Séparation verticale"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Séparation personnalisée"</string>
@@ -505,21 +503,15 @@
<string name="accessibility_output_chooser" msgid="8185317493017988680">"Changer d\'appareil de sortie"</string>
<string name="screen_pinning_title" msgid="3273740381976175811">"L\'écran est épinglé"</string>
<string name="screen_pinning_description" msgid="8909878447196419623">"Cet écran est épinglé jusqu\'à ce que vous annuliez l\'opération. Pour annuler l\'épinglage, maintenez le doigt sur « Retour » et « Aperçu »."</string>
- <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
- <skip />
+ <string name="screen_pinning_description_recents_invisible" msgid="8281145542163727971">"Cet écran est épinglé jusqu\'à ce que vous annuliez l\'opération. Pour annuler l\'épinglage, maintenez le doigt sur les touches Retour et Accueil."</string>
<string name="screen_pinning_description_accessible" msgid="426190689254018656">"Cet écran est épinglé jusqu\'à ce que vous annuliez l\'opération. Pour annuler l\'épinglage, maintenez le doigt sur « Aperçu »."</string>
- <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
- <skip />
+ <string name="screen_pinning_description_recents_invisible_accessible" msgid="6134833683151189507">"Cet écran est épinglé jusqu\'à ce que vous annuliez l\'opération. Pour annuler l\'épinglage, maintenez le doigt sur la touche Accueil."</string>
+ <string name="screen_pinning_toast" msgid="2266705122951934150">"Pour annuler l\'épinglage de cet écran, maintenez le doigt sur les touches Retour et Aperçu."</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="8252402309499161281">"Pour annuler l\'épinglage de cet écran, maintenez le doigt sur les touches Retour et Accueil."</string>
<string name="screen_pinning_positive" msgid="3783985798366751226">"OK"</string>
<string name="screen_pinning_negative" msgid="3741602308343880268">"Non, merci"</string>
- <!-- no translation found for screen_pinning_start (1022122128489278317) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
- <skip />
+ <string name="screen_pinning_start" msgid="1022122128489278317">"Écran épinglé"</string>
+ <string name="screen_pinning_exit" msgid="5187339744262325372">"Épinglage d\'écran annulé"</string>
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Masquer <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Cet élément réapparaîtra la prochaine fois que vous l\'activerez dans les paramètres."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Masquer"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 33d8821..5dc1dfa 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -103,12 +103,9 @@
<string name="camera_label" msgid="7261107956054836961">"բացել ֆոտոխցիկը"</string>
<string name="recents_caption_resize" msgid="3517056471774958200">"Ընտրել առաջադրանքի նոր դասավորություն"</string>
<string name="cancel" msgid="6442560571259935130">"Չեղարկել"</string>
- <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
- <skip />
- <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
- <skip />
- <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
- <skip />
+ <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Մատնահետքի պատկերակ"</string>
+ <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Հավելվածի պատկերակ"</string>
+ <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Օգնության հաղորդագրության դաշտ"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Համատեղելիության խոշորացման կոճակը:"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Դիտափոխել փոքրից ավելի մեծ էկրան:"</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth-ը միացված է:"</string>
@@ -311,6 +308,7 @@
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi-ը անջատված է"</string>
<string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"Wi-Fi-ը միացված է"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Հասանելի Wi-Fi ցանցեր չկան"</string>
+ <string name="quick_settings_alarm_title" msgid="2416759007342260676">"Զարթուցիչ"</string>
<string name="quick_settings_cast_title" msgid="7709016546426454729">"Հեռարձակում"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Հեռարձակում"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Անանուն սարք"</string>
@@ -327,9 +325,11 @@
<string name="quick_settings_connecting" msgid="47623027419264404">"Միանում է..."</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Մոդեմի ռեժիմ"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Թեժ կետ"</string>
- <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
- <skip />
- <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+ <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"Միանում է..."</string>
+ <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+ <item quantity="one">%d սարք</item>
+ <item quantity="other">%d սարք</item>
+ </plurals>
<string name="quick_settings_notifications_label" msgid="4818156442169154523">"Ծանուցումներ"</string>
<string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Լապտեր"</string>
<string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"Բջջային ինտերնետ"</string>
@@ -339,10 +339,8 @@
<string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"Օգտագործված է՝ <xliff:g id="DATA_USED">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Սահմանաչափ՝ <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> զգուշացում"</string>
- <!-- no translation found for quick_settings_work_mode_on_label (3421274215098764735) -->
- <skip />
- <!-- no translation found for quick_settings_work_mode_off_label (8856918707867192186) -->
- <skip />
+ <string name="quick_settings_work_mode_on_label" msgid="3421274215098764735">"Աշխատանքային պրոֆիլ"</string>
+ <string name="quick_settings_work_mode_off_label" msgid="8856918707867192186">"Ծանուցումներն ու հավելվածներն անջատված են"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Գիշերային լույս"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"Կմիացվի մայրամուտին"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"Մինչև լուսաբաց"</string>
@@ -360,8 +358,6 @@
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> հավելվածը անվտանգ ռեժիմում անջատված է:"</string>
<string name="recents_stack_action_button_label" msgid="6593727103310426253">"Մաքրել բոլորը"</string>
<string name="recents_drag_hint_message" msgid="2649739267073203985">"Քաշեք այստեղ՝ էկրանի տրոհումն օգտագործելու համար"</string>
- <!-- no translation found for recents_swipe_up_onboarding (3824607135920170001) -->
- <skip />
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Հորիզոնական տրոհում"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Ուղղահայաց տրոհում"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Հատուկ տրոհում"</string>
@@ -502,11 +498,18 @@
<string name="volume_zen_end_now" msgid="6930243045593601084">"Անջատել հիմա"</string>
<string name="accessibility_volume_expand" msgid="5946812790999244205">"Ընդարձակել"</string>
<string name="accessibility_volume_collapse" msgid="3609549593031810875">"Կոծկել"</string>
+ <string name="accessibility_output_chooser" msgid="8185317493017988680">"Փոխել արտածման սարքը"</string>
<string name="screen_pinning_title" msgid="3273740381976175811">"Էկրանն ամրացված է"</string>
<string name="screen_pinning_description" msgid="8909878447196419623">"Էկրանը կմնա տեսադաշտում, մինչև այն ապամրացնեք: Ապամրացնելու համար հպեք և պահեք Հետ և Համատեսք կոճակները:"</string>
+ <string name="screen_pinning_description_recents_invisible" msgid="8281145542163727971">"Էկրանը կցուցադրվի այնքան ժամանակ, մինչև որ չապամրացնեք այն: Ապամրացնելու համար հպեք և պահեք Հետ և գլխավոր էկրանի կոճակները:"</string>
<string name="screen_pinning_description_accessible" msgid="426190689254018656">"Էկրանը կմնա տեսադաշտում, մինչև այն ապամրացնեք: Ապամրացնելու համար հպեք և պահեք Համատեսք կոճակը:"</string>
+ <string name="screen_pinning_description_recents_invisible_accessible" msgid="6134833683151189507">"Էկրանը կցուցադրվի այնքան ժամանակ, մինչև որ չապամրացնեք այն: Ապամրացնելու համար հպեք և պահեք գլխավոր էկրանի կոճակը:"</string>
+ <string name="screen_pinning_toast" msgid="2266705122951934150">"Էկրանն ապամրացնելու համար հպեք և պահեք Հետ և Համատեսք կոճակները"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="8252402309499161281">"Էկրանն ապամրացնելու համար հպեք և պահեք Հետ և գլխավոր էկրանի կոճակները"</string>
<string name="screen_pinning_positive" msgid="3783985798366751226">"Եղավ"</string>
<string name="screen_pinning_negative" msgid="3741602308343880268">"Ոչ"</string>
+ <string name="screen_pinning_start" msgid="1022122128489278317">"Էկրանն ամրացված է"</string>
+ <string name="screen_pinning_exit" msgid="5187339744262325372">"Էկրանն ապամրացված է"</string>
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Թաքցնե՞լ <xliff:g id="TILE_LABEL">%1$s</xliff:g>-ը:"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Այն դարձյալ կհայտնվի, երբ նորից միացնեք կարգավորումներում:"</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Թաքցնել"</string>
@@ -586,8 +589,7 @@
<string name="power_notification_controls_description" msgid="4372459941671353358">"Ծանուցումների ընդլայնված կառավարման օգնությամբ կարող եք յուրաքանչյուր հավելվածի ծանուցումների համար նշանակել կարևորության աստիճան՝ 0-5 սահմաններում: \n\n"<b>"5-րդ աստիճան"</b>" \n- Ցուցադրել ծանուցումների ցանկի վերևում \n- Թույլատրել լիաէկրան ընդհատումները \n- Միշտ ցուցադրել կարճ ծանուցումները \n\n"<b>"4-րդ աստիճան"</b>" \n- Արգելել լիաէկրան ընդհատումները \n- Միշտ ցուցադրել կարճ ծանուցումները \n\n"<b>"3-րդ աստիճան"</b>" \n- Արգելել լիաէկրան ընդհատումները \n- Արգելել կարճ ծանուցումների ցուցադրումը \n\n"<b>"2-րդ աստիճան"</b>" \n- Արգելել լիաէկրան ընդհատումները \n- Արգելել կարճ ծանուցումների ցուցադրումը \n- Անջատել ձայնը և թրթռումը \n\n"<b>"1-ին աստիճան"</b>" \n- Արգելել լիաէկրան ընդհատումները \n- Արգելել կարճ ծանուցումների ցուցադրումը \n- Անջատել ձայնը և թրթռումը \n- Չցուցադրել կողպէկրանում և կարգավիճակի գոտում \n- Ցուցադրել ծանուցումների ցանկի ներքևում \n\n"<b>"0-րդ աստիճան"</b>\n"- Արգելափակել հավելվածի բոլոր ծանուցումները"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Ծանուցումներ"</string>
<string name="notification_channel_disabled" msgid="344536703863700565">"Դուք այլևս չեք ստանա այս ծանուցումները"</string>
- <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
- <skip />
+ <string name="inline_blocking_helper" msgid="3055064577771478591">"Դուք սովորաբար փակում եք այս ծանուցումները: \nՇարունակե՞լ ցուցադրել դրանք:"</string>
<string name="inline_keep_showing" msgid="8945102997083836858">"Ցուցադրե՞լ այս ծանուցումները։"</string>
<string name="inline_stop_button" msgid="4172980096860941033">"Չցուցադրել ծանուցումներ"</string>
<string name="inline_keep_button" msgid="6665940297019018232">"Ցուցադրել"</string>
@@ -766,7 +768,7 @@
<string name="pip_skip_to_prev" msgid="1955311326688637914">"Վերադառնալ նախորդին"</string>
<string name="thermal_shutdown_title" msgid="4458304833443861111">"Հեռախոսն անջատվել է տաքանալու պատճառով"</string>
<string name="thermal_shutdown_message" msgid="9006456746902370523">"Հեռախոսն այժմ նորմալ աշխատում է"</string>
- <string name="thermal_shutdown_dialog_message" msgid="566347880005304139">"Ձեր հեռախոսը չափազանց տաք էր, այդ պատճառով այն անջատվել է՝ սառելու համար: Հեռախոսն այժմ նորմալ աշխատում է:\n\nՀեռախոսը կարող է տաքանալ, եթե՝\n • Օգտագործում եք ռեսուրսատար հավելվածներ (օրինակ՝ խաղեր, տեսանյութեր կամ նավարկման հավելվածներ)\n • Ներբեռնում կամ վերբեռնում եք ծանր ֆայլեր\n • Օգտագործում եք ձեր հեռախոսը բարձր ջերմային պայմաններում"</string>
+ <string name="thermal_shutdown_dialog_message" msgid="566347880005304139">"Ձեր հեռախոսը չափազանց տաք էր, այդ պատճառով այն անջատվել է՝ հովանալու համար: Հեռախոսն այժմ նորմալ աշխատում է:\n\nՀեռախոսը կարող է տաքանալ, եթե՝\n • Օգտագործում եք ռեսուրսատար հավելվածներ (օրինակ՝ խաղեր, տեսանյութեր կամ նավարկման հավելվածներ)\n • Ներբեռնում կամ վերբեռնում եք ծանր ֆայլեր\n • Օգտագործում եք ձեր հեռախոսը բարձր ջերմային պայմաններում"</string>
<string name="high_temp_title" msgid="4589508026407318374">"Հեռախոսը տաքանում է"</string>
<string name="high_temp_notif_message" msgid="5642466103153429279">"Հովանալու ընթացքում հեռախոսի որոշ գործառույթներ սահմանափակ են"</string>
<string name="high_temp_dialog_message" msgid="6840700639374113553">"Ձեր հեռախոսն ավտոմատ կերպով կփորձի hովանալ: Կարող եք շարունակել օգտագործել հեռախոսը, սակայն հնարավոր է, որ այն ավելի դանդաղ աշխատի:\n\nՀովանալուց հետո հեռախոսը կաշխատի կանոնավոր կերպով:"</string>
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
index a5e37d5..13ca114 100644
--- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
@@ -40,7 +40,7 @@
<dimen name="battery_detail_graph_space_top">27dp</dimen>
<dimen name="battery_detail_graph_space_bottom">27dp</dimen>
- <dimen name="qs_tile_margin_top">16dp</dimen>
+ <dimen name="qs_tile_margin_top">32dp</dimen>
<dimen name="qs_brightness_padding_top">6dp</dimen>
<dimen name="qs_detail_margin_top">28dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 37d8118..0279d16 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -310,8 +310,7 @@
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi o‘chiq"</string>
<string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"Wi-Fi yoqilgan"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Hech qanday Wi-Fi tarmog‘i mavjud emas"</string>
- <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
- <skip />
+ <string name="quick_settings_alarm_title" msgid="2416759007342260676">"Signal"</string>
<string name="quick_settings_cast_title" msgid="7709016546426454729">"Translatsiya"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Translatsiya qilinmoqda"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Nomsiz qurilma"</string>
@@ -361,7 +360,6 @@
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"Xavfsiz rejimda <xliff:g id="APP">%s</xliff:g> ilovasi o‘chirib qo‘yildi."</string>
<string name="recents_stack_action_button_label" msgid="6593727103310426253">"Hammasini tozalash"</string>
<string name="recents_drag_hint_message" msgid="2649739267073203985">"Ekranni bo‘lish xususiyatidan foydalanish uchun bu yerga torting"</string>
- <string name="recents_swipe_up_onboarding" msgid="3824607135920170001">"Ilovalarni almashtirish uchun ekranni tepaga suring"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Gorizontal yo‘nalishda bo‘lish"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Vertikal yo‘nalishda bo‘lish"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Boshqa usulda bo‘lish"</string>
@@ -502,25 +500,18 @@
<string name="volume_zen_end_now" msgid="6930243045593601084">"O‘chiring"</string>
<string name="accessibility_volume_expand" msgid="5946812790999244205">"Yoyish"</string>
<string name="accessibility_volume_collapse" msgid="3609549593031810875">"Yig‘ish"</string>
- <!-- no translation found for accessibility_output_chooser (8185317493017988680) -->
- <skip />
+ <string name="accessibility_output_chooser" msgid="8185317493017988680">"Audiochiqish qurilmasini almashtirish"</string>
<string name="screen_pinning_title" msgid="3273740381976175811">"Ekran qadaldi"</string>
<string name="screen_pinning_description" msgid="8909878447196419623">"Ekran yechilmaguncha u o‘zgarmas holatda qoladi. Uni yechish uchun “Orqaga” va “Umumiy ma’lumot” tugmalarini bosib turing."</string>
- <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
- <skip />
+ <string name="screen_pinning_description_recents_invisible" msgid="8281145542163727971">"Ekran yechilmaguncha u o‘zgarmas holatda qoladi. Uni yechish uchun Orqaga va Boshi tugmalarini bosib turing."</string>
<string name="screen_pinning_description_accessible" msgid="426190689254018656">"Ekran yechilmaguncha u o‘zgarmas holatda qoladi. Uni yechish uchun “Umumiy ma’lumot” tugmasini bosib turing."</string>
- <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
- <skip />
+ <string name="screen_pinning_description_recents_invisible_accessible" msgid="6134833683151189507">"Ekran yechilmaguncha u o‘zgarmas holatda qoladi. Uni yechish uchun Orqaga va Boshi tugmlarini bosib turing."</string>
+ <string name="screen_pinning_toast" msgid="2266705122951934150">"Bu ekrandan chiqish uchun Orqaga va Menyu tugmalarini bosib turing"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="8252402309499161281">"Bu ekrandan chiqish uchun Orqaga va Boshi tugmalarini bosib turing"</string>
<string name="screen_pinning_positive" msgid="3783985798366751226">"OK"</string>
<string name="screen_pinning_negative" msgid="3741602308343880268">"Yo‘q, kerakmas"</string>
- <!-- no translation found for screen_pinning_start (1022122128489278317) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
- <skip />
+ <string name="screen_pinning_start" msgid="1022122128489278317">"Ekran mahkamlandi"</string>
+ <string name="screen_pinning_exit" msgid="5187339744262325372">"Ekran olib tashlandi"</string>
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> berkitilsinmi?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Keyingi safar sozlamalardan yoqilgan paydo bo‘ladi."</string>
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Berkitish"</string>
diff --git a/packages/SystemUI/res/values/attrs_car.xml b/packages/SystemUI/res/values/attrs_car.xml
new file mode 100644
index 0000000..b1097c3
--- /dev/null
+++ b/packages/SystemUI/res/values/attrs_car.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources>
+ <!-- Allow for custom attribs to be added to a facet button -->
+ <declare-styleable name="CarFacetButton">
+ <!-- icon to be rendered (drawable) -->
+ <attr name="icon" format="reference"/>
+ <!-- intent to start when button is click -->
+ <attr name="intent" format="string"/>
+ <!-- intent to start when a long press has happened -->
+ <attr name="longIntent" format="string"/>
+ <!-- categories that will be added as extras to the fired intents -->
+ <attr name="categories" format="string"/>
+ <!-- package names that will be added as extras to the fired intents -->
+ <attr name="packages" format="string" />
+ </declare-styleable>
+
+
+ <!-- Allow for custom attribs to be added to a nav button -->
+ <declare-styleable name="CarNavigationButton">
+ <!-- intent to start when button is click -->
+ <attr name="intent" format="string"/>
+ <!-- intent to start when a long press has happened -->
+ <attr name="longIntent" format="string"/>
+ <!-- start the intent as a broad cast instead of an activity if true-->
+ <attr name="broadcast" format="boolean"/>
+ </declare-styleable>
+</resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 4fcfdf7..be8e990 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -166,4 +166,6 @@
<color name="fingerprint_dialog_dim_color">#80000000</color> <!-- 50% black -->
<color name="fingerprint_error_message_color">#ff5722</color>
+ <!-- Logout button -->
+ <color name="logout_button_bg_color">#ccffffff</color>
</resources>
diff --git a/packages/SystemUI/res/values/config_car.xml b/packages/SystemUI/res/values/config_car.xml
index 9c8dcb1..db829f2 100644
--- a/packages/SystemUI/res/values/config_car.xml
+++ b/packages/SystemUI/res/values/config_car.xml
@@ -22,4 +22,9 @@
uri that will be launched into the docked window. -->
<bool name="config_enablePersistentDockedActivity">false</bool>
<string name="config_persistentDockedActivityIntentUri" translatable="false"></string>
+
+ <!-- configure which system ui bars should be displayed -->
+ <bool name="config_enableLeftNavigationBar">false</bool>
+ <bool name="config_enableRightNavigationBar">false</bool>
+ <bool name="config_enableBottomNavigationBar">true</bool>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index c351b94..bc828ff 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -230,7 +230,7 @@
<!-- The height of the quick settings footer that holds the user switcher, settings icon,
etc. -->
- <dimen name="qs_footer_height">48dp</dimen>
+ <dimen name="qs_footer_height">56dp</dimen>
<!-- The padding between the notifications and the quick settings container -->
<dimen name="qs_notification_padding">@dimen/notification_side_paddings</dimen>
@@ -290,7 +290,7 @@
<dimen name="qs_tile_height">106dp</dimen>
<dimen name="qs_tile_margin">19dp</dimen>
- <dimen name="qs_tile_margin_top">16dp</dimen>
+ <dimen name="qs_tile_margin_top">32dp</dimen>
<dimen name="qs_quick_tile_size">48dp</dimen>
<dimen name="qs_quick_tile_padding">12dp</dimen>
<dimen name="qs_header_gear_translation">16dp</dimen>
@@ -309,6 +309,7 @@
<dimen name="qs_tile_padding_bottom">16dp</dimen>
<dimen name="qs_tile_spacing">4dp</dimen>
<dimen name="qs_panel_padding_bottom">0dp</dimen>
+ <dimen name="qs_panel_padding_top">32dp</dimen>
<dimen name="qs_detail_header_height">56dp</dimen>
<dimen name="qs_detail_header_padding">0dp</dimen>
<dimen name="qs_detail_image_width">56dp</dimen>
@@ -333,11 +334,14 @@
<dimen name="qs_detail_item_icon_width">32dp</dimen>
<dimen name="qs_detail_item_icon_marginStart">0dp</dimen>
<dimen name="qs_detail_item_icon_marginEnd">20dp</dimen>
+ <dimen name="qs_header_padding_start">16dp</dimen>
+ <dimen name="qs_header_padding_end">24dp</dimen>
+ <dimen name="qs_header_tooltip_height">32dp</dimen>
<dimen name="qs_footer_padding_start">16dp</dimen>
<dimen name="qs_footer_padding_end">24dp</dimen>
<dimen name="qs_footer_icon_size">16dp</dimen>
<!-- Difference between drag handle margin in QQS and expanded QS -->
- <dimen name="qs_footer_drag_handle_offset">6dp</dimen>
+ <dimen name="qs_footer_drag_handle_offset">10dp</dimen>
<dimen name="qs_notif_collapsed_space">64dp</dimen>
@@ -513,7 +517,7 @@
<dimen name="multi_user_avatar_keyguard_size">22dp</dimen>
<!-- The width of user avatar when expanded -->
- <dimen name="multi_user_avatar_expanded_size">16dp</dimen>
+ <dimen name="multi_user_avatar_expanded_size">18dp</dimen>
<!-- The font size of the time when collapsed in QS -->
<dimen name="qs_time_collapsed_size">14sp</dimen>
@@ -855,8 +859,6 @@
<dimen name="default_gear_space">18dp</dimen>
<dimen name="cell_overlay_padding">18dp</dimen>
- <dimen name="signal_icon_size">17dp</dimen>
-
<dimen name="hwui_edge_margin">16dp</dimen>
<dimen name="global_actions_panel_width">120dp</dimen>
@@ -885,13 +887,8 @@
<dimen name="nav_quick_scrub_track_edge_padding">42dp</dimen>
<dimen name="nav_quick_scrub_track_thickness">2dp</dimen>
- <!-- Intended corner radius when drawing the mobile signal -->
- <dimen name="stat_sys_mobile_signal_corner_radius">0.75dp</dimen>
- <!-- How far to inset the rounded edges -->
- <dimen name="stat_sys_mobile_signal_circle_inset">0.9dp</dimen>
-
<!-- Home button padding for sizing -->
- <dimen name="home_padding">15dp</dimen>
+ <dimen name="home_padding">16dp</dimen>
<!-- Smart reply button -->
<dimen name="smart_reply_button_corner_radius">24dip</dimen>
@@ -932,4 +929,10 @@
<integer name="wired_charging_aod_text_animation_duration_up">300</integer>
<!-- Wired charging on AOD, text animation distance -->
<integer name="wired_charging_aod_text_animation_distance">-30</integer>
+
+ <!-- Logout button -->
+ <dimen name="logout_button_layout_height">32dp</dimen>
+ <dimen name="logout_button_padding_horizontal">16dp</dimen>
+ <dimen name="logout_button_margin_bottom">12dp</dimen>
+ <dimen name="logout_button_corner_radius">2dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index fc5ea45..86cab22 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -666,6 +666,8 @@
<!-- Textual description of Ethernet connections -->
<string name="ethernet_label">Ethernet</string>
+ <!-- QuickSettings: Onboarding text that introduces users to long press on an option in order to view the option's menu in Settings [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_header_onboarding_text">Press & hold on the icons for more options</string>
<!-- QuickSettings: Do not disturb [CHAR LIMIT=NONE] -->
<string name="quick_settings_dnd_label">Do not disturb</string>
<!-- QuickSettings: Do not disturb - Priority only [CHAR LIMIT=NONE] -->
@@ -1340,8 +1342,7 @@
<string name="volume_stream_content_description_vibrate_a11y">%1$s. Tap to set to vibrate.</string>
<string name="volume_stream_content_description_mute_a11y">%1$s. Tap to mute.</string>
- <string name="volume_dialog_accessibility_shown_message">%s volume controls shown. Swipe up to dismiss.</string>
- <string name="volume_dialog_accessibility_dismissed_message">Volume controls hidden</string>
+ <string name="volume_dialog_title">%s volume controls</string>
<string name="output_title">Media output</string>
<string name="output_calls_title">Phone call output</string>
@@ -1752,15 +1753,13 @@
<string-array name="nav_bar_buttons">
<item>Clipboard</item>
<item>Keycode</item>
- <item>Keyboard switcher</item>
- <item>Rotation suggestion</item>
+ <item>Rotate confirm, keyboard switcher</item>
<item>None</item>
</string-array>
<string-array name="nav_bar_button_values" translatable="false">
<item>clipboard</item>
<item>key</item>
<item>menu_ime</item>
- <item>rotate</item>
<item>space</item>
</string-array>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
index 7f382ac..e200a7f 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
@@ -23,6 +23,14 @@
void onBind(in ISystemUiProxy sysUiProxy);
/**
+ * Called once immediately prior to the first onMotionEvent() call, providing a hint to the
+ * target the initial source of the subsequent motion events.
+ *
+ * @param downHitTarget is one of the {@link NavigationBarCompat.HitTarget}s
+ */
+ void onPreMotionEvent(int downHitTarget);
+
+ /**
* Proxies motion events from the nav bar in SystemUI to the OverviewProxyService. The sender
* guarantees the following order of events:
*
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
index 4cf817e..b8319a8e 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
@@ -44,4 +44,9 @@
* Specifies the text to be shown for onboarding the new swipe-up gesture to access recents.
*/
void setRecentsOnboardingText(CharSequence text);
+
+ /**
+ * Enables/disables launcher/overview interaction features {@link InteractionType}.
+ */
+ void setInteractionState(int flags);
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index 62bd72f..138910c 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -316,6 +316,17 @@
}
/**
+ * Cancels the remote recents animation started from {@link #startRecentsActivity}.
+ */
+ public void cancelRecentsAnimation() {
+ try {
+ ActivityManager.getService().cancelRecentsAnimation();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to cancel recents animation", e);
+ }
+ }
+
+ /**
* Starts a task from Recents.
*
* @see {@link #startActivityFromRecentsAsync(TaskKey, ActivityOptions, int, int, Consumer, Handler)}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java
new file mode 100644
index 0000000..17191868
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java
@@ -0,0 +1,60 @@
+/*
+ * 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.systemui.shared.system;
+
+import android.annotation.IntDef;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+public class NavigationBarCompat {
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({HIT_TARGET_NONE, HIT_TARGET_BACK, HIT_TARGET_HOME})
+ public @interface HitTarget{}
+
+ public static final int HIT_TARGET_NONE = 0;
+ public static final int HIT_TARGET_BACK = 1;
+ public static final int HIT_TARGET_HOME = 2;
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({FLAG_DISABLE_SWIPE_UP,
+ FLAG_DISABLE_QUICK_SCRUB,
+ FLAG_SHOW_OVERVIEW_BUTTON,
+ FLAG_HIDE_BACK_BUTTON
+ })
+ public @interface InteractionType {}
+
+ /**
+ * Interaction type: whether the gesture to swipe up from the navigation bar will trigger
+ * launcher to show overview
+ */
+
+ public static final int FLAG_DISABLE_SWIPE_UP = 0x1;
+ /**
+ * Interaction type: enable quick scrub and switch interaction on the home button
+ */
+ public static final int FLAG_DISABLE_QUICK_SCRUB = 0x2;
+
+ /**
+ * Interaction type: show/hide the overview button while this service is connected to launcher
+ */
+ public static final int FLAG_SHOW_OVERVIEW_BUTTON = 0x4;
+
+ /**
+ * Interaction type: show/hide the back button while this service is connected to launcher
+ */
+ public static final int FLAG_HIDE_BACK_BUTTON = 0x8;
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/PackageManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/PackageManagerWrapper.java
index d5e6e6e..6fa7db3 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/PackageManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/PackageManagerWrapper.java
@@ -21,8 +21,12 @@
import android.content.pm.ActivityInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.os.RemoteException;
+import java.util.ArrayList;
+import java.util.List;
+
public class PackageManagerWrapper {
private static final String TAG = "PackageManagerWrapper";
@@ -47,4 +51,42 @@
return null;
}
}
+
+ /**
+ * @return true if the packageName belongs to the current preferred home app on the device.
+ *
+ * If will also return false if there are multiple home apps and the user has not picked any
+ * preferred home, in which case the user would see a disambiguation screen on going to home.
+ */
+ public boolean isDefaultHomeActivity(String packageName) {
+ List<ResolveInfo> allHomeCandidates = new ArrayList<>();
+ ComponentName home;
+ try {
+ home = mIPackageManager.getHomeActivities(allHomeCandidates);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ return false;
+ }
+
+ if (home != null && packageName.equals(home.getPackageName())) {
+ return true;
+ }
+
+ // Find the launcher with the highest priority and return that component if there are no
+ // other home activity with the same priority.
+ int lastPriority = Integer.MIN_VALUE;
+ ComponentName lastComponent = null;
+ final int size = allHomeCandidates.size();
+ for (int i = 0; i < size; i++) {
+ final ResolveInfo ri = allHomeCandidates.get(i);
+ if (ri.priority > lastPriority) {
+ lastComponent = ri.activityInfo.getComponentName();
+ lastPriority = ri.priority;
+ } else if (ri.priority == lastPriority) {
+ // Two components found with same priority.
+ lastComponent = null;
+ }
+ }
+ return lastComponent != null && packageName.equals(lastComponent.getPackageName());
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index e440731..3b5f34c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -16,13 +16,16 @@
package com.android.keyguard;
+import android.app.ActivityManager;
import android.app.AlarmManager;
+import android.app.IActivityManager;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
import android.os.Handler;
import android.os.Looper;
+import android.os.RemoteException;
import android.os.UserHandle;
import android.support.v4.graphics.ColorUtils;
import android.text.TextUtils;
@@ -51,9 +54,11 @@
private final LockPatternUtils mLockPatternUtils;
private final AlarmManager mAlarmManager;
+ private final IActivityManager mIActivityManager;
private final float mSmallClockScale;
private final float mWidgetPadding;
+ private TextView mLogoutView;
private TextClock mClockView;
private View mClockSeparator;
private TextView mOwnerInfo;
@@ -80,6 +85,7 @@
if (DEBUG) Slog.v(TAG, "refresh statusview showing:" + showing);
refresh();
updateOwnerInfo();
+ updateLogoutView();
}
}
@@ -97,6 +103,12 @@
public void onUserSwitchComplete(int userId) {
refresh();
updateOwnerInfo();
+ updateLogoutView();
+ }
+
+ @Override
+ public void onLogoutEnabledChanged() {
+ updateLogoutView();
}
};
@@ -111,6 +123,7 @@
public KeyguardStatusView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+ mIActivityManager = ActivityManager.getService();
mLockPatternUtils = new LockPatternUtils(getContext());
mHandler = new Handler(Looper.myLooper());
mSmallClockScale = getResources().getDimension(R.dimen.widget_small_font_size)
@@ -145,6 +158,9 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
+ mLogoutView = findViewById(R.id.logout);
+ mLogoutView.setOnClickListener(this::onLogoutClicked);
+
mClockContainer = findViewById(R.id.keyguard_clock_container);
mClockView = findViewById(R.id.clock_view);
mClockView.setShowCurrentUserTime(true);
@@ -164,6 +180,7 @@
setEnableMarquee(shouldMarquee);
refresh();
updateOwnerInfo();
+ updateLogoutView();
// Disable elegant text height because our fancy colon makes the ymin value huge for no
// reason.
@@ -213,14 +230,28 @@
}
public int getClockBottom() {
- return mKeyguardSlice.getVisibility() == VISIBLE ? mKeyguardSlice.getBottom()
- : mClockView.getBottom();
+ if (mOwnerInfo != null && mOwnerInfo.getVisibility() == VISIBLE) {
+ return mOwnerInfo.getBottom();
+ } else {
+ return mClockContainer.getBottom();
+ }
+ }
+
+ public int getLogoutButtonHeight() {
+ return mLogoutView.getVisibility() == VISIBLE ? mLogoutView.getHeight() : 0;
}
public float getClockTextSize() {
return mClockView.getTextSize();
}
+ private void updateLogoutView() {
+ mLogoutView.setVisibility(shouldShowLogout() ? VISIBLE : GONE);
+ // Logout button will stay in language of user 0 if we don't set that manually.
+ mLogoutView.setText(mContext.getResources().getString(
+ com.android.internal.R.string.global_action_logout));
+ }
+
private void updateOwnerInfo() {
if (mOwnerInfo == null) return;
String ownerInfo = getOwnerInfo();
@@ -309,6 +340,7 @@
mDarkAmount = darkAmount;
boolean dark = darkAmount == 1;
+ mLogoutView.setAlpha(dark ? 0 : 1);
final int N = mClockContainer.getChildCount();
for (int i = 0; i < N; i++) {
View child = mClockContainer.getChildAt(i);
@@ -340,4 +372,19 @@
child.setAlpha(mDarkAmount == 1 && mPulsing ? 0.8f : 1);
}
}
+
+ private boolean shouldShowLogout() {
+ return KeyguardUpdateMonitor.getInstance(mContext).isLogoutEnabled()
+ && KeyguardUpdateMonitor.getCurrentUser() != UserHandle.USER_SYSTEM;
+ }
+
+ private void onLogoutClicked(View view) {
+ int currentUserId = KeyguardUpdateMonitor.getCurrentUser();
+ try {
+ mIActivityManager.switchUser(UserHandle.USER_SYSTEM);
+ mIActivityManager.stopUser(currentUserId, true /*force*/, null);
+ } catch (RemoteException re) {
+ Log.e(TAG, "Failed to logout user", re);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 9e4b405..f3f8d91f 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -141,6 +141,7 @@
private static final int MSG_USER_UNLOCKED = 334;
private static final int MSG_ASSISTANT_STACK_CHANGED = 335;
private static final int MSG_FINGERPRINT_AUTHENTICATION_CONTINUE = 336;
+ private static final int MSG_DEVICE_POLICY_MANAGER_STATE_CHANGED = 337;
/** Fingerprint state: Not listening to fingerprint. */
private static final int FINGERPRINT_STATE_STOPPED = 0;
@@ -225,6 +226,8 @@
private LockPatternUtils mLockPatternUtils;
private final IDreamManager mDreamManager;
private boolean mIsDreaming;
+ private final DevicePolicyManager mDevicePolicyManager;
+ private boolean mLogoutEnabled;
/**
* Short delay before restarting fingerprint authentication after a successful try
@@ -330,6 +333,9 @@
case MSG_FINGERPRINT_AUTHENTICATION_CONTINUE:
updateFingerprintListeningState();
break;
+ case MSG_DEVICE_POLICY_MANAGER_STATE_CHANGED:
+ updateLogoutEnabled();
+ break;
}
}
};
@@ -795,6 +801,9 @@
}
mHandler.sendMessage(
mHandler.obtainMessage(MSG_SERVICE_STATE_CHANGE, subId, 0, serviceState));
+ } else if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(
+ action)) {
+ mHandler.sendEmptyMessage(MSG_DEVICE_POLICY_MANAGER_STATE_CHANGED);
}
}
};
@@ -1159,6 +1168,7 @@
filter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
+ filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
context.registerReceiver(mBroadcastReceiver, filter);
final IntentFilter bootCompleteFilter = new IntentFilter();
@@ -1213,6 +1223,8 @@
ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
mUserManager = context.getSystemService(UserManager.class);
+ mDevicePolicyManager = context.getSystemService(DevicePolicyManager.class);
+ mLogoutEnabled = mDevicePolicyManager.isLogoutEnabled();
}
private void updateFingerprintListeningState() {
@@ -1936,6 +1948,26 @@
return null; // not found
}
+ /**
+ * @return a cached version of DevicePolicyManager.isLogoutEnabled()
+ */
+ public boolean isLogoutEnabled() {
+ return mLogoutEnabled;
+ }
+
+ private void updateLogoutEnabled() {
+ boolean logoutEnabled = mDevicePolicyManager.isLogoutEnabled();
+ if (mLogoutEnabled != logoutEnabled) {
+ mLogoutEnabled = logoutEnabled;
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+ if (cb != null) {
+ cb.onLogoutEnabledChanged();
+ }
+ }
+ }
+ }
+
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("KeyguardUpdateMonitor state:");
pw.println(" SIM States:");
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 1afcca6..67571bb 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -283,4 +283,11 @@
* @see KeyguardIndicationController#showTransientIndication(CharSequence)
*/
public void onTrustAgentErrorMessage(CharSequence message) { }
+
+
+ /**
+ * Called when a value of logout enabled is change.
+ */
+ public void onLogoutEnabledChanged() { }
+
}
diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
index d0128ef..1185f45 100644
--- a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
@@ -47,6 +47,8 @@
import java.util.ArrayList;
import java.util.List;
+import static com.android.systemui.shared.system.NavigationBarCompat.InteractionType;
+
/**
* Class to send information from overview to launcher with a binder.
*/
@@ -67,6 +69,7 @@
private IOverviewProxy mOverviewProxy;
private int mConnectionBackoffAttempts;
private CharSequence mOnboardingText;
+ private @InteractionType int mInteractionFlags;
private ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() {
@@ -108,6 +111,22 @@
public void setRecentsOnboardingText(CharSequence text) {
mOnboardingText = text;
}
+
+ public void setInteractionState(@InteractionType int flags) {
+ long token = Binder.clearCallingIdentity();
+ try {
+ if (mInteractionFlags != flags) {
+ mInteractionFlags = flags;
+ mHandler.post(() -> {
+ for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
+ mConnectionCallbacks.get(i).onInteractionFlagsChanged(flags);
+ }
+ });
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
};
private final BroadcastReceiver mLauncherAddedReceiver = new BroadcastReceiver() {
@@ -230,6 +249,10 @@
return mOnboardingText;
}
+ public int getInteractionFlags() {
+ return mInteractionFlags;
+ }
+
private void disconnectFromLauncherService() {
if (mOverviewProxy != null) {
mOverviewProxy.asBinder().unlinkToDeath(mOverviewServiceDeathRcpt, 0);
@@ -263,5 +286,6 @@
public interface OverviewProxyListener {
default void onConnectionChanged(boolean isConnected) {}
default void onRecentsAnimationStarted() {}
+ default void onInteractionFlagsChanged(@InteractionType int flags) {}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index adb4e33..8b57740 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -47,6 +47,7 @@
Key.QS_INVERT_COLORS_ADDED,
Key.QS_WORK_ADDED,
Key.QS_NIGHTDISPLAY_ADDED,
+ Key.QS_LONG_PRESS_TOOLTIP_SHOWN_COUNT,
Key.SEEN_MULTI_USER,
Key.NUM_APPS_LAUNCHED,
Key.HAS_SEEN_RECENTS_ONBOARDING,
@@ -76,6 +77,11 @@
String QS_WORK_ADDED = "QsWorkAdded";
@Deprecated
String QS_NIGHTDISPLAY_ADDED = "QsNightDisplayAdded";
+ /**
+ * Used for tracking how many times the user has seen the long press tooltip in the Quick
+ * Settings panel.
+ */
+ String QS_LONG_PRESS_TOOLTIP_SHOWN_COUNT = "QsLongPressTooltipShownCount";
String SEEN_MULTI_USER = "HasSeenMultiUser";
String NUM_APPS_LAUNCHED = "NumAppsLaunched";
String HAS_SEEN_RECENTS_ONBOARDING = "HasSeenRecentsOnboarding";
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index c28b7ee..259bff2 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -688,7 +688,7 @@
}
private Action getLockdownAction() {
- return new SinglePressAction(R.drawable.ic_lock_lock,
+ return new SinglePressAction(com.android.systemui.R.drawable.ic_lock_lockdown,
R.string.global_action_lockdown) {
@Override
@@ -1369,6 +1369,7 @@
mListView = findViewById(android.R.id.list);
mHardwareLayout = HardwareUiLayout.get(mListView);
mHardwareLayout.setOutsideTouchListener(view -> dismiss());
+ setTitle(R.string.global_actions);
}
private void updateList() {
@@ -1464,20 +1465,6 @@
}
@Override
- public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
- if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
- for (int i = 0; i < mAdapter.getCount(); ++i) {
- CharSequence label =
- mAdapter.getItem(i).getLabelForAccessibility(getContext());
- if (label != null) {
- event.getText().add(label);
- }
- }
- }
- return super.dispatchPopulateAccessibilityEvent(event);
- }
-
- @Override
public void onColorsChanged(ColorExtractor extractor, int which) {
if (mKeyguardShowing) {
if ((WallpaperManager.FLAG_LOCK & which) != 0) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/CellTileView.java b/packages/SystemUI/src/com/android/systemui/qs/CellTileView.java
index 5f26093..e7eefe8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/CellTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/CellTileView.java
@@ -19,12 +19,12 @@
import android.service.quicksettings.Tile;
import android.widget.ImageView;
+import com.android.settingslib.graph.SignalDrawable;
import com.android.settingslib.Utils;
import com.android.systemui.R;
import com.android.systemui.plugins.qs.QSTile.Icon;
import com.android.systemui.plugins.qs.QSTile.State;
import com.android.systemui.qs.tileimpl.QSTileImpl;
-import com.android.systemui.statusbar.phone.SignalDrawable;
import java.util.Objects;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index 222c6e82..fccd9ce 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -44,6 +44,7 @@
public static final float EXPANDED_TILE_DELAY = .86f;
+
private final ArrayList<View> mAllViews = new ArrayList<>();
/**
* List of {@link View}s representing Quick Settings that are being animated from the quick QS
@@ -65,6 +66,11 @@
private TouchAnimator mNonfirstPageDelayedAnimator;
private TouchAnimator mBrightnessAnimator;
+ /**
+ * Whether the animation is stable and not in the middle of animating between the collapsed and
+ * expanded states.
+ */
+ private boolean mIsInStableState;
private boolean mOnKeyguard;
private boolean mAllowFancy;
@@ -89,6 +95,10 @@
Log.w(TAG, "QS Not using page layout");
}
panel.setPageListener(this);
+
+ // At time of creation, the QS panel is always considered stable as it's not in the middle
+ // of collapse/expanded.
+ mIsInStableState = true;
}
public void onRtlChanged() {
@@ -243,6 +253,11 @@
} else {
mBrightnessAnimator = null;
}
+ View headerView = mQsPanel.getHeaderView();
+ if (headerView!= null) {
+ firstPageBuilder.addFloat(headerView, "translationY", heightDiff, 0);
+ mAllViews.add(headerView);
+ }
mFirstPageAnimator = firstPageBuilder
.setListener(this)
.build();
@@ -326,11 +341,21 @@
@Override
public void onAnimationAtStart() {
+ if (!mIsInStableState) {
+ mQsPanel.onCollapse();
+ }
+ mIsInStableState = true;
+
mQuickQsPanel.setVisibility(View.VISIBLE);
}
@Override
public void onAnimationAtEnd() {
+ if (!mIsInStableState) {
+ mQsPanel.onExpanded();
+ }
+ mIsInStableState = true;
+
mQuickQsPanel.setVisibility(View.INVISIBLE);
final int N = mQuickQsViews.size();
for (int i = 0; i < N; i++) {
@@ -340,6 +365,11 @@
@Override
public void onAnimationStarted() {
+ if (mIsInStableState) {
+ mQsPanel.onAnimating();
+ }
+ mIsInStableState = false;
+
mQuickQsPanel.setVisibility(mOnKeyguard ? View.INVISIBLE : View.VISIBLE);
if (mOnFirstPage) {
final int N = mQuickQsViews.size();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index fe3ffb9..b9919a3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -174,7 +174,8 @@
.addFloat(mDivider, "alpha", 0, 1)
.addFloat(mCarrierText, "alpha", 0, 1)
.addFloat(mActionsContainer, "alpha", 0, 1)
- .addFloat(mDragHandle, "translationY", 0, -mDragHandleExpandOffset)
+ .addFloat(mDragHandle, "translationY", mDragHandleExpandOffset, 0)
+ .addFloat(mDragHandle, "alpha", 1, 0)
.build();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index f7c388d..5640be5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -18,6 +18,7 @@
import static com.android.systemui.qs.tileimpl.QSTileImpl.getColorForState;
+import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
import android.content.res.Configuration;
@@ -58,6 +59,7 @@
public class QSPanel extends LinearLayout implements Tunable, Callback, BrightnessMirrorListener {
public static final String QS_SHOW_BRIGHTNESS = "qs_show_brightness";
+ public static final String QS_SHOW_LONG_PRESS_TOOLTIP = "qs_show_long_press";
protected final Context mContext;
protected final ArrayList<TileRecord> mRecords = new ArrayList<TileRecord>();
@@ -72,6 +74,7 @@
private BrightnessController mBrightnessController;
protected QSTileHost mHost;
+ protected QSTooltipView mTooltipView;
protected QSSecurityFooter mFooter;
private boolean mGridContentVisible = true;
@@ -94,6 +97,9 @@
setOrientation(VERTICAL);
+ mTooltipView = (QSTooltipView) LayoutInflater.from(mContext)
+ .inflate(R.layout.quick_settings_header, this, false);
+
mBrightnessView = LayoutInflater.from(mContext).inflate(
R.layout.quick_settings_brightness_dialog, this, false);
mTileLayout = new TileLayout(mContext);
@@ -101,7 +107,12 @@
Space space = new Space(mContext);
space.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
mContext.getResources().getDimensionPixelSize(R.dimen.qs_footer_height)));
- mScrollLayout = new QSScrollLayout(mContext, mBrightnessView, (View) mTileLayout, space);
+ mScrollLayout = new QSScrollLayout(
+ mContext,
+ mTooltipView,
+ mBrightnessView,
+ (View) mTileLayout,
+ space);
addView(mScrollLayout);
addDivider();
@@ -134,7 +145,10 @@
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
- Dependency.get(TunerService.class).addTunable(this, QS_SHOW_BRIGHTNESS);
+ final TunerService tunerService = Dependency.get(TunerService.class);
+ tunerService.addTunable(this, QS_SHOW_BRIGHTNESS);
+ tunerService.addTunable(this, QS_SHOW_LONG_PRESS_TOOLTIP);
+
if (mHost != null) {
setTiles(mHost.getTiles());
}
@@ -166,11 +180,16 @@
@Override
public void onTuningChanged(String key, String newValue) {
if (QS_SHOW_BRIGHTNESS.equals(key)) {
- mBrightnessView.setVisibility(newValue == null || Integer.parseInt(newValue) != 0
- ? VISIBLE : GONE);
+ updateViewVisibilityForTuningValue(mBrightnessView, newValue);
+ } else if (QS_SHOW_LONG_PRESS_TOOLTIP.equals(key)) {
+ updateViewVisibilityForTuningValue(mTooltipView, newValue);
}
}
+ private void updateViewVisibilityForTuningValue(View view, @Nullable String newValue) {
+ view.setVisibility(newValue == null || Integer.parseInt(newValue) != 0 ? VISIBLE : GONE);
+ }
+
public void openDetails(String subPanel) {
QSTile tile = getTile(subPanel);
showDetailAdapter(true, tile.getDetailAdapter(), new int[]{getWidth() / 2, 0});
@@ -205,6 +224,10 @@
return mBrightnessView;
}
+ View getHeaderView() {
+ return mTooltipView;
+ }
+
public void setCallback(QSDetail.Callback callback) {
mCallback = callback;
}
@@ -266,11 +289,27 @@
if (mCustomizePanel != null && mCustomizePanel.isShown()) {
mCustomizePanel.hide(mCustomizePanel.getWidth() / 2, mCustomizePanel.getHeight() / 2);
}
+
+ // Instantly hide the header here since we don't want it to still be animating.
+ mTooltipView.setVisibility(View.INVISIBLE);
+ }
+
+ /**
+ * Called when the panel is fully animated out/expanded. This is different from the state
+ * tracked by {@link #mExpanded}, which only checks if the panel is even partially pulled out.
+ */
+ public void onExpanded() {
+ mTooltipView.fadeIn();
+ }
+
+ public void onAnimating() {
+ mTooltipView.fadeOut();
}
public void setExpanded(boolean expanded) {
if (mExpanded == expanded) return;
mExpanded = expanded;
+
if (!mExpanded) {
if (mTileLayout instanceof PagedTileLayout) {
((PagedTileLayout) mTileLayout).setCurrentItem(0, false);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTooltipView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTooltipView.java
new file mode 100644
index 0000000..d1f9741
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTooltipView.java
@@ -0,0 +1,122 @@
+/*
+ * 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.systemui.qs;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.content.Context;
+import android.os.Handler;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.LinearLayout;
+
+import com.android.systemui.Prefs;
+
+import java.util.concurrent.TimeUnit;
+
+
+/**
+ * Tooltip/header view for the Quick Settings panel.
+ */
+public class QSTooltipView extends LinearLayout {
+
+ private static final int FADE_ANIMATION_DURATION_MS = 300;
+ private static final long AUTO_FADE_OUT_DELAY_MS = TimeUnit.SECONDS.toMillis(6);
+ private static final int TOOLTIP_NOT_YET_SHOWN_COUNT = 0;
+ public static final int MAX_TOOLTIP_SHOWN_COUNT = 3;
+
+ private final Handler mHandler = new Handler();
+ private final Runnable mAutoFadeOutRunnable = () -> fadeOut();
+
+ private int mShownCount;
+
+ public QSTooltipView(Context context) {
+ this(context, null);
+ }
+
+ public QSTooltipView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mShownCount = getStoredShownCount();
+ }
+
+ /** Returns the latest stored tooltip shown count from SharedPreferences. */
+ private int getStoredShownCount() {
+ return Prefs.getInt(
+ mContext,
+ Prefs.Key.QS_LONG_PRESS_TOOLTIP_SHOWN_COUNT,
+ TOOLTIP_NOT_YET_SHOWN_COUNT);
+ }
+
+ /**
+ * Fades in the header view if we can show the tooltip - short circuits any running animation.
+ */
+ public void fadeIn() {
+ if (mShownCount < MAX_TOOLTIP_SHOWN_COUNT) {
+ animate().cancel();
+ setVisibility(View.VISIBLE);
+ animate()
+ .alpha(1f)
+ .setDuration(FADE_ANIMATION_DURATION_MS)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mHandler.postDelayed(mAutoFadeOutRunnable, AUTO_FADE_OUT_DELAY_MS);
+ }
+ })
+ .start();
+
+ // Increment and drop the shown count in prefs for the next time we're deciding to
+ // fade in the tooltip. We first sanity check that the tooltip count hasn't changed yet
+ // in prefs (say, from a long press).
+ if (getStoredShownCount() <= mShownCount) {
+ Prefs.putInt(mContext, Prefs.Key.QS_LONG_PRESS_TOOLTIP_SHOWN_COUNT, ++mShownCount);
+ }
+ }
+ }
+
+ /**
+ * Fades out the header view if it's partially visible - short circuits any running animation.
+ */
+ public void fadeOut() {
+ animate().cancel();
+ if (getVisibility() == View.VISIBLE && getAlpha() != 0f) {
+ mHandler.removeCallbacks(mAutoFadeOutRunnable);
+ animate()
+ .alpha(0f)
+ .setDuration(FADE_ANIMATION_DURATION_MS)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ perhapsMakeViewInvisible();
+ }
+ })
+ .start();
+ } else {
+ perhapsMakeViewInvisible();
+ }
+ }
+
+ /**
+ * Only update visibility if the view is currently being shown. Otherwise, it's already been
+ * hidden by some other manner.
+ */
+ private void perhapsMakeViewInvisible() {
+ if (getVisibility() == View.VISIBLE) {
+ setVisibility(View.INVISIBLE);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index 8314855..1b4b7df 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -124,9 +124,8 @@
@Override
public void onTuningChanged(String key, String newValue) {
- // No tunings for you.
- if (key.equals(QS_SHOW_BRIGHTNESS)) {
- // No Brightness for you.
+ if (QS_SHOW_BRIGHTNESS.equals(key) || QS_SHOW_LONG_PRESS_TOOLTIP.equals(key)) {
+ // No Brightness or Tooltip for you!
super.onTuningChanged(key, "0");
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index 65135ab..9fa7beb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -99,7 +99,11 @@
record.tileView.measure(exactly(mCellWidth), exactly(mCellHeight));
previousView = record.tileView.updateAccessibilityOrder(previousView);
}
- int height = (mCellHeight + mCellMargin) * rows + (mCellMarginTop - mCellMargin);
+
+ // Only include the top margin in our measurement if we have more than 1 row to show.
+ // Otherwise, don't add the extra margin buffer at top.
+ int height = (mCellHeight + mCellMargin) * rows +
+ rows != 0 ? (mCellMarginTop - mCellMargin) : 0;
if (height < 0) height = 0;
setMeasuredDimension(width, height);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java
index 37f2528..6263efa 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java
@@ -107,7 +107,7 @@
void onAnimationAtStart();
/**
- * Called when the animator moves into a position of "0". Start and end delays are
+ * Called when the animator moves into a position of "1". Start and end delays are
* taken into account, so this position may cover a range of fractional inputs.
*/
void onAnimationAtEnd();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index 5a3081c..3847040 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -171,8 +171,6 @@
queryTiles();
mNotifQsContainer.setCustomizerAnimating(true);
mNotifQsContainer.setCustomizerShowing(true);
- announceForAccessibility(mContext.getString(
- R.string.accessibility_desc_quick_settings_edit));
Dependency.get(KeyguardMonitor.class).addCallback(mKeyguardCallback);
updateNavColors();
}
@@ -213,8 +211,6 @@
mClipper.animateCircularClip(mX, mY, false, mCollapseAnimationListener);
mNotifQsContainer.setCustomizerAnimating(true);
mNotifQsContainer.setCustomizerShowing(false);
- announceForAccessibility(mContext.getString(
- R.string.accessibility_desc_quick_settings));
Dependency.get(KeyguardMonitor.class).removeCallback(mKeyguardCallback);
updateNavColors();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index 72592829..016cbd6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -42,6 +42,7 @@
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
+import com.android.systemui.Prefs;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.plugins.qs.QSIconView;
@@ -49,6 +50,7 @@
import com.android.systemui.plugins.qs.QSTile.State;
import com.android.systemui.qs.PagedTileLayout.TilePage;
import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.QSTooltipView;
import java.util.ArrayList;
@@ -191,6 +193,11 @@
public void longClick() {
mMetricsLogger.write(populate(new LogMaker(ACTION_QS_LONG_PRESS).setType(TYPE_ACTION)));
mHandler.sendEmptyMessage(H.LONG_CLICK);
+
+ Prefs.putInt(
+ mContext,
+ Prefs.Key.QS_LONG_PRESS_TOOLTIP_SHOWN_COUNT,
+ QSTooltipView.MAX_TOOLTIP_SHOWN_COUNT);
}
public LogMaker populate(LogMaker logMaker) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 2607ebb..7fe9e35 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -131,21 +131,10 @@
if (enabled) {
if (connected) {
- state.icon = ResourceIcon.get(R.drawable.ic_qs_bluetooth_connected);
+ state.icon = new BluetoothConnectedTileIcon();
state.contentDescription = mContext.getString(
R.string.accessibility_bluetooth_name, state.label);
- final CachedBluetoothDevice lastDevice = mController.getLastDevice();
- if (lastDevice != null) {
- final int batteryLevel = lastDevice.getBatteryLevel();
- if (batteryLevel != BluetoothDevice.BATTERY_LEVEL_UNKNOWN) {
- state.icon = new BluetoothBatteryTileIcon(
- batteryLevel,
- mContext.getResources().getFraction(
- R.fraction.bt_battery_scale_fraction, 1, 1));
- }
- }
-
state.label = mController.getLastDeviceName();
} else if (state.isTransient) {
state.icon = ResourceIcon.get(R.drawable.ic_bluetooth_transient_animation);
@@ -281,6 +270,25 @@
}
}
+
+ /**
+ * Bluetooth icon wrapper (when connected with no battery indicator) for Quick Settings. This is
+ * used instead of {@link com.android.systemui.qs.tileimpl.QSTileImpl.DrawableIcon} in order to
+ * use a context that reflects dark/light theme attributes.
+ */
+ private class BluetoothConnectedTileIcon extends Icon {
+
+ BluetoothConnectedTileIcon() {
+ // Do nothing. Default constructor to limit visibility.
+ }
+
+ @Override
+ public Drawable getDrawable(Context context) {
+ // This method returns Pair<Drawable, String> - the first value is the drawable.
+ return context.getDrawable(R.drawable.ic_qs_bluetooth_connected);
+ }
+ }
+
protected class BluetoothDetailAdapter implements DetailAdapter, QSDetailItems.Callback {
// We probably won't ever have space in the UI for more than 20 devices, so don't
// get info for them.
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index bf4a225..2acb1bb 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -38,10 +38,12 @@
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
+import android.graphics.Canvas;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
+import android.graphics.Picture;
import android.graphics.PixelFormat;
import android.graphics.PointF;
import android.graphics.Rect;
@@ -57,13 +59,10 @@
import android.util.DisplayMetrics;
import android.util.Slog;
import android.view.Display;
-import android.view.DisplayListCanvas;
import android.view.LayoutInflater;
import android.view.MotionEvent;
-import android.view.RenderNode;
import android.view.Surface;
import android.view.SurfaceControl;
-import android.view.ThreadedRenderer;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
@@ -233,14 +232,12 @@
*/
private Bitmap generateAdjustedHwBitmap(Bitmap bitmap, int width, int height, Matrix matrix,
Paint paint, int color) {
- RenderNode node = RenderNode.create("ScreenshotCanvas", null);
- node.setLeftTopRightBottom(0, 0, width, height);
- node.setClipToBounds(false);
- DisplayListCanvas canvas = node.start(width, height);
+ Picture picture = new Picture();
+ Canvas canvas = picture.beginRecording(width, height);
canvas.drawColor(color);
canvas.drawBitmap(bitmap, matrix, paint);
- node.end(canvas);
- return ThreadedRenderer.createHardwareBitmap(node, width, height);
+ picture.endRecording();
+ return Bitmap.createBitmap(picture);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index eb5619b..0876507 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -308,6 +308,10 @@
}
}
+ public void setRippleAllowed(boolean allowed) {
+ mBackgroundNormal.setPressedAllowed(allowed);
+ }
+
private boolean handleTouchEventDimmed(MotionEvent event) {
if (mNeedsDimming && !mDimmed) {
// We're actually dimmed, but our content isn't dimmable, let's ensure we have a ripple
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index b3f68d3..2723df7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -370,14 +370,6 @@
mNotificationInflater.inflateNotificationViews();
}
- @Override
- public void setPressed(boolean pressed) {
- if (isOnKeyguard() || mEntry.notification.getNotification().contentIntent == null) {
- // We're dropping the ripple if we have a collapse / launch animation
- super.setPressed(pressed);
- }
- }
-
public void onNotificationUpdated() {
for (NotificationContentView l : mLayouts) {
l.onNotificationUpdated(mEntry);
@@ -407,6 +399,7 @@
showBlockingHelper(mEntry.userSentiment ==
NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE);
+ updateRippleAllowed();
}
@VisibleForTesting
@@ -1805,6 +1798,13 @@
mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
}
}
+ updateRippleAllowed();
+ }
+
+ private void updateRippleAllowed() {
+ boolean allowed = isOnKeyguard()
+ || mEntry.notification.getNotification().contentIntent == null;
+ setRippleAllowed(allowed);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
index ab89a52..0ff4dde 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
@@ -28,6 +28,7 @@
import android.util.AttributeSet;
import android.view.View;
+import com.android.internal.util.ArrayUtils;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
@@ -50,6 +51,7 @@
private boolean mExpandAnimationRunning;
private float mActualWidth;
private int mDrawableAlpha = 255;
+ private boolean mIsPressedAllowed;
public NotificationBackgroundView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -94,13 +96,7 @@
@Override
protected void drawableStateChanged() {
- drawableStateChanged(mBackground);
- }
-
- private void drawableStateChanged(Drawable d) {
- if (d != null && d.isStateful()) {
- d.setState(getDrawableState());
- }
+ setState(getDrawableState());
}
@Override
@@ -177,7 +173,13 @@
}
public void setState(int[] drawableState) {
- mBackground.setState(drawableState);
+ if (mBackground != null && mBackground.isStateful()) {
+ if (!mIsPressedAllowed) {
+ drawableState = ArrayUtils.removeInt(drawableState,
+ com.android.internal.R.attr.state_pressed);
+ }
+ mBackground.setState(drawableState);
+ }
}
public void setRippleColor(int color) {
@@ -258,4 +260,8 @@
}
invalidate();
}
+
+ public void setPressedAllowed(boolean allowed) {
+ mIsPressedAllowed = allowed;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
index 735f4fd..afe906c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
@@ -50,7 +50,6 @@
import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import java.lang.IllegalArgumentException;
import java.util.List;
import java.util.Set;
@@ -274,7 +273,7 @@
}
private void saveImportance() {
- if (mNonblockable || !hasImportanceChanged()) {
+ if (mNonblockable) {
return;
}
MetricsLogger.action(mContext, MetricsEvent.ACTION_SAVE_IMPORTANCE,
@@ -409,7 +408,7 @@
final int centerY = v.getHeight() / 2;
final int x = targetLoc[0] - parentLoc[0] + centerX;
final int y = targetLoc[1] - parentLoc[1] + centerY;
- mGutsContainer.closeControls(x, y, false /* save */, false /* force */);
+ mGutsContainer.closeControls(x, y, true /* save */, false /* force */);
}
@Override
@@ -429,7 +428,9 @@
@Override
public boolean handleCloseControls(boolean save, boolean force) {
- if (save && hasImportanceChanged()) {
+ // Save regardless of the importance so we can lock the importance field if the user wants
+ // to keep getting notifications
+ if (save) {
if (mCheckSaveListener != null) {
mCheckSaveListener.checkSave(this::saveImportance, mSbn);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index a7fb61a..cb6e5a6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -38,9 +38,9 @@
import android.widget.ImageView;
import android.widget.LinearLayout;
+import com.android.settingslib.graph.SignalDrawable;
import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.statusbar.phone.SignalDrawable;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.policy.DarkIconDispatcher;
import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java
new file mode 100644
index 0000000..53101a5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java
@@ -0,0 +1,161 @@
+package com.android.systemui.statusbar.car;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+
+import com.android.keyguard.AlphaOptimizedImageButton;
+import com.android.systemui.R;
+
+/**
+ * CarFacetButton is a ui component designed to be used as a shortcut for an app of a defined
+ * category. It can also render a indicator impling that there are more options of apps to launch
+ * using this component. This is done with a "More icon" currently an arrow as defined in the layout
+ * file. The class is to serve as an example.
+ * Usage example: A button that allows a user to select a music app and indicate that there are
+ * other music apps installed.
+ */
+public class CarFacetButton extends LinearLayout {
+ private static final float SELECTED_ALPHA = 1f;
+ private static final float UNSELECTED_ALPHA = 0.7f;
+
+ private static final String FACET_FILTER_DELIMITER = ";";
+ /**
+ * Extra information to be sent to a helper to make the decision of what app to launch when
+ * clicked.
+ */
+ private static final String EXTRA_FACET_CATEGORIES = "categories";
+ private static final String EXTRA_FACET_PACKAGES = "packages";
+ private static final String EXTRA_FACET_ID = "filter_id";
+ private static final String EXTRA_FACET_LAUNCH_PICKER = "launch_picker";
+
+ private Context mContext;
+ private AlphaOptimizedImageButton mIcon;
+ private AlphaOptimizedImageButton mMoreIcon;
+ private boolean mSelected = false;
+ /** App categories that are to be used with this widget */
+ private String[] mFacetCategories;
+ /** App packages that are allowed to be used with this widget */
+ private String[] mFacetPackages;
+
+
+ public CarFacetButton(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mContext = context;
+ View.inflate(context, R.layout.car_facet_button, this);
+
+ // extract custom attributes
+ TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CarFacetButton);
+ setupIntents(typedArray);
+ setupIcons(typedArray);
+ }
+
+ /**
+ * Reads the custom attributes to setup click handlers for this component.
+ */
+ private void setupIntents(TypedArray typedArray) {
+ String intentString = typedArray.getString(R.styleable.CarFacetButton_intent);
+ String longPressIntentString = typedArray.getString(R.styleable.CarFacetButton_longIntent);
+ String categoryString = typedArray.getString(R.styleable.CarFacetButton_categories);
+ String packageString = typedArray.getString(R.styleable.CarFacetButton_packages);
+ try {
+ final Intent intent = Intent.parseUri(intentString, Intent.URI_INTENT_SCHEME);
+ intent.putExtra(EXTRA_FACET_ID, Integer.toString(getId()));
+
+ if (packageString != null) {
+ mFacetPackages = packageString.split(FACET_FILTER_DELIMITER);
+ intent.putExtra(EXTRA_FACET_PACKAGES, mFacetPackages);
+ }
+ if (categoryString != null) {
+ mFacetCategories = categoryString.split(FACET_FILTER_DELIMITER);
+ intent.putExtra(EXTRA_FACET_CATEGORIES, mFacetCategories);
+ }
+
+ setOnClickListener(v -> {
+ intent.putExtra(EXTRA_FACET_LAUNCH_PICKER, mSelected);
+ mContext.startActivity(intent);
+ });
+
+ if (longPressIntentString != null) {
+ final Intent longPressIntent = Intent.parseUri(longPressIntentString,
+ Intent.URI_INTENT_SCHEME);
+ setOnLongClickListener(v -> {
+ mContext.startActivity(longPressIntent);
+ return true;
+ });
+ }
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to attach intent", e);
+ }
+ }
+
+
+ private void setupIcons(TypedArray styledAttributes) {
+ mIcon = findViewById(R.id.car_nav_button_icon);
+ mIcon.setScaleType(ImageView.ScaleType.CENTER);
+ mIcon.setClickable(false);
+ mIcon.setAlpha(UNSELECTED_ALPHA);
+ int iconResourceId = styledAttributes.getResourceId(R.styleable.CarFacetButton_icon, 0);
+ if (iconResourceId == 0) {
+ throw new RuntimeException("specified icon resource was not found and is required");
+ }
+ mIcon.setImageResource(iconResourceId);
+
+ mMoreIcon = findViewById(R.id.car_nav_button_more_icon);
+ mMoreIcon.setClickable(false);
+ mMoreIcon.setImageDrawable(getContext().getDrawable(R.drawable.car_ic_arrow));
+ mMoreIcon.setAlpha(UNSELECTED_ALPHA);
+ mMoreIcon.setVisibility(GONE);
+ }
+
+ /**
+ * @return The app categories the component represents
+ */
+ public String[] getCategories() {
+ if (mFacetCategories == null) {
+ return new String[0];
+ }
+ return mFacetCategories;
+ }
+
+ /**
+ * @return The valid packages that should be considered.
+ */
+ public String[] getFacetPackages() {
+ if (mFacetPackages == null) {
+ return new String[0];
+ }
+ return mFacetPackages;
+ }
+
+ /**
+ * Updates the alpha of the icons to "selected" and shows the "More icon"
+ * @param selected true if the view must be selected, false otherwise
+ */
+ public void setSelected(boolean selected) {
+ super.setSelected(selected);
+ setSelected(selected, selected);
+ }
+
+ /**
+ * Updates the visual state to let the user know if it's been selected.
+ * @param selected true if should update the alpha of the icon to selected, false otherwise
+ * @param showMoreIcon true if the "more icon" should be shown, false otherwise
+ */
+ public void setSelected(boolean selected, boolean showMoreIcon) {
+ mSelected = selected;
+ if (selected) {
+ mMoreIcon.setVisibility(showMoreIcon ? VISIBLE : GONE);
+ mMoreIcon.setAlpha(SELECTED_ALPHA);
+ mIcon.setAlpha(SELECTED_ALPHA);
+ } else {
+ mMoreIcon.setVisibility(GONE);
+ mIcon.setAlpha(UNSELECTED_ALPHA);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButtonController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButtonController.java
new file mode 100644
index 0000000..e8c9a5e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButtonController.java
@@ -0,0 +1,114 @@
+package com.android.systemui.statusbar.car;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * CarFacetButtons placed on the nav bar are designed to have visual indication that the active
+ * application on screen is associated with it. This is basically a similar concept to a radio
+ * button group.
+ */
+public class CarFacetButtonController {
+
+ protected HashMap<String, CarFacetButton> mButtonsByCategory = new HashMap<>();
+ protected HashMap<String, CarFacetButton> mButtonsByPackage = new HashMap<>();
+ protected CarFacetButton mSelectedFacetButton;
+ protected Context mContext;
+
+ public CarFacetButtonController(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Goes through the supplied CarNavigationBarView and keeps track of all the CarFacetButtons
+ * such that it can select and unselect them based on running task chages
+ * @param bar that may contain CarFacetButtons
+ */
+ public void addCarNavigationBar(CarNavigationBarView bar) {
+ findFacets(bar);
+ }
+
+ private void findFacets(ViewGroup root) {
+ final int childCount = root.getChildCount();
+
+ for (int i = 0; i < childCount; ++i) {
+ final View v = root.getChildAt(i);
+ if (v instanceof CarFacetButton) {
+ CarFacetButton facetButton = (CarFacetButton) v;
+ String[] categories = facetButton.getCategories();
+ for (int j = 0; j < categories.length; j++) {
+ String category = categories[j];
+ mButtonsByCategory.put(category, facetButton);
+ }
+
+ String[] facetPackages = facetButton.getFacetPackages();
+ for (int j = 0; j < facetPackages.length; j++) {
+ String facetPackage = facetPackages[j];
+ mButtonsByPackage.put(facetPackage, facetButton);
+ }
+ } else if (v instanceof ViewGroup) {
+ findFacets((ViewGroup) v);
+ }
+ }
+ }
+
+
+ /**
+ * This will unselect the currently selected CarFacetButton and determine which one should be
+ * selected next. It does this by reading the properties on the CarFacetButton and seeing if
+ * they are a match with the supplied taskino.
+ * @param taskInfo of the currently running application
+ */
+ public void taskChanged(ActivityManager.RunningTaskInfo taskInfo) {
+ if (taskInfo == null || taskInfo.baseActivity == null) {
+ return;
+ }
+ String packageName = taskInfo.baseActivity.getPackageName();
+
+ // If the package name belongs to a filter, then highlight appropriate button in
+ // the navigation bar.
+ if (mSelectedFacetButton != null) {
+ mSelectedFacetButton.setSelected(false);
+ }
+ CarFacetButton facetButton = mButtonsByPackage.get(packageName);
+ if (facetButton != null) {
+ facetButton.setSelected(true);
+ mSelectedFacetButton = facetButton;
+ } else {
+ String category = getPackageCategory(packageName);
+ if (category != null) {
+ facetButton = mButtonsByCategory.get(category);
+ facetButton.setSelected(true);
+ mSelectedFacetButton = facetButton;
+ }
+ }
+ }
+
+ protected String getPackageCategory(String packageName) {
+ PackageManager pm = mContext.getPackageManager();
+ Set<String> supportedCategories = mButtonsByCategory.keySet();
+ for (String category : supportedCategories) {
+ Intent intent = new Intent();
+ intent.setPackage(packageName);
+ intent.setAction(Intent.ACTION_MAIN);
+ intent.addCategory(category);
+ List<ResolveInfo> list = pm.queryIntentActivities(intent, 0);
+ if (list.size() > 0) {
+ // Cache this package name into facetPackageMap, so we won't have to query
+ // all categories next time this package name shows up.
+ mButtonsByPackage.put(packageName, mButtonsByCategory.get(category));
+ return category;
+ }
+ }
+ return null;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
deleted file mode 100644
index 64c52ed..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
+++ /dev/null
@@ -1,407 +0,0 @@
-/*
- * 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 com.android.systemui.statusbar.car;
-
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-
-import android.app.ActivityManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.drawable.Drawable;
-import android.support.v4.util.SimpleArrayMap;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.SparseBooleanArray;
-import android.view.View;
-import android.widget.LinearLayout;
-import com.android.systemui.R;
-
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * A controller to populate data for CarNavigationBarView and handle user interactions.
- *
- * <p>Each button inside the navigation bar is defined by data in arrays_car.xml. OEMs can
- * customize the navigation buttons by updating arrays_car.xml appropriately in an overlay.
- */
-class CarNavigationBarController {
- private static final String TAG = "CarNavBarController";
-
- private static final String EXTRA_FACET_CATEGORIES = "categories";
- private static final String EXTRA_FACET_PACKAGES = "packages";
- private static final String EXTRA_FACET_ID = "filter_id";
- private static final String EXTRA_FACET_LAUNCH_PICKER = "launch_picker";
-
- /**
- * Each facet of the navigation bar maps to a set of package names or categories defined in
- * arrays_car.xml. Package names for a given facet are delimited by ";".
- */
- private static final String FACET_FILTER_DELIMITER = ";";
-
- private final Context mContext;
- private final CarNavigationBarView mNavBar;
- private final CarStatusBar mStatusBar;
-
- /**
- * Set of categories each facet will filter on.
- */
- private final List<String[]> mFacetCategories = new ArrayList<>();
-
- /**
- * Set of package names each facet will filter on.
- */
- private final List<String[]> mFacetPackages = new ArrayList<>();
-
- private final SimpleArrayMap<String, Integer> mFacetCategoryMap = new SimpleArrayMap<>();
- private final SimpleArrayMap<String, Integer> mFacetPackageMap = new SimpleArrayMap<>();
-
- private final List<CarNavigationButton> mNavButtons = new ArrayList<>();
-
- private final SparseBooleanArray mFacetHasMultipleAppsCache = new SparseBooleanArray();
-
- private int mCurrentFacetIndex;
- private Intent mPersistentTaskIntent;
-
- public CarNavigationBarController(Context context, CarNavigationBarView navBar,
- CarStatusBar activityStarter) {
- mContext = context;
- mNavBar = navBar;
- mStatusBar = activityStarter;
- bind();
-
- if (context.getResources().getBoolean(R.bool.config_enablePersistentDockedActivity)) {
- setupPersistentDockedTask();
- }
- }
-
- private void setupPersistentDockedTask() {
- try {
- mPersistentTaskIntent = Intent.parseUri(
- mContext.getString(R.string.config_persistentDockedActivityIntentUri),
- Intent.URI_INTENT_SCHEME);
- } catch (URISyntaxException e) {
- Log.e(TAG, "Malformed persistent task intent.");
- }
- }
-
- public void taskChanged(String packageName, ActivityManager.RunningTaskInfo taskInfo) {
- // If the package name belongs to a filter, then highlight appropriate button in
- // the navigation bar.
- if (mFacetPackageMap.containsKey(packageName)) {
- setCurrentFacet(mFacetPackageMap.get(packageName));
- }
-
- // Check if the package matches any of the categories for the facets
- String category = getPackageCategory(packageName);
- if (category != null) {
- setCurrentFacet(mFacetCategoryMap.get(category));
- }
-
- // Set up the persistent docked task if needed.
- boolean isHomeTask =
- taskInfo.configuration.windowConfiguration.getActivityType() == ACTIVITY_TYPE_HOME;
- if (mPersistentTaskIntent != null && !mStatusBar.hasDockedTask() && !isHomeTask) {
- mStatusBar.startActivityOnStack(mPersistentTaskIntent,
- WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED);
- }
- }
-
- public void onPackageChange(String packageName) {
- if (mFacetPackageMap.containsKey(packageName)) {
- int index = mFacetPackageMap.get(packageName);
- mFacetHasMultipleAppsCache.put(index, facetHasMultiplePackages(index));
- // No need to check categories because we've already refreshed the cache.
- return;
- }
-
- String category = getPackageCategory(packageName);
- if (mFacetCategoryMap.containsKey(category)) {
- int index = mFacetCategoryMap.get(category);
- mFacetHasMultipleAppsCache.put(index, facetHasMultiplePackages(index));
- }
- }
-
- /**
- * Iterates through the items in arrays_car.xml and sets up the facet bar buttons to
- * perform the task in that configuration file when clicked or long-pressed.
- */
- private void bind() {
- Resources res = mContext.getResources();
-
- TypedArray icons = res.obtainTypedArray(R.array.car_facet_icons);
- TypedArray intents = res.obtainTypedArray(R.array.car_facet_intent_uris);
- TypedArray longPressIntents = res.obtainTypedArray(R.array.car_facet_longpress_intent_uris);
- TypedArray facetPackageNames = res.obtainTypedArray(R.array.car_facet_package_filters);
- TypedArray facetCategories = res.obtainTypedArray(R.array.car_facet_category_filters);
-
- try {
- if (icons.length() != intents.length()
- || icons.length() != longPressIntents.length()
- || icons.length() != facetPackageNames.length()
- || icons.length() != facetCategories.length()) {
- throw new RuntimeException("car_facet array lengths do not match");
- }
-
- for (int i = 0, size = icons.length(); i < size; i++) {
- Drawable icon = icons.getDrawable(i);
- CarNavigationButton button = createNavButton(icon);
- initClickListeners(button, i, intents.getString(i), longPressIntents.getString(i));
-
- mNavButtons.add(button);
- mNavBar.addButton(button, createNavButton(icon) /* lightsOutButton */);
-
- initFacetFilterMaps(i, facetPackageNames.getString(i).split(FACET_FILTER_DELIMITER),
- facetCategories.getString(i).split(FACET_FILTER_DELIMITER));
- mFacetHasMultipleAppsCache.put(i, facetHasMultiplePackages(i));
- }
- } finally {
- // Clean up all the TypedArrays.
- icons.recycle();
- intents.recycle();
- longPressIntents.recycle();
- facetPackageNames.recycle();
- facetCategories.recycle();
- }
- }
-
- /**
- * Recreates each of the buttons on a density or font scale change. This manual process is
- * necessary since this class is not part of an activity that automatically gets recreated.
- */
- public void onDensityOrFontScaleChanged() {
- TypedArray icons = mContext.getResources().obtainTypedArray(R.array.car_facet_icons);
-
- try {
- int length = icons.length();
- if (length != mNavButtons.size()) {
- // This should not happen since the mNavButtons list is created from the length
- // of the icons array in bind().
- throw new RuntimeException("car_facet array lengths do not match number of "
- + "created buttons.");
- }
-
- for (int i = 0; i < length; i++) {
- Drawable icon = icons.getDrawable(i);
-
- // Setting a new icon will trigger a requestLayout() call if necessary.
- mNavButtons.get(i).setResources(icon);
- }
- } finally {
- icons.recycle();
- }
- }
-
- private void initFacetFilterMaps(int id, String[] packageNames, String[] categories) {
- mFacetCategories.add(categories);
- for (String category : categories) {
- mFacetCategoryMap.put(category, id);
- }
-
- mFacetPackages.add(packageNames);
- for (String packageName : packageNames) {
- mFacetPackageMap.put(packageName, id);
- }
- }
-
- private String getPackageCategory(String packageName) {
- PackageManager pm = mContext.getPackageManager();
- int size = mFacetCategories.size();
- // For each facet, check if the given package name matches one of its categories
- for (int i = 0; i < size; i++) {
- String[] categories = mFacetCategories.get(i);
- for (int j = 0; j < categories.length; j++) {
- String category = categories[j];
- Intent intent = new Intent();
- intent.setPackage(packageName);
- intent.setAction(Intent.ACTION_MAIN);
- intent.addCategory(category);
- List<ResolveInfo> list = pm.queryIntentActivities(intent, 0);
- if (list.size() > 0) {
- // Cache this package name into facetPackageMap, so we won't have to query
- // all categories next time this package name shows up.
- mFacetPackageMap.put(packageName, mFacetCategoryMap.get(category));
- return category;
- }
- }
- }
- return null;
- }
-
- /**
- * Helper method to check if a given facet has multiple packages associated with it. This can
- * be resource defined package names or package names filtered by facet category.
- *
- * @return {@code true} if the facet at the given index has more than one package.
- */
- private boolean facetHasMultiplePackages(int index) {
- PackageManager pm = mContext.getPackageManager();
-
- // Check if the packages defined for the filter actually exists on the device
- String[] packages = mFacetPackages.get(index);
- if (packages.length > 1) {
- int count = 0;
- for (int i = 0; i < packages.length; i++) {
- count += pm.getLaunchIntentForPackage(packages[i]) != null ? 1 : 0;
- if (count > 1) {
- return true;
- }
- }
- }
-
- // If there weren't multiple packages defined for the facet, check the categories
- // and see if they resolve to multiple package names
- String categories[] = mFacetCategories.get(index);
-
- int count = 0;
- for (int i = 0; i < categories.length; i++) {
- String category = categories[i];
- Intent intent = new Intent();
- intent.setAction(Intent.ACTION_MAIN);
- intent.addCategory(category);
- count += pm.queryIntentActivities(intent, 0).size();
- if (count > 1) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Sets the facet at the given index to be the facet that is currently active. The button will
- * be highlighted appropriately.
- */
- private void setCurrentFacet(int index) {
- if (index == mCurrentFacetIndex) {
- return;
- }
-
- if (mNavButtons.get(mCurrentFacetIndex) != null) {
- mNavButtons.get(mCurrentFacetIndex)
- .setSelected(false /* selected */, false /* showMoreIcon */);
- }
-
- if (mNavButtons.get(index) != null) {
- mNavButtons.get(index).setSelected(true /* selected */,
- mFacetHasMultipleAppsCache.get(index) /* showMoreIcon */);
- }
-
- mCurrentFacetIndex = index;
- }
-
- /**
- * Creates the View that is used for the buttons along the navigation bar.
- *
- * @param icon The icon to be used for the button.
- */
- private CarNavigationButton createNavButton(Drawable icon) {
- CarNavigationButton button = (CarNavigationButton) View.inflate(mContext,
- R.layout.car_navigation_button, null);
- button.setResources(icon);
- LinearLayout.LayoutParams lp =
- new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.MATCH_PARENT, 1);
- button.setLayoutParams(lp);
-
- return button;
- }
-
- /**
- * Initializes the click and long click listeners that correspond to the given command string.
- * The click listeners are attached to the given button.
- */
- private void initClickListeners(View button, int index, String clickString,
- String longPressString) {
- // Each button at least have an action when pressed.
- if (TextUtils.isEmpty(clickString)) {
- throw new RuntimeException("Facet at index " + index + " does not have click action.");
- }
-
- try {
- Intent intent = Intent.parseUri(clickString, Intent.URI_INTENT_SCHEME);
- button.setOnClickListener(v -> onFacetClicked(intent, index));
- } catch (URISyntaxException e) {
- throw new RuntimeException("Malformed intent uri", e);
- }
-
- if (TextUtils.isEmpty(longPressString)) {
- button.setLongClickable(false);
- return;
- }
-
- try {
- Intent intent = Intent.parseUri(longPressString, Intent.URI_INTENT_SCHEME);
- button.setOnLongClickListener(v -> {
- onFacetLongClicked(intent, index);
- return true;
- });
- } catch (URISyntaxException e) {
- throw new RuntimeException("Malformed long-press intent uri", e);
- }
- }
-
- /**
- * Handles a click on a facet. A click will trigger the given Intent.
- *
- * @param index The index of the facet that was clicked.
- */
- private void onFacetClicked(Intent intent, int index) {
- String packageName = intent.getPackage();
-
- if (packageName == null && !intent.getCategories().contains(Intent.CATEGORY_HOME)) {
- return;
- }
-
- intent.putExtra(EXTRA_FACET_CATEGORIES, mFacetCategories.get(index));
- intent.putExtra(EXTRA_FACET_PACKAGES, mFacetPackages.get(index));
- // The facet is identified by the index in which it was added to the nav bar.
- // This value can be used to determine which facet was selected
- intent.putExtra(EXTRA_FACET_ID, Integer.toString(index));
-
- // If the current facet is clicked, we want to launch the picker by default
- // rather than the "preferred/last run" app.
- intent.putExtra(EXTRA_FACET_LAUNCH_PICKER, index == mCurrentFacetIndex);
-
- int windowingMode = WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
- int activityType = ACTIVITY_TYPE_UNDEFINED;
- if (intent.getCategories().contains(Intent.CATEGORY_HOME)) {
- windowingMode = WINDOWING_MODE_UNDEFINED;
- activityType = ACTIVITY_TYPE_HOME;
- }
-
- setCurrentFacet(index);
- mStatusBar.startActivityOnStack(intent, windowingMode, activityType);
- }
-
- /**
- * Handles a long-press on a facet. The long-press will trigger the given Intent.
- *
- * @param index The index of the facet that was clicked.
- */
- private void onFacetLongClicked(Intent intent, int index) {
- setCurrentFacet(index);
- mStatusBar.startActivityOnStack(intent,
- WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_UNDEFINED);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java
index e5a311d..1d9ef61 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java
@@ -16,17 +16,15 @@
package com.android.systemui.statusbar.car;
+import android.app.UiModeManager;
import android.content.Context;
-import android.graphics.Canvas;
import android.util.AttributeSet;
-import android.view.MotionEvent;
+import android.util.Log;
import android.view.View;
import android.widget.LinearLayout;
+import com.android.keyguard.AlphaOptimizedImageButton;
import com.android.systemui.R;
-import com.android.systemui.plugins.statusbar.phone.NavGesture;
-import com.android.systemui.statusbar.phone.NavigationBarGestureHelper;
-import com.android.systemui.statusbar.phone.NavigationBarView;
/**
* A custom navigation bar for the automotive use case.
@@ -34,9 +32,10 @@
* The navigation bar in the automotive use case is more like a list of shortcuts, rendered
* in a linear layout.
*/
-class CarNavigationBarView extends NavigationBarView {
+class CarNavigationBarView extends LinearLayout {
private LinearLayout mNavButtons;
- private LinearLayout mLightsOutButtons;
+ private AlphaOptimizedImageButton mNotificationsButton;
+ private CarStatusBar mCarStatusBar;
public CarNavigationBarView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -45,99 +44,16 @@
@Override
public void onFinishInflate() {
mNavButtons = findViewById(R.id.nav_buttons);
- mLightsOutButtons = findViewById(R.id.lights_out);
+
+ mNotificationsButton = findViewById(R.id.notifications);
+ mNotificationsButton.setOnClickListener(this::onNotificationsClick);
}
- public void addButton(CarNavigationButton button, CarNavigationButton lightsOutButton){
- mNavButtons.addView(button);
- mLightsOutButtons.addView(lightsOutButton);
+ void setStatusBar(CarStatusBar carStatusBar) {
+ mCarStatusBar = carStatusBar;
}
- @Override
- public void setDisabledFlags(int disabledFlags, boolean force) {
- // TODO: Populate.
- }
-
- @Override
- public void reorient() {
- // We expect the car head unit to always have a fixed rotation so we ignore this. The super
- // class implentation expects mRotatedViews to be populated, so if you call into it, there
- // is a possibility of a NullPointerException.
- }
-
- @Override
- public View getCurrentView() {
- return this;
- }
-
- @Override
- public void setNavigationIconHints(int hints, boolean force) {
- // We do not need to set the navigation icon hints for a vehicle
- // Calling setNavigationIconHints in the base class will result in a NPE as the car
- // navigation bar does not have a back button.
- }
-
- @Override
- public void onPluginConnected(NavGesture plugin, Context context) {
- // set to null version of the plugin ignoring incoming arg.
- super.onPluginConnected(new NullNavGesture(), context);
- }
-
- @Override
- public void onPluginDisconnected(NavGesture plugin) {
- // reinstall the null nav gesture plugin
- super.onPluginConnected(new NullNavGesture(), getContext());
- }
-
- /**
- * Null object pattern to work around expectations of the base class.
- * This is a temporary solution to have the car system ui working.
- * Already underway is a refactor of they car sys ui as to not use this class
- * hierarchy.
- */
- private static class NullNavGesture implements NavGesture {
- @Override
- public GestureHelper getGestureHelper() {
- return new GestureHelper() {
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- return false;
- }
-
- @Override
- public boolean onInterceptTouchEvent(MotionEvent event) {
- return false;
- }
-
- @Override
- public void setBarState(boolean vertical, boolean isRtl) {
- }
-
- @Override
- public void onDraw(Canvas canvas) {
- }
-
- @Override
- public void onDarkIntensityChange(float intensity) {
- }
-
- @Override
- public void onLayout(boolean changed, int left, int top, int right, int bottom) {
- }
- };
- }
-
- @Override
- public int getVersion() {
- return 0;
- }
-
- @Override
- public void onCreate(Context sysuiContext, Context pluginContext) {
- }
-
- @Override
- public void onDestroy() {
- }
+ protected void onNotificationsClick(View v) {
+ mCarStatusBar.togglePanel();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java
index 2de358f..0cdaec1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java
@@ -1,72 +1,87 @@
-/*
- * 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 com.android.systemui.statusbar.car;
import android.content.Context;
-import android.graphics.drawable.Drawable;
+import android.content.Intent;
+import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.widget.ImageView;
-import android.widget.RelativeLayout;
-import com.android.keyguard.AlphaOptimizedImageButton;
import com.android.systemui.R;
+import java.net.URISyntaxException;
+
/**
- * A wrapper view for a car navigation facet, which includes a button icon and a drop down icon.
+ * CarNavigationButton is an image button that allows for a bit more configuration at the
+ * xml file level. This allows for more control via overlays instead of having to update
+ * code.
*/
-public class CarNavigationButton extends RelativeLayout {
+public class CarNavigationButton extends com.android.keyguard.AlphaOptimizedImageButton {
+
private static final float SELECTED_ALPHA = 1;
private static final float UNSELECTED_ALPHA = 0.7f;
- private AlphaOptimizedImageButton mIcon;
- private AlphaOptimizedImageButton mMoreIcon;
+ private Context mContext;
+ private String mIntent = null;
+ private String mLongIntent = null;
+ private boolean mBroadcastIntent = false;
+ private boolean mSelected = false;
+
public CarNavigationButton(Context context, AttributeSet attrs) {
super(context, attrs);
+ mContext = context;
+ TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CarNavigationButton);
+ mIntent = typedArray.getString(R.styleable.CarNavigationButton_intent);
+ mLongIntent = typedArray.getString(R.styleable.CarNavigationButton_longIntent);
+ mBroadcastIntent = typedArray.getBoolean(R.styleable.CarNavigationButton_broadcast, false);
}
+
+ /**
+ * After the standard inflate this then adds the xml defined intents to click and long click
+ * actions if defined.
+ */
@Override
public void onFinishInflate() {
super.onFinishInflate();
- mIcon = findViewById(R.id.car_nav_button_icon);
- mIcon.setScaleType(ImageView.ScaleType.CENTER);
- mIcon.setClickable(false);
- mIcon.setBackgroundColor(android.R.color.transparent);
- mIcon.setAlpha(UNSELECTED_ALPHA);
-
- mMoreIcon = findViewById(R.id.car_nav_button_more_icon);
- mMoreIcon.setClickable(false);
- mMoreIcon.setBackgroundColor(android.R.color.transparent);
- mMoreIcon.setVisibility(INVISIBLE);
- mMoreIcon.setImageDrawable(getContext().getDrawable(R.drawable.car_ic_arrow));
- mMoreIcon.setAlpha(UNSELECTED_ALPHA);
- }
-
- public void setResources(Drawable icon) {
- mIcon.setImageDrawable(icon);
- }
-
- public void setSelected(boolean selected, boolean showMoreIcon) {
- if (selected) {
- mMoreIcon.setVisibility(showMoreIcon ? VISIBLE : INVISIBLE);
- mMoreIcon.setAlpha(SELECTED_ALPHA);
- mIcon.setAlpha(SELECTED_ALPHA);
- } else {
- mMoreIcon.setVisibility(INVISIBLE);
- mIcon.setAlpha(UNSELECTED_ALPHA);
+ setScaleType(ImageView.ScaleType.CENTER);
+ setAlpha(UNSELECTED_ALPHA);
+ try {
+ if (mIntent != null) {
+ final Intent intent = Intent.parseUri(mIntent, Intent.URI_INTENT_SCHEME);
+ intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
+ setOnClickListener(v -> {
+ if (mBroadcastIntent) {
+ mContext.sendBroadcast(intent);
+ return;
+ }
+ mContext.startActivity(intent);
+ });
+ }
+ } catch (URISyntaxException e) {
+ throw new RuntimeException("Failed to attach intent", e);
}
+
+ try {
+ if (mLongIntent != null) {
+ final Intent intent = Intent.parseUri(mLongIntent, Intent.URI_INTENT_SCHEME);
+ intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
+ setOnLongClickListener(v -> {
+ mContext.startActivity(intent);
+ return true;
+ });
+ }
+ } catch (URISyntaxException e) {
+ throw new RuntimeException("Failed to attach long press intent", e);
+ }
+ }
+
+ /**
+ * @param selected true if should indicate if this is a selected state, false otherwise
+ */
+ public void setSelected(boolean selected) {
+ super.setSelected(selected);
+ mSelected = selected;
+ setAlpha(mSelected ? SELECTED_ALPHA : UNSELECTED_ALPHA);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 3dfb913..c15a013 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -18,17 +18,14 @@
import android.app.ActivityManager;
import android.app.ActivityOptions;
-import android.content.BroadcastReceiver;
-import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.service.notification.StatusBarNotification;
import android.util.Log;
+import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
@@ -46,10 +43,7 @@
import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
-import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.statusbar.ExpandableNotificationRow;
-import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment;
import com.android.systemui.statusbar.phone.NavigationBarView;
@@ -69,7 +63,6 @@
private TaskStackListenerImpl mTaskStackListener;
- private CarNavigationBarController mController;
private FullscreenUserSwitcher mFullscreenUserSwitcher;
private CarBatteryController mCarBatteryController;
@@ -78,15 +71,23 @@
private ConnectedDeviceSignalController mConnectedDeviceSignalController;
private ViewGroup mNavigationBarWindow;
+ private ViewGroup mLeftNavigationBarWindow;
+ private ViewGroup mRightNavigationBarWindow;
private CarNavigationBarView mNavigationBarView;
+ private CarNavigationBarView mLeftNavigationBarView;
+ private CarNavigationBarView mRightNavigationBarView;
private final Object mQueueLock = new Object();
+ private boolean mShowLeft;
+ private boolean mShowRight;
+ private boolean mShowBottom;
+ private CarFacetButtonController mCarFacetButtonController;
+
@Override
public void start() {
super.start();
mTaskStackListener = new TaskStackListenerImpl();
ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
- registerPackageChangeReceivers();
mStackScroller.setScrollingEnabled(true);
@@ -104,6 +105,16 @@
mNavigationBarView = null;
}
+ if (mLeftNavigationBarWindow != null) {
+ mWindowManager.removeViewImmediate(mLeftNavigationBarWindow);
+ mLeftNavigationBarView = null;
+ }
+
+ if (mRightNavigationBarWindow != null) {
+ mWindowManager.removeViewImmediate(mRightNavigationBarWindow);
+ mRightNavigationBarView = null;
+ }
+
super.destroy();
}
@@ -153,10 +164,36 @@
@Override
protected void createNavigationBar() {
+ mCarFacetButtonController = new CarFacetButtonController(mContext);
if (mNavigationBarView != null) {
return;
}
+ mShowBottom = mContext.getResources().getBoolean(R.bool.config_enableBottomNavigationBar);
+ if (mShowBottom) {
+ buildBottomBar();
+ }
+
+ int widthForSides = mContext.getResources().getDimensionPixelSize(
+ R.dimen.navigation_bar_height_car_mode);
+
+
+ mShowLeft = mContext.getResources().getBoolean(R.bool.config_enableLeftNavigationBar);
+
+ if (mShowLeft) {
+ buildLeft(widthForSides);
+ }
+
+ mShowRight = mContext.getResources().getBoolean(R.bool.config_enableRightNavigationBar);
+
+ if (mShowRight) {
+ buildRight(widthForSides);
+ }
+
+ }
+
+
+ private void buildBottomBar() {
// SystemUI requires that the navigation bar view have a parent. Since the regular
// StatusBar inflates navigation_bar_window as this parent view, use the same view for the
// CarNavigationBarView.
@@ -171,17 +208,15 @@
mNavigationBarView = (CarNavigationBarView) mNavigationBarWindow.getChildAt(0);
if (mNavigationBarView == null) {
Log.e(TAG, "CarStatusBar failed inflate for R.layout.car_navigation_bar");
+ throw new RuntimeException("Unable to build botom nav bar due to missing layout");
}
+ mNavigationBarView.setStatusBar(this);
- mController = new CarNavigationBarController(mContext, mNavigationBarView,
- this /* ActivityStarter*/);
- mNavigationBarView.getBarTransitions().setAlwaysOpaque(true);
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
- WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
- | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
@@ -189,9 +224,74 @@
lp.setTitle("CarNavigationBar");
lp.windowAnimations = 0;
+
+ mCarFacetButtonController.addCarNavigationBar(mNavigationBarView);
mWindowManager.addView(mNavigationBarWindow, lp);
}
+ private void buildLeft(int widthForSides) {
+ mLeftNavigationBarWindow = (ViewGroup) View.inflate(mContext,
+ R.layout.navigation_bar_window, null);
+ if (mLeftNavigationBarWindow == null) {
+ Log.e(TAG, "CarStatusBar failed inflate for R.layout.navigation_bar_window");
+ }
+
+ View.inflate(mContext, R.layout.car_left_navigation_bar, mLeftNavigationBarWindow);
+ mLeftNavigationBarView = (CarNavigationBarView) mLeftNavigationBarWindow.getChildAt(0);
+ if (mLeftNavigationBarView == null) {
+ Log.e(TAG, "CarStatusBar failed inflate for R.layout.car_navigation_bar");
+ throw new RuntimeException("Unable to build left nav bar due to missing layout");
+ }
+ mLeftNavigationBarView.setStatusBar(this);
+ mCarFacetButtonController.addCarNavigationBar(mLeftNavigationBarView);
+
+ WindowManager.LayoutParams leftlp = new WindowManager.LayoutParams(
+ widthForSides, LayoutParams.MATCH_PARENT,
+ WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+ | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
+ PixelFormat.TRANSLUCENT);
+ leftlp.setTitle("LeftCarNavigationBar");
+ leftlp.windowAnimations = 0;
+ leftlp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
+ leftlp.gravity = Gravity.LEFT;
+ mWindowManager.addView(mLeftNavigationBarWindow, leftlp);
+ }
+
+
+ private void buildRight(int widthForSides) {
+ mRightNavigationBarWindow = (ViewGroup) View.inflate(mContext,
+ R.layout.navigation_bar_window, null);
+ if (mRightNavigationBarWindow == null) {
+ Log.e(TAG, "CarStatusBar failed inflate for R.layout.navigation_bar_window");
+ }
+
+ View.inflate(mContext, R.layout.car_right_navigation_bar, mRightNavigationBarWindow);
+ mRightNavigationBarView = (CarNavigationBarView) mRightNavigationBarWindow.getChildAt(0);
+ if (mRightNavigationBarView == null) {
+ Log.e(TAG, "CarStatusBar failed inflate for R.layout.car_navigation_bar");
+ throw new RuntimeException("Unable to build right nav bar due to missing layout");
+ }
+ mRightNavigationBarView.setStatusBar(this);
+ mCarFacetButtonController.addCarNavigationBar(mRightNavigationBarView);
+
+ WindowManager.LayoutParams rightlp = new WindowManager.LayoutParams(
+ widthForSides, LayoutParams.MATCH_PARENT,
+ WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+ | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
+ PixelFormat.TRANSLUCENT);
+ rightlp.setTitle("RightCarNavigationBar");
+ rightlp.windowAnimations = 0;
+ rightlp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
+ rightlp.gravity = Gravity.RIGHT;
+ mWindowManager.addView(mRightNavigationBarWindow, rightlp);
+ }
+
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
//When executing dump() funciton simultaneously, we need to serialize them
@@ -204,8 +304,8 @@
}
pw.print(" mTaskStackListener="); pw.println(mTaskStackListener);
- pw.print(" mController=");
- pw.println(mController);
+ pw.print(" mCarFacetButtonController=");
+ pw.println(mCarFacetButtonController);
pw.print(" mFullscreenUserSwitcher="); pw.println(mFullscreenUserSwitcher);
pw.print(" mCarBatteryController=");
pw.println(mCarBatteryController);
@@ -229,10 +329,6 @@
}
}
- @Override
- public NavigationBarView getNavigationBarView() {
- return mNavigationBarView;
- }
@Override
public View getNavigationBarWindow() {
@@ -269,24 +365,6 @@
}
}
- private BroadcastReceiver mPackageChangeReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (intent.getData() == null || mController == null) {
- return;
- }
- String packageName = intent.getData().getSchemeSpecificPart();
- mController.onPackageChange(packageName);
- }
- };
-
- private void registerPackageChangeReceivers() {
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_PACKAGE_ADDED);
- filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- filter.addDataScheme("package");
- mContext.registerReceiver(mPackageChangeReceiver, filter);
- }
public boolean hasDockedTask() {
return Recents.getSystemServices().hasDockedTask();
@@ -301,10 +379,7 @@
public void onTaskStackChanged() {
ActivityManager.RunningTaskInfo runningTaskInfo =
ActivityManagerWrapper.getInstance().getRunningTask();
- if (runningTaskInfo != null && runningTaskInfo.baseActivity != null) {
- mController.taskChanged(runningTaskInfo.baseActivity.getPackageName(),
- runningTaskInfo);
- }
+ mCarFacetButtonController.taskChanged(runningTaskInfo);
}
}
@@ -346,33 +421,6 @@
// Do nothing, we don't want to display media art in the lock screen for a car.
}
- private int startActivityWithOptions(Intent intent, Bundle options) {
- int result = ActivityManager.START_CANCELED;
- try {
- result = ActivityManager.getService().startActivityAsUser(null /* caller */,
- mContext.getBasePackageName(),
- intent,
- intent.resolveTypeIfNeeded(mContext.getContentResolver()),
- null /* resultTo*/,
- null /* resultWho*/,
- 0 /* requestCode*/,
- Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP,
- null /* profilerInfo*/,
- options,
- UserHandle.CURRENT.getIdentifier());
- } catch (RemoteException e) {
- Log.w(TAG, "Unable to start activity", e);
- }
-
- return result;
- }
-
- public int startActivityOnStack(Intent intent, int windowingMode, int activityType) {
- final ActivityOptions options = ActivityOptions.makeBasic();
- options.setLaunchWindowingMode(windowingMode);
- options.setLaunchActivityType(activityType);
- return startActivityWithOptions(intent, options.toBundle());
- }
@Override
public void animateExpandNotificationsPanel() {
@@ -390,8 +438,6 @@
@Override
public void onDensityOrFontScaleChanged() {
super.onDensityOrFontScaleChanged();
- mController.onDensityOrFontScaleChanged();
-
// Need to update the background on density changed in case the change was due to night
// mode.
mNotificationPanelBackground = getDefaultWallpaper();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java
index 677fa81..0304086 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java
@@ -16,10 +16,10 @@
import android.util.TypedValue;
import android.view.View;
import android.widget.ImageView;
+import com.android.settingslib.graph.SignalDrawable;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.statusbar.ScalingDrawableWrapper;
-import com.android.systemui.statusbar.phone.SignalDrawable;
import com.android.systemui.statusbar.policy.BluetoothController;
import static com.android.systemui.statusbar.phone.StatusBar.DEBUG;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
index 11d20b2..ef44ad1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
@@ -77,11 +77,11 @@
mStatusBar = statusBar;
}
- public ActivityOptions getLaunchAnimation(
- ExpandableNotificationRow sourceNofitication) {
- AnimationRunner animationRunner = new AnimationRunner(sourceNofitication);
- return ActivityOptions.makeRemoteAnimation(
- new RemoteAnimationAdapter(animationRunner, 1000 /* Duration */, 0 /* delay */));
+ public RemoteAnimationAdapter getLaunchAnimation(
+ ExpandableNotificationRow sourceNotification) {
+ AnimationRunner animationRunner = new AnimationRunner(sourceNotification);
+ return new RemoteAnimationAdapter(animationRunner, ANIMATION_DURATION,
+ 0 /* statusBarTransitionDelay */);
}
public boolean isAnimationPending() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 1239a9e..79c605e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -19,6 +19,7 @@
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
import static android.app.StatusBarManager.windowStateToString;
+import static com.android.systemui.shared.system.NavigationBarCompat.InteractionType;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
import static com.android.systemui.statusbar.phone.StatusBar.DEBUG_WINDOW_STATE;
import static com.android.systemui.statusbar.phone.StatusBar.dumpBarTransitions;
@@ -71,7 +72,6 @@
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener;
-import android.widget.Button;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -114,8 +114,6 @@
/** Allow some time inbetween the long press for back and recents. */
private static final int LOCK_TO_APP_GESTURE_TOLERENCE = 200;
- private static final int BUTTON_FADE_IN_OUT_DURATION_MS = 100;
-
protected NavigationBarView mNavigationBarView = null;
protected AssistManager mAssistManager;
@@ -152,7 +150,7 @@
private RotationLockController mRotationLockController;
private TaskStackListenerImpl mTaskStackListener;
- private final Runnable mRemoveRotationProposal = () -> setRotateSuggestionButtonState(false);
+ private final Runnable mRemoveRotationProposal = () -> safeSetRotationButtonState(false);
private Animator mRotateShowAnimator;
private Animator mRotateHideAnimator;
@@ -167,6 +165,11 @@
public void onRecentsAnimationStarted() {
mNavigationBarView.setRecentsAnimationStarted(true);
}
+
+ @Override
+ public void onInteractionFlagsChanged(@InteractionType int flags) {
+ mNavigationBarView.updateStates();
+ }
};
// ----- Fragment Lifecycle Callbacks -----
@@ -361,22 +364,32 @@
// rotate button if shown.
if (!isValid) {
- setRotateSuggestionButtonState(false);
+ safeSetRotationButtonState(false);
return;
}
if (rotation == mWindowManager.getDefaultDisplay().getRotation()) {
// Use this as a signal to remove any current suggestions
getView().getHandler().removeCallbacks(mRemoveRotationProposal);
- setRotateSuggestionButtonState(false);
+ safeSetRotationButtonState(false);
} else {
mLastRotationSuggestion = rotation; // Remember rotation for click
- setRotateSuggestionButtonState(true);
+ safeSetRotationButtonState(true);
rescheduleRotationTimeout(false);
mMetricsLogger.visible(MetricsEvent.ROTATION_SUGGESTION_SHOWN);
}
}
+ private void safeSetRotationButtonState(boolean vis) {
+ if (mNavigationBarView != null) mNavigationBarView.setRotateSuggestionButtonState(vis);
+ }
+
+ private void safeSetRotationButtonState(boolean vis, boolean force) {
+ if (mNavigationBarView != null) {
+ mNavigationBarView.setRotateSuggestionButtonState(vis, force);
+ }
+ }
+
private void rescheduleRotationTimeout(final boolean reasonHover) {
// May be called due to a new rotation proposal or a change in hover state
if (reasonHover) {
@@ -402,84 +415,6 @@
return 6000;
}
- public void setRotateSuggestionButtonState(final boolean visible) {
- setRotateSuggestionButtonState(visible, false);
- }
-
- public void setRotateSuggestionButtonState(final boolean visible, final boolean skipAnim) {
- ButtonDispatcher rotBtn = mNavigationBarView.getRotateSuggestionButton();
- final boolean currentlyVisible = rotBtn.getVisibility() == View.VISIBLE;
-
- // Rerun a show animation to indicate change but don't rerun a hide animation
- if (!visible && !currentlyVisible) return;
-
- View currentView = rotBtn.getCurrentView();
- if (currentView == null) return;
-
- KeyButtonDrawable kbd = rotBtn.getImageDrawable();
- if (kbd == null) return;
-
- AnimatedVectorDrawable animIcon = null;
- if (kbd.getDrawable(0) instanceof AnimatedVectorDrawable) {
- animIcon = (AnimatedVectorDrawable) kbd.getDrawable(0);
- }
-
- if (visible) { // Appear and change
- rotBtn.setVisibility(View.VISIBLE);
- mNavigationBarView.notifySubtreeAccessibilityStateChangedIfNeeded();
-
- if (skipAnim) {
- currentView.setAlpha(1f);
- return;
- }
-
- // Start a new animation if running
- if (mRotateShowAnimator != null) mRotateShowAnimator.pause();
- if (mRotateHideAnimator != null) mRotateHideAnimator.pause();
-
- ObjectAnimator appearFade = ObjectAnimator.ofFloat(currentView, "alpha",
- 0f, 1f);
- appearFade.setDuration(BUTTON_FADE_IN_OUT_DURATION_MS);
- appearFade.setInterpolator(Interpolators.LINEAR);
- mRotateShowAnimator = appearFade;
- appearFade.start();
-
- // Run the rotate icon's animation if it has one
- if (animIcon != null) {
- animIcon.reset();
- animIcon.start();
- }
-
- } else { // Hide
-
- if (skipAnim) {
- rotBtn.setVisibility(View.INVISIBLE);
- mNavigationBarView.notifySubtreeAccessibilityStateChangedIfNeeded();
- return;
- }
-
- // Don't start any new hide animations if one is running
- if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) return;
- // Pause any active show animations but don't reset the AVD to avoid jumps
- if (mRotateShowAnimator != null) mRotateShowAnimator.pause();
-
- ObjectAnimator fadeOut = ObjectAnimator.ofFloat(currentView, "alpha",
- 0f);
- fadeOut.setDuration(BUTTON_FADE_IN_OUT_DURATION_MS);
- fadeOut.setInterpolator(Interpolators.LINEAR);
- fadeOut.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- rotBtn.setVisibility(View.INVISIBLE);
- mNavigationBarView.notifySubtreeAccessibilityStateChangedIfNeeded();
- }
- });
-
- mRotateHideAnimator = fadeOut;
- fadeOut.start();
- }
- }
-
// Injected from StatusBar at creation.
public void setCurrentSysuiVisibility(int systemUiVisibility) {
mSystemUiVisibility = systemUiVisibility;
@@ -892,7 +827,7 @@
if (shouldOverrideUserLockPrefs(rotation)) {
mRotationLockController.setRotationLockedAtAngle(true, rotation);
}
- setRotateSuggestionButtonState(false, true);
+ safeSetRotationButtonState(false, true);
}
if (mNavigationBarView != null
@@ -928,22 +863,22 @@
@Override
public void onTaskStackChanged() {
- setRotateSuggestionButtonState(false);
+ safeSetRotationButtonState(false);
}
@Override
public void onTaskRemoved(int taskId) {
- setRotateSuggestionButtonState(false);
+ safeSetRotationButtonState(false);
}
@Override
public void onTaskMovedToFront(int taskId) {
- setRotateSuggestionButtonState(false);
+ safeSetRotationButtonState(false);
}
@Override
public void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation) {
- setRotateSuggestionButtonState(false);
+ safeSetRotationButtonState(false);
}
}
@@ -960,6 +895,7 @@
PixelFormat.TRANSLUCENT);
lp.token = new Binder();
lp.setTitle("NavigationBar");
+ lp.accessibilityTitle = context.getString(R.string.nav_bar);
lp.windowAnimations = 0;
View navigationBarView = LayoutInflater.from(context).inflate(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
index d15c771..8970ea0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
@@ -127,10 +127,13 @@
private boolean proxyMotionEvents(MotionEvent event) {
final IOverviewProxy overviewProxy = mOverviewProxyService.getProxy();
- if (overviewProxy != null) {
+ if (overviewProxy != null && mNavigationBarView.isQuickStepSwipeUpEnabled()) {
mNavigationBarView.requestUnbufferedDispatch(event);
event.transform(mTransformGlobalMatrix);
try {
+ if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+ overviewProxy.onPreMotionEvent(mNavigationBarView.getDownHitTarget());
+ }
overviewProxy.onMotionEvent(event);
if (DEBUG_OVERVIEW_PROXY) {
Log.d(TAG_OPS, "Send MotionEvent: " + event.toString());
@@ -146,8 +149,8 @@
}
public boolean onInterceptTouchEvent(MotionEvent event) {
- int action = event.getAction();
- switch (action & MotionEvent.ACTION_MASK) {
+ int action = event.getActionMasked();
+ switch (action) {
case MotionEvent.ACTION_DOWN: {
mTouchDownX = (int) event.getX();
mTouchDownY = (int) event.getY();
@@ -189,7 +192,7 @@
}
public void onDraw(Canvas canvas) {
- if (mOverviewProxyService.getProxy() != null) {
+ if (mNavigationBarView.isQuickScrubEnabled()) {
mQuickScrubController.onDraw(canvas);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
index 9d20e4e..9894235 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
@@ -57,13 +57,12 @@
public static final String NAV_BAR_LEFT = "sysui_nav_bar_left";
public static final String NAV_BAR_RIGHT = "sysui_nav_bar_right";
- public static final String MENU_IME = "menu_ime";
+ public static final String MENU_IME_ROTATE = "menu_ime";
public static final String BACK = "back";
public static final String HOME = "home";
public static final String RECENT = "recent";
public static final String NAVSPACE = "space";
public static final String CLIPBOARD = "clipboard";
- public static final String ROTATE = "rotate";
public static final String KEY = "key";
public static final String LEFT = "left";
public static final String RIGHT = "right";
@@ -317,10 +316,10 @@
View v = null;
String button = extractButton(buttonSpec);
if (LEFT.equals(button)) {
- String s = Dependency.get(TunerService.class).getValue(NAV_BAR_LEFT, ROTATE);
+ String s = Dependency.get(TunerService.class).getValue(NAV_BAR_LEFT, NAVSPACE);
button = extractButton(s);
} else if (RIGHT.equals(button)) {
- String s = Dependency.get(TunerService.class).getValue(NAV_BAR_RIGHT, MENU_IME);
+ String s = Dependency.get(TunerService.class).getValue(NAV_BAR_RIGHT, MENU_IME_ROTATE);
button = extractButton(s);
}
// Let plugins go first so they can override a standard view if they want.
@@ -334,14 +333,12 @@
v = inflater.inflate(R.layout.back, parent, false);
} else if (RECENT.equals(button)) {
v = inflater.inflate(R.layout.recent_apps, parent, false);
- } else if (MENU_IME.equals(button)) {
+ } else if (MENU_IME_ROTATE.equals(button)) {
v = inflater.inflate(R.layout.menu_ime, parent, false);
} else if (NAVSPACE.equals(button)) {
v = inflater.inflate(R.layout.nav_key_space, parent, false);
} else if (CLIPBOARD.equals(button)) {
v = inflater.inflate(R.layout.clipboard, parent, false);
- } else if (ROTATE.equals(button)) {
- v = inflater.inflate(R.layout.rotate_suggestion, parent, false);
} else if (button.startsWith(KEY)) {
String uri = extractImage(button);
int code = extractKeycode(button);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index af0afbd..0dea6b8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -16,6 +16,13 @@
package com.android.systemui.statusbar.phone;
+import static android.view.MotionEvent.ACTION_DOWN;
+import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_BACK;
+import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_HOME;
+import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_NONE;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.animation.LayoutTransition;
import android.animation.LayoutTransition.TransitionListener;
import android.animation.ObjectAnimator;
@@ -29,9 +36,11 @@
import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.Rect;
+import android.graphics.drawable.AnimatedVectorDrawable;
import android.os.Handler;
import android.os.Message;
import android.os.RemoteException;
+import android.os.SystemProperties;
import android.support.annotation.ColorInt;
import android.util.AttributeSet;
import android.util.Log;
@@ -49,6 +58,7 @@
import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
import com.android.systemui.DockedStackExistsListener;
+import com.android.systemui.Interpolators;
import com.android.systemui.OverviewProxyService;
import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
@@ -57,6 +67,7 @@
import com.android.systemui.plugins.statusbar.phone.NavGesture;
import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper;
import com.android.systemui.recents.RecentsOnboarding;
+import com.android.systemui.shared.system.NavigationBarCompat;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.policy.DeadZone;
import com.android.systemui.statusbar.policy.KeyButtonDrawable;
@@ -66,10 +77,17 @@
import java.io.PrintWriter;
import java.util.function.Consumer;
+import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_DISABLE_QUICK_SCRUB;
+import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_DISABLE_SWIPE_UP;
+import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_HIDE_BACK_BUTTON;
+import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_SHOW_OVERVIEW_BUTTON;
+
public class NavigationBarView extends FrameLayout implements PluginListener<NavGesture> {
final static boolean DEBUG = false;
final static String TAG = "StatusBar/NavBarView";
+ final static int BUTTON_FADE_IN_OUT_DURATION_MS = 100;
+
// slippery nav bar when everything is disabled, e.g. during setup
final static boolean SLIPPERY_WHEN_DISABLED = true;
@@ -85,9 +103,15 @@
boolean mShowMenu;
boolean mShowAccessibilityButton;
boolean mLongClickableAccessibilityButton;
+ boolean mShowRotateButton;
int mDisabledFlags = 0;
int mNavigationIconHints = 0;
+ private @NavigationBarCompat.HitTarget int mDownHitTarget = HIT_TARGET_NONE;
+ private Rect mHomeButtonBounds = new Rect();
+ private Rect mBackButtonBounds = new Rect();
+ private int[] mTmpPosition = new int[2];
+
private KeyButtonDrawable mBackIcon, mBackLandIcon, mBackAltIcon, mBackAltLandIcon;
private KeyButtonDrawable mBackCarModeIcon, mBackLandCarModeIcon;
private KeyButtonDrawable mBackAltCarModeIcon, mBackAltLandCarModeIcon;
@@ -127,6 +151,8 @@
private RecentsOnboarding mRecentsOnboarding;
private NotificationPanelView mPanelView;
+ private Animator mRotateHideAnimator;
+
private class NavTransitionListener implements TransitionListener {
private boolean mBackTransitioning;
private boolean mHomeAppearing;
@@ -217,6 +243,9 @@
mShowAccessibilityButton = false;
mLongClickableAccessibilityButton = false;
+ mOverviewProxyService = Dependency.get(OverviewProxyService.class);
+ mRecentsOnboarding = new RecentsOnboarding(context, mOverviewProxyService);
+
mConfiguration = new Configuration();
mConfiguration.updateFrom(context.getResources().getConfiguration());
updateIcons(context, Configuration.EMPTY, mConfiguration);
@@ -232,9 +261,6 @@
new ButtonDispatcher(R.id.accessibility_button));
mButtonDispatchers.put(R.id.rotate_suggestion,
new ButtonDispatcher(R.id.rotate_suggestion));
-
- mOverviewProxyService = Dependency.get(OverviewProxyService.class);
- mRecentsOnboarding = new RecentsOnboarding(context, mOverviewProxyService);
}
public BarTransitions getBarTransitions() {
@@ -275,6 +301,18 @@
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
+ switch (event.getActionMasked()) {
+ case ACTION_DOWN:
+ int x = (int) event.getX();
+ int y = (int) event.getY();
+ mDownHitTarget = HIT_TARGET_NONE;
+ if (mBackButtonBounds.contains(x, y)) {
+ mDownHitTarget = HIT_TARGET_BACK;
+ } else if (mHomeButtonBounds.contains(x, y)) {
+ mDownHitTarget = HIT_TARGET_HOME;
+ }
+ break;
+ }
return mGestureHelper.onInterceptTouchEvent(event);
}
@@ -286,6 +324,10 @@
return super.onTouchEvent(event);
}
+ public @NavigationBarCompat.HitTarget int getDownHitTarget() {
+ return mDownHitTarget;
+ }
+
public void abortCurrentGesture() {
getHomeButton().abortCurrentGesture();
}
@@ -336,6 +378,19 @@
return getRecentsButton().getVisibility() == View.VISIBLE;
}
+ public boolean isQuickStepSwipeUpEnabled() {
+ return mOverviewProxyService.getProxy() != null
+ && ((mOverviewProxyService.getInteractionFlags()
+ & FLAG_DISABLE_SWIPE_UP) == 0);
+ }
+
+ public boolean isQuickScrubEnabled() {
+ return SystemProperties.getBoolean("persist.quickstep.scrub.enabled", true)
+ && mOverviewProxyService.getProxy() != null && !isRecentsButtonVisible()
+ && ((mOverviewProxyService.getInteractionFlags()
+ & FLAG_DISABLE_QUICK_SCRUB) == 0);
+ }
+
private void updateCarModeIcons(Context ctx) {
mBackCarModeIcon = getDrawable(ctx,
R.drawable.ic_sysbar_back_carmode, R.drawable.ic_sysbar_back_carmode);
@@ -355,14 +410,23 @@
}
if (oldConfig.densityDpi != newConfig.densityDpi
|| oldConfig.getLayoutDirection() != newConfig.getLayoutDirection()) {
- mBackIcon = getDrawable(ctx, R.drawable.ic_sysbar_back, R.drawable.ic_sysbar_back_dark);
+ final boolean quickStepEnabled = isQuickStepSwipeUpEnabled() || isQuickScrubEnabled();
+ mBackIcon = quickStepEnabled
+ ? getDrawable(ctx, R.drawable.ic_sysbar_back_quick_step,
+ R.drawable.ic_sysbar_back_quick_step_dark)
+ : getDrawable(ctx, R.drawable.ic_sysbar_back, R.drawable.ic_sysbar_back_dark);
mBackLandIcon = mBackIcon;
- mBackAltIcon = getDrawable(ctx,
- R.drawable.ic_sysbar_back_ime, R.drawable.ic_sysbar_back_ime_dark);
+ mBackAltIcon = quickStepEnabled
+ ? getDrawable(ctx, R.drawable.ic_sysbar_back_ime_quick_step,
+ R.drawable.ic_sysbar_back_ime_quick_step_dark)
+ : getDrawable(ctx, R.drawable.ic_sysbar_back_ime,
+ R.drawable.ic_sysbar_back_ime_dark);
mBackAltLandIcon = mBackAltIcon;
- mHomeDefaultIcon = getDrawable(ctx,
- R.drawable.ic_sysbar_home, R.drawable.ic_sysbar_home_dark);
+ mHomeDefaultIcon = quickStepEnabled
+ ? getDrawable(ctx, R.drawable.ic_sysbar_home_quick_step,
+ R.drawable.ic_sysbar_home_quick_step_dark)
+ : getDrawable(ctx, R.drawable.ic_sysbar_home, R.drawable.ic_sysbar_home_dark);
mRecentIcon = getDrawable(ctx,
R.drawable.ic_sysbar_recent, R.drawable.ic_sysbar_recent_dark);
mMenuIcon = getDrawable(ctx, R.drawable.ic_sysbar_menu, R.drawable.ic_sysbar_menu_dark);
@@ -462,22 +526,25 @@
getHomeButton().setImageDrawable(mHomeDefaultIcon);
}
- // The Accessibility button always overrides the appearance of the IME switcher
+ // Update IME button visibility, a11y and rotate button always overrides the appearance
final boolean showImeButton =
- !mShowAccessibilityButton && ((hints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN)
- != 0);
+ !mShowAccessibilityButton &&
+ !mShowRotateButton &&
+ ((hints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) != 0);
getImeSwitchButton().setVisibility(showImeButton ? View.VISIBLE : View.INVISIBLE);
getImeSwitchButton().setImageDrawable(mImeIcon);
- // Update menu button in case the IME state has changed.
+ // Update menu button, visibility logic in method
setMenuVisibility(mShowMenu, true);
getMenuButton().setImageDrawable(mMenuIcon);
+ // Update rotate button, visibility altered by a11y button logic
+ getRotateSuggestionButton().setImageDrawable(mRotateSuggestionIcon);
+
+ // Update a11y button, visibility logic in state method
setAccessibilityButtonState(mShowAccessibilityButton, mLongClickableAccessibilityButton);
getAccessibilityButton().setImageDrawable(mAccessibilityIcon);
- getRotateSuggestionButton().setImageDrawable(mRotateSuggestionIcon);
-
setDisabledFlags(mDisabledFlags, true);
mBarTransitions.reapplyDarkIntensity();
@@ -507,9 +574,14 @@
disableBack = false;
disableRecent = false;
}
+
if (mOverviewProxyService.getProxy() != null) {
- // When overview is connected to the launcher service, disable the recents button
- disableRecent = true;
+ // When overview is connected to the launcher service, disable the recents button by
+ // default unless overwritten by interaction flags. Similar with the back button but
+ // shown by default.
+ final int flags = mOverviewProxyService.getInteractionFlags();
+ disableRecent |= (flags & FLAG_SHOW_OVERVIEW_BUTTON) == 0;
+ disableBack |= (flags & FLAG_HIDE_BACK_BUTTON) != 0;
}
ViewGroup navButtons = (ViewGroup) getCurrentView().findViewById(R.id.nav_buttons);
@@ -587,6 +659,11 @@
updateSlippery();
}
+ public void updateStates() {
+ updateSlippery();
+ setDisabledFlags(mDisabledFlags, true);
+ }
+
private void updateSlippery() {
setSlippery(mOverviewProxyService.getProxy() != null && mPanelView.isFullyExpanded());
}
@@ -621,8 +698,10 @@
mShowMenu = show;
- // Only show Menu if IME switcher and Accessibility button not shown.
- final boolean shouldShow = mShowMenu && !mShowAccessibilityButton &&
+ // Only show Menu if IME switcher, rotate and Accessibility buttons are not shown.
+ final boolean shouldShow = mShowMenu &&
+ !mShowAccessibilityButton &&
+ !mShowRotateButton &&
((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) == 0);
getMenuButton().setVisibility(shouldShow ? View.VISIBLE : View.INVISIBLE);
@@ -632,15 +711,96 @@
mShowAccessibilityButton = visible;
mLongClickableAccessibilityButton = longClickable;
if (visible) {
- // Accessibility button overrides Menu and IME switcher buttons.
+ // Accessibility button overrides Menu, IME switcher and rotate buttons.
setMenuVisibility(false, true);
getImeSwitchButton().setVisibility(View.INVISIBLE);
+ setRotateSuggestionButtonState(false, true);
}
getAccessibilityButton().setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
getAccessibilityButton().setLongClickable(longClickable);
}
+ public void setRotateSuggestionButtonState(final boolean visible) {
+ setRotateSuggestionButtonState(visible, false);
+ }
+
+ public void setRotateSuggestionButtonState(final boolean visible, final boolean force) {
+ ButtonDispatcher rotBtn = getRotateSuggestionButton();
+ final boolean currentlyVisible = mShowRotateButton;
+
+ // Rerun a show animation to indicate change but don't rerun a hide animation
+ if (!visible && !currentlyVisible) return;
+
+ View currentView = rotBtn.getCurrentView();
+ if (currentView == null) return;
+
+ KeyButtonDrawable kbd = rotBtn.getImageDrawable();
+ if (kbd == null) return;
+
+ AnimatedVectorDrawable animIcon = null;
+ if (kbd.getDrawable(0) instanceof AnimatedVectorDrawable) {
+ animIcon = (AnimatedVectorDrawable) kbd.getDrawable(0);
+ }
+
+ if (visible) { // Appear and change, cannot force
+ setRotateButtonVisibility(true);
+
+ // Stop any currently running hide animations
+ if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) {
+ mRotateHideAnimator.pause();
+ }
+
+ // Reset the alpha if any has changed due to hide animation
+ currentView.setAlpha(1f);
+
+ // Run the rotate icon's animation if it has one
+ if (animIcon != null) {
+ animIcon.reset();
+ animIcon.start();
+ }
+
+ } else { // Hide
+ if (force) {
+ // If a hide animator is running stop it and instantly make invisible
+ if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) {
+ mRotateHideAnimator.pause();
+ }
+ setRotateButtonVisibility(false);
+ return;
+ }
+
+ // Don't start any new hide animations if one is running
+ if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) return;
+
+ ObjectAnimator fadeOut = ObjectAnimator.ofFloat(currentView, "alpha",
+ 0f);
+ fadeOut.setDuration(BUTTON_FADE_IN_OUT_DURATION_MS);
+ fadeOut.setInterpolator(Interpolators.LINEAR);
+ fadeOut.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ setRotateButtonVisibility(false);
+ }
+ });
+
+ mRotateHideAnimator = fadeOut;
+ fadeOut.start();
+ }
+ }
+
+ private void setRotateButtonVisibility(final boolean visible) {
+ // Never show if a11y is visible
+ final boolean adjVisible = visible && !mShowAccessibilityButton;
+ final int vis = adjVisible ? View.VISIBLE : View.INVISIBLE;
+
+ getRotateSuggestionButton().setVisibility(vis);
+ mShowRotateButton = visible;
+
+ // Hide/restore other button visibility, if necessary
+ setNavigationIconHints(mNavigationIconHints, true);
+ }
+
@Override
public void onFinishInflate() {
mNavigationInflaterView = (NavigationBarInflaterView) findViewById(
@@ -663,9 +823,10 @@
}
public void onOverviewProxyConnectionChanged(boolean isConnected) {
- setSlippery(!isConnected);
- setDisabledFlags(mDisabledFlags, true);
- setUpSwipeUpOnboarding(isConnected);
+ updateStates();
+ setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled());
+ updateIcons(getContext(), Configuration.EMPTY, mConfiguration);
+ setNavigationIconHints(mNavigationIconHints, true);
}
@Override
@@ -677,9 +838,23 @@
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
+ updateButtonLocationOnScreen(getBackButton(), mBackButtonBounds);
+ updateButtonLocationOnScreen(getHomeButton(), mHomeButtonBounds);
mGestureHelper.onLayout(changed, left, top, right, bottom);
}
+ private void updateButtonLocationOnScreen(ButtonDispatcher button, Rect buttonBounds) {
+ View view = button.getCurrentView();
+ if (view == null) {
+ buttonBounds.setEmpty();
+ return;
+ }
+ view.getLocationInWindow(mTmpPosition);
+ buttonBounds.set(mTmpPosition[0], mTmpPosition[1],
+ mTmpPosition[0] + view.getMeasuredWidth(),
+ mTmpPosition[1] + view.getMeasuredHeight());
+ }
+
private void updateRotatedViews() {
mRotatedViews[Surface.ROTATION_0] =
mRotatedViews[Surface.ROTATION_180] = findViewById(R.id.rot0);
@@ -734,6 +909,11 @@
Log.d(TAG, "reorient(): rot=" + mCurrentRotation);
}
+ // Resolve layout direction if not resolved since components changing layout direction such
+ // as changing languages will recreate this view and the direction will be resolved later
+ if (!isLayoutDirectionResolved()) {
+ resolveLayoutDirection();
+ }
updateTaskSwitchHelper();
setNavigationIconHints(mNavigationIconHints, true);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 52d005c..3b129fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -45,7 +45,7 @@
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.WindowInsets;
-import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
import android.widget.FrameLayout;
import com.android.internal.logging.MetricsLogger;
@@ -111,6 +111,7 @@
}
};
private final PowerManager mPowerManager;
+ private final AccessibilityManager mAccessibilityManager;
private KeyguardAffordanceHelper mAffordanceHelper;
private KeyguardUserSwitcher mKeyguardUserSwitcher;
@@ -249,6 +250,8 @@
setWillNotDraw(!DEBUG);
mFalsingManager = FalsingManager.getInstance(context);
mPowerManager = context.getSystemService(PowerManager.class);
+ mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
+ setAccessibilityPaneTitle(determineAccessibilityPaneTitle());
}
public void setStatusBar(StatusBar bar) {
@@ -498,7 +501,8 @@
float shelfSize = shelf.getVisibility() == GONE ? 0
: shelf.getIntrinsicHeight() + notificationPadding;
float availableSpace = mNotificationStackScroller.getHeight() - minPadding - shelfSize
- - Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding);
+ - Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding)
+ - mKeyguardStatusView.getLogoutButtonHeight();
int count = 0;
for (int i = 0; i < mNotificationStackScroller.getChildCount(); i++) {
ExpandableView child = (ExpandableView) mNotificationStackScroller.getChildAt(i);
@@ -661,16 +665,6 @@
}
@Override
- public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
- if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
- event.getText().add(getKeyguardOrLockScreenString());
- mLastAnnouncementWasQuickSettings = false;
- return true;
- }
- return super.dispatchPopulateAccessibilityEventInternal(event);
- }
-
- @Override
public boolean onInterceptTouchEvent(MotionEvent event) {
if (mBlockTouches || mQsFullyExpanded && mQs.onInterceptTouchEvent(event)) {
return false;
@@ -1300,10 +1294,6 @@
setQsExpanded(true);
} else if (height <= mQsMinExpansionHeight && mQsExpanded) {
setQsExpanded(false);
- if (mLastAnnouncementWasQuickSettings && !mTracking && !isCollapsing()) {
- announceForAccessibility(getKeyguardOrLockScreenString());
- mLastAnnouncementWasQuickSettings = false;
- }
}
mQsExpansionHeight = height;
updateQsExpansion();
@@ -1329,13 +1319,10 @@
updateClock(mClockPositionResult.clockAlpha, mClockPositionResult.clockScale);
}
- // Upon initialisation when we are not layouted yet we don't want to announce that we are
- // fully expanded, hence the != 0.0f check.
- if (height != 0.0f && mQsFullyExpanded && !mLastAnnouncementWasQuickSettings) {
- announceForAccessibility(getContext().getString(
- R.string.accessibility_desc_quick_settings));
- mLastAnnouncementWasQuickSettings = true;
+ if (mAccessibilityManager.isEnabled()) {
+ setAccessibilityPaneTitle(determineAccessibilityPaneTitle());
}
+
if (mQsFullyExpanded && mFalsingManager.shouldEnforceBouncer()) {
mStatusBar.executeRunnableDismissingKeyguard(null, null /* cancelAction */,
false /* dismissShade */, true /* afterKeyguardGone */, false /* deferred */);
@@ -1350,9 +1337,13 @@
mQs.setQsExpansion(getQsExpansionFraction(), getHeaderTranslation());
}
- private String getKeyguardOrLockScreenString() {
+ private String determineAccessibilityPaneTitle() {
if (mQs != null && mQs.isCustomizing()) {
return getContext().getString(R.string.accessibility_desc_quick_settings_edit);
+ } else if (mQsExpansionHeight != 0.0f && mQsFullyExpanded) {
+ // Upon initialisation when we are not layouted yet we don't want to announce that we
+ // are fully expanded, hence the != 0.0f check.
+ return getContext().getString(R.string.accessibility_desc_quick_settings);
} else if (mStatusBarState == StatusBarState.KEYGUARD) {
return getContext().getString(R.string.accessibility_desc_lock_screen);
} else {
@@ -1880,6 +1871,9 @@
requestScrollerTopPaddingUpdate(false /* animate */);
requestPanelHeightUpdate();
}
+ if (mAccessibilityManager.isEnabled()) {
+ setAccessibilityPaneTitle(determineAccessibilityPaneTitle());
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 6444cc8..747a551 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -575,7 +575,7 @@
Intent browserIntent = getTaskIntent(taskId, userId);
Notification.Builder builder = new Notification.Builder(mContext, NotificationChannels.GENERAL);
- if (browserIntent != null) {
+ if (browserIntent != null && browserIntent.isWebIntent()) {
// Make sure that this doesn't resolve back to an instant app
browserIntent.setComponent(null)
.setPackage(null)
@@ -597,8 +597,9 @@
.addCategory("unique:" + System.currentTimeMillis())
.putExtra(Intent.EXTRA_PACKAGE_NAME, appInfo.packageName)
.putExtra(Intent.EXTRA_VERSION_CODE, (int) (appInfo.versionCode & 0x7fffffff))
- .putExtra(Intent.EXTRA_VERSION_CODE, appInfo.versionCode)
- .putExtra(Intent.EXTRA_EPHEMERAL_FAILURE, pendingIntent);
+ .putExtra(Intent.EXTRA_LONG_VERSION_CODE, appInfo.versionCode)
+ .putExtra(Intent.EXTRA_EPHEMERAL_FAILURE, pendingIntent)
+ .putExtra(Intent.EXTRA_INSTANT_APP_FAILURE, pendingIntent);
PendingIntent webPendingIntent = PendingIntent.getActivity(mContext, 0, goToWebIntent, 0);
Action webAction = new Notification.Action.Builder(null, mContext.getString(R.string.go_to_web),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
index dc0835e..0bf01b0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
@@ -29,15 +29,12 @@
import android.graphics.Rect;
import android.os.Handler;
import android.os.RemoteException;
-import android.os.SystemProperties;
import android.util.Log;
import android.util.Slog;
-import android.view.Display;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
-import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
@@ -53,6 +50,7 @@
import static android.view.WindowManagerPolicyConstants.NAV_BAR_BOTTOM;
import static com.android.systemui.OverviewProxyService.DEBUG_OVERVIEW_PROXY;
import static com.android.systemui.OverviewProxyService.TAG_OPS;
+import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_HOME;
/**
* Class to detect gestures on the navigation bar and implement quick scrub and switch.
@@ -88,11 +86,11 @@
private int mLightTrackColor;
private int mDarkTrackColor;
private float mDarkIntensity;
+ private View mHomeButtonView;
private final Handler mHandler = new Handler();
private final Interpolator mQuickScrubEndInterpolator = new DecelerateInterpolator();
private final Rect mTrackRect = new Rect();
- private final Rect mHomeButtonRect = new Rect();
private final Paint mTrackPaint = new Paint();
private final int mScrollTouchSlop;
private final OverviewProxyService mOverviewEventSender;
@@ -114,11 +112,10 @@
if (!mQuickScrubActive) {
pos = mDragPositive ? Math.min((int) mTranslation, pos) : Math.max((int) mTranslation, pos);
}
- final View homeView = mNavigationBarView.getHomeButton().getCurrentView();
if (mIsVertical) {
- homeView.setTranslationY(pos);
+ mHomeButtonView.setTranslationY(pos);
} else {
- homeView.setTranslationX(pos);
+ mHomeButtonView.setTranslationX(pos);
}
};
@@ -126,6 +123,7 @@
@Override
public void onAnimationEnd(Animator animation) {
mNavigationBarView.getHomeButton().setClickable(true);
+ mHomeButtonView = null;
mQuickScrubActive = false;
mTranslation = 0;
}
@@ -137,8 +135,9 @@
new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velX, float velY) {
- if (!isQuickScrubEnabled() || mQuickScrubActive || !mAllowQuickSwitch ||
- !mHomeButtonRect.contains(mTouchDownX, mTouchDownY)) {
+ if (!mNavigationBarView.isQuickScrubEnabled() || mQuickScrubActive
+ || !mAllowQuickSwitch
+ || mNavigationBarView.getDownHitTarget() != HIT_TARGET_HOME) {
return false;
}
float velocityX = mIsRTL ? -velX : velX;
@@ -195,9 +194,8 @@
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
- final IOverviewProxy overviewProxy = mOverviewEventSender.getProxy();
final ButtonDispatcher homeButton = mNavigationBarView.getHomeButton();
- if (overviewProxy == null) {
+ if (!mNavigationBarView.isQuickScrubEnabled()) {
homeButton.setDelayTouchFeedback(false);
return false;
}
@@ -226,7 +224,9 @@
case MotionEvent.ACTION_DOWN: {
int x = (int) event.getX();
int y = (int) event.getY();
- if (isQuickScrubEnabled() && mHomeButtonRect.contains(x, y)) {
+ mHomeButtonView = homeButton.getCurrentView();
+ if (mNavigationBarView.isQuickScrubEnabled()
+ && mNavigationBarView.getDownHitTarget() == HIT_TARGET_HOME) {
mTouchDownX = x;
mTouchDownY = y;
homeButton.setDelayTouchFeedback(true);
@@ -293,7 +293,7 @@
: Utilities.clamp(offset - mDownOffset, 0, trackSize);
if (mQuickScrubActive) {
try {
- overviewProxy.onQuickScrubProgress(scrubFraction);
+ mOverviewEventSender.getProxy().onQuickScrubProgress(scrubFraction);
if (DEBUG_OVERVIEW_PROXY) {
Log.d(TAG_OPS, "Quick Scrub Progress:" + scrubFraction);
}
@@ -304,9 +304,9 @@
mTranslation /= SWITCH_STICKINESS;
}
if (mIsVertical) {
- homeButton.getCurrentView().setTranslationY(mTranslation);
+ mHomeButtonView.setTranslationY(mTranslation);
} else {
- homeButton.getCurrentView().setTranslationX(mTranslation);
+ mHomeButtonView.setTranslationX(mTranslation);
}
}
}
@@ -314,7 +314,7 @@
}
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
- endQuickScrub();
+ endQuickScrub(true /* animate */);
break;
}
return mDraggingActive || mQuickScrubActive;
@@ -346,17 +346,6 @@
x2 = x1 + width / 2 - mTrackPadding;
}
mTrackRect.set(x1, y1, x2, y2);
-
- // Get the touch rect of the home button location
- View homeView = mNavigationBarView.getHomeButton().getCurrentView();
- if (homeView != null) {
- int[] globalHomePos = homeView.getLocationOnScreen();
- int[] globalNavBarPos = mNavigationBarView.getLocationOnScreen();
- int homeX = globalHomePos[0] - globalNavBarPos[0];
- int homeY = globalHomePos[1] - globalNavBarPos[1];
- mHomeButtonRect.set(homeX, homeY, homeX + homeView.getMeasuredWidth(),
- homeY + homeView.getMeasuredHeight());
- }
}
@Override
@@ -367,6 +356,11 @@
@Override
public void setBarState(boolean isVertical, boolean isRTL) {
+ final boolean changed = (mIsVertical != isVertical) || (mIsRTL != isRTL);
+ if (changed) {
+ // End quickscrub if the state changes mid-transition
+ endQuickScrub(false /* animate */);
+ }
mIsVertical = isVertical;
mIsRTL = isRTL;
try {
@@ -380,10 +374,6 @@
}
}
- boolean isQuickScrubEnabled() {
- return SystemProperties.getBoolean("persist.quickstep.scrub.enabled", false);
- }
-
private void startQuickScrub() {
if (!mQuickScrubActive) {
mQuickScrubActive = true;
@@ -402,7 +392,7 @@
}
}
- private void endQuickScrub() {
+ private void endQuickScrub(boolean animate) {
mHandler.removeCallbacks(mLongPressRunnable);
if (mDraggingActive || mQuickScrubActive) {
mButtonAnimator.setIntValues((int) mTranslation, 0);
@@ -416,6 +406,9 @@
} catch (RemoteException e) {
Log.e(TAG, "Failed to send end of quick scrub.", e);
}
+ if (!animate) {
+ mQuickScrubEndAnimator.end();
+ }
}
mDraggingActive = false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 1438763..2b50853 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -166,6 +166,7 @@
private boolean mScreenBlankingCallbackCalled;
private Callback mCallback;
private boolean mWallpaperSupportsAmbientMode;
+ private boolean mScreenOn;
// Scrim blanking callbacks
private Choreographer.FrameCallback mPendingFrameCallback;
@@ -785,10 +786,11 @@
// Setting power states can happen after we push out the frame. Make sure we
// stay fully opaque until the power state request reaches the lower levels.
+ final int delay = mScreenOn ? 16 : 500;
if (DEBUG) {
- Log.d(TAG, "Waiting for the screen to turn on...");
+ Log.d(TAG, "Fading out scrims with delay: " + delay);
}
- getHandler().postDelayed(mBlankingTransitionRunnable, 500);
+ getHandler().postDelayed(mBlankingTransitionRunnable, delay);
};
doOnTheNextFrame(mPendingFrameCallback);
}
@@ -904,6 +906,7 @@
* Interrupts blanking transitions once the display notifies that it's already on.
*/
public void onScreenTurnedOn() {
+ mScreenOn = true;
final Handler handler = getHandler();
if (handler.hasCallbacks(mBlankingTransitionRunnable)) {
if (DEBUG) {
@@ -914,6 +917,10 @@
}
}
+ public void onScreenTurnedOff() {
+ mScreenOn = false;
+ }
+
public interface Callback {
default void onStart() {
}
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 458518c..24920cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -111,6 +111,7 @@
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
+import android.view.RemoteAnimationAdapter;
import android.view.ThreadedRenderer;
import android.view.View;
import android.view.ViewGroup;
@@ -2849,7 +2850,7 @@
Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
int result = ActivityManager.START_CANCELED;
ActivityOptions options = new ActivityOptions(getActivityOptions(
- null /* sourceNotification */));
+ null /* remoteAnimation */));
options.setDisallowEnterPictureInPictureWhileLaunching(
disallowEnterPictureInPictureWhileLaunching);
if (intent == KeyguardBottomAreaView.INSECURE_CAMERA_INTENT) {
@@ -4413,6 +4414,7 @@
@Override
public void onScreenTurnedOff() {
mFalsingManager.onScreenOff();
+ mScrimController.onScreenTurnedOff();
// If we pulse in from AOD, we turn the screen off first. However, updatingIsKeyguard
// in that case destroys the HeadsUpManager state, so don't do it in that case.
if (!isPulsing()) {
@@ -5000,11 +5002,15 @@
fillInIntent = new Intent().putExtra(Notification.EXTRA_REMOTE_INPUT_DRAFT,
remoteInputText.toString());
}
+ RemoteAnimationAdapter adapter = mActivityLaunchAnimator.getLaunchAnimation(
+ row);
try {
+ ActivityManager.getService().registerRemoteAnimationForNextActivityStart(
+ intent.getCreatorPackage(), adapter);
launchResult = intent.sendAndReturnResult(mContext, 0, fillInIntent, null,
- null, null, getActivityOptions(row));
+ null, null, getActivityOptions(adapter));
mActivityLaunchAnimator.setLaunchResult(launchResult);
- } catch (PendingIntent.CanceledException e) {
+ } catch (RemoteException | PendingIntent.CanceledException e) {
// the stack trace isn't very helpful here.
// Just log the exception message.
Log.w(TAG, "Sending contentIntent failed: " + e);
@@ -5164,7 +5170,8 @@
AsyncTask.execute(() -> {
int launchResult = TaskStackBuilder.create(mContext)
.addNextIntentWithParentStack(intent)
- .startActivities(getActivityOptions(row),
+ .startActivities(getActivityOptions(
+ mActivityLaunchAnimator.getLaunchAnimation(row)),
new UserHandle(UserHandle.getUserId(appUid)));
mActivityLaunchAnimator.setLaunchResult(launchResult);
if (shouldCollapse()) {
@@ -5299,7 +5306,7 @@
}
try {
intent.send(null, 0, null, null, null, null, getActivityOptions(
- null /* sourceNotification */));
+ null /* animationAdapter */));
} catch (PendingIntent.CanceledException e) {
// the stack trace isn't very helpful here.
// Just log the exception message.
@@ -5327,10 +5334,10 @@
return true;
}
- protected Bundle getActivityOptions(ExpandableNotificationRow sourceNotification) {
+ protected Bundle getActivityOptions(@Nullable RemoteAnimationAdapter animationAdapter) {
ActivityOptions options;
- if (sourceNotification != null) {
- options = mActivityLaunchAnimator.getLaunchAnimation(sourceNotification);
+ if (animationAdapter != null) {
+ options = ActivityOptions.makeRemoteAnimation(animationAdapter);
} else {
options = ActivityOptions.makeBasic();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
index c30f633..948f524 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -106,6 +106,7 @@
mLp.gravity = Gravity.TOP;
mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
mLp.setTitle("StatusBar");
+ mLp.accessibilityTitle = mContext.getString(R.string.status_bar);
mLp.packageName = mContext.getPackageName();
mStatusBarView = statusBarView;
mBarHeight = barHeight;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
index 1da50ad..503a1b4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
@@ -36,6 +36,7 @@
public class StatusIconContainer extends AlphaOptimizedLinearLayout {
private static final String TAG = "StatusIconContainer";
+ private static final boolean DEBUG = false;
private static final int MAX_ICONS = 5;
private static final int MAX_DOTS = 3;
@@ -94,7 +95,7 @@
int childCount = getChildCount();
// Underflow === don't show content until that index
int firstUnderflowIndex = -1;
- android.util.Log.d(TAG, "calculateIconTransitions: start=" + translationX);
+ if (DEBUG) android.util.Log.d(TAG, "calculateIconTransitions: start=" + translationX);
//TODO: Dots
for (int i = childCount - 1; i >= 0; i--) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 9d1c1e8..98bebec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -52,6 +52,7 @@
import com.android.systemui.OverviewProxyService;
import com.android.systemui.R;
import com.android.systemui.plugins.statusbar.phone.NavBarButtonProvider.ButtonInterface;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK;
@@ -269,11 +270,7 @@
if (doIt) {
// If there was a pending remote recents animation, then we need to
// cancel the animation now before we handle the button itself
- try {
- ActivityManager.getService().cancelRecentsAnimation();
- } catch (RemoteException e) {
- Log.e(TAG, "Could not cancel recents animation", e);
- }
+ ActivityManagerWrapper.getInstance().cancelRecentsAnimation();
sendEvent(KeyEvent.ACTION_UP, 0);
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index 8516278..f0854ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -35,8 +35,8 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.telephony.cdma.EriInfo;
+import com.android.settingslib.graph.SignalDrawable;
import com.android.systemui.R;
-import com.android.systemui.statusbar.phone.SignalDrawable;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
import com.android.systemui.statusbar.policy.NetworkControllerImpl.Config;
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java b/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java
index 45abd45..eb0c89b 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java
@@ -18,7 +18,7 @@
import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.KEY_CODE_END;
import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.KEY_CODE_START;
import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.KEY_IMAGE_DELIM;
-import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.MENU_IME;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.MENU_IME_ROTATE;
import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.NAVSPACE;
import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.NAV_BAR_LEFT;
import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.NAV_BAR_RIGHT;
@@ -29,24 +29,14 @@
import android.annotation.Nullable;
import android.app.AlertDialog;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnClickListener;
-import android.content.res.Resources;
import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Paint.FontMetricsInt;
-import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.os.Handler;
-import android.support.v14.preference.PreferenceFragment;
-import android.support.v7.preference.DropDownPreference;
import android.support.v7.preference.ListPreference;
import android.support.v7.preference.Preference;
import android.support.v7.preference.Preference.OnPreferenceChangeListener;
-import android.support.v7.preference.Preference.OnPreferenceClickListener;
-import android.support.v7.preference.PreferenceCategory;
import android.text.SpannableStringBuilder;
import android.text.style.ImageSpan;
import android.util.Log;
@@ -56,7 +46,6 @@
import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.statusbar.phone.NavigationBarInflaterView;
import com.android.systemui.tuner.TunerService.Tunable;
import java.util.ArrayList;
@@ -100,7 +89,7 @@
addPreferencesFromResource(R.xml.nav_bar_tuner);
bindLayout((ListPreference) findPreference(LAYOUT));
bindButton(NAV_BAR_LEFT, NAVSPACE, LEFT);
- bindButton(NAV_BAR_RIGHT, MENU_IME, RIGHT);
+ bindButton(NAV_BAR_RIGHT, MENU_IME_ROTATE, RIGHT);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 8881ee9..1e8e98c 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -178,7 +178,6 @@
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
- mWindow.setTitle(VolumeDialogImpl.class.getSimpleName());
mWindow.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
mWindow.setWindowAnimations(com.android.internal.R.style.Animation_Toast);
final WindowManager.LayoutParams lp = mWindow.getAttributes();
@@ -410,6 +409,7 @@
final boolean hasVibrator = mController.hasVibrator();
if (mState.ringerModeInternal == AudioManager.RINGER_MODE_NORMAL) {
if (hasVibrator) {
+ mController.vibrate();
mController.setRingerMode(AudioManager.RINGER_MODE_VIBRATE, false);
} else {
mController.setRingerMode(AudioManager.RINGER_MODE_SILENT, false);
@@ -491,15 +491,6 @@
}, 50))
.start();
- if (mAccessibilityMgr.isEnabled()) {
- AccessibilityEvent event =
- AccessibilityEvent.obtain(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
- event.setPackageName(mContext.getPackageName());
- event.setClassName(CustomDialog.class.getSuperclass().getName());
- event.getText().add(mContext.getString(
- R.string.volume_dialog_accessibility_dismissed_message));
- mAccessibilityMgr.sendAccessibilityEvent(event);
- }
Events.writeEvent(mContext, Events.EVENT_DISMISS_DIALOG, reason);
mController.notifyVisible(false);
synchronized (mSafetyWarningLock) {
@@ -670,6 +661,8 @@
updateVolumeRowH(row);
}
updateRingerH();
+ mWindow.setTitle(mContext.getString(R.string.volume_dialog_title,
+ getStreamLabelH(getActiveRow().ss)));
}
private void updateVolumeRowH(VolumeRow row) {
@@ -1065,22 +1058,6 @@
}
return false;
}
-
- @Override
- public boolean dispatchPopulateAccessibilityEvent(@NonNull AccessibilityEvent event) {
- event.setClassName(getClass().getSuperclass().getName());
- event.setPackageName(mContext.getPackageName());
-
- if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
- if (mShowing) {
- event.getText().add(mContext.getString(
- R.string.volume_dialog_accessibility_shown_message,
- getStreamLabelH(getActiveRow().ss)));
- return true;
- }
- }
- return false;
- }
}
private final class VolumeSeekBarChangeListener implements OnSeekBarChangeListener {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
index 1c9c794..6764634 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
@@ -37,6 +37,7 @@
import android.content.Intent;
import android.metrics.LogMaker;
import android.support.test.filters.SmallTest;
+import android.support.test.InstrumentationRegistry;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
@@ -73,6 +74,7 @@
mMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class);
mHost = mock(QSTileHost.class);
when(mHost.indexOf(spec)).thenReturn(POSITION);
+ when(mHost.getContext()).thenReturn(mContext.getBaseContext());
mTile = spy(new TileImpl(mHost));
mTile.mHandler = mTile.new H(mTestableLooper.getLooper());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
index 8e8b3e0..b8d9b19 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
@@ -16,7 +16,9 @@
package com.android.systemui.statusbar;
+import static android.app.NotificationChannel.USER_LOCKED_IMPORTANCE;
import static android.app.NotificationManager.IMPORTANCE_LOW;
+import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
import static android.print.PrintManager.PRINT_SPOOLER_PACKAGE_NAME;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
@@ -95,6 +97,7 @@
final LayoutInflater layoutInflater = LayoutInflater.from(mContext);
mNotificationInfo = (NotificationInfo) layoutInflater.inflate(R.layout.notification_info,
null);
+ mNotificationInfo.setGutsParent(mock(NotificationGuts.class));
// PackageManager must return a packageInfo and applicationInfo.
final PackageInfo packageInfo = new PackageInfo();
@@ -323,24 +326,27 @@
@Test
public void testHandleCloseControls_DoesNotUpdateNotificationChannelIfUnchanged()
throws Exception {
+ int originalImportance = mNotificationChannel.getImportance();
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
mNotificationInfo.handleCloseControls(true, false);
- verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
+ verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
anyString(), eq(TEST_UID), any());
+ assertEquals(originalImportance, mNotificationChannel.getImportance());
}
@Test
public void testHandleCloseControls_DoesNotUpdateNotificationChannelIfUnspecified()
throws Exception {
- mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_UNSPECIFIED);
+ mNotificationChannel.setImportance(IMPORTANCE_UNSPECIFIED);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
mNotificationInfo.handleCloseControls(true, false);
- verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
+ verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
anyString(), eq(TEST_UID), any());
+ assertEquals(IMPORTANCE_UNSPECIFIED, mNotificationChannel.getImportance());
}
@Test
@@ -370,16 +376,30 @@
verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
anyString(), eq(TEST_UID), updated.capture());
assertTrue((updated.getValue().getUserLockedFields()
- & NotificationChannel.USER_LOCKED_IMPORTANCE) != 0);
+ & USER_LOCKED_IMPORTANCE) != 0);
}
@Test
- public void testBlockUndoDoesNotCallUpdateNotificationChannel() throws Exception {
+ public void testKeepUpdatesNotificationChannel() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null,
- Collections.singleton(TEST_PACKAGE_NAME));
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
+ mNotificationInfo.handleCloseControls(true, false);
+
+ ArgumentCaptor<NotificationChannel> updated =
+ ArgumentCaptor.forClass(NotificationChannel.class);
+ verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
+ anyString(), eq(TEST_UID), updated.capture());
+ assertTrue(0 != (mNotificationChannel.getUserLockedFields() & USER_LOCKED_IMPORTANCE));
+ assertEquals(IMPORTANCE_LOW, mNotificationChannel.getImportance());
+ }
+
+ @Test
+ public void testBlockUndoDoesNotBlockNotificationChannel() throws Exception {
+ mNotificationChannel.setImportance(IMPORTANCE_LOW);
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, null);
mNotificationInfo.findViewById(R.id.block).performClick();
waitForUndoButton();
@@ -389,8 +409,9 @@
ArgumentCaptor<NotificationChannel> updated =
ArgumentCaptor.forClass(NotificationChannel.class);
- verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
+ verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
anyString(), eq(TEST_UID), updated.capture());
+ assertTrue(0 != (mNotificationChannel.getUserLockedFields() & USER_LOCKED_IMPORTANCE));
assertEquals(IMPORTANCE_LOW, mNotificationChannel.getImportance());
}
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 f685b1f..8aab837 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
@@ -43,9 +43,9 @@
import android.util.Log;
import com.android.internal.telephony.cdma.EriInfo;
+import com.android.settingslib.graph.SignalDrawable;
import com.android.settingslib.net.DataUsageController;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.phone.SignalDrawable;
import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
index 3ad107c..550f4a7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
@@ -30,9 +30,9 @@
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.TelephonyIntents;
+import com.android.settingslib.graph.SignalDrawable;
import com.android.settingslib.net.DataUsageController;
import com.android.systemui.R;
-import com.android.systemui.statusbar.phone.SignalDrawable;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index ae5e133..320c37f 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -5213,6 +5213,50 @@
// OS: P
ACTION_OUTPUT_CHOOSER_DISCONNECT = 1297;
+ // OPEN: TV Settings > Home theater control
+ // OS: P
+ SETTINGS_TV_HOME_THEATER_CONTROL_CATEGORY = 1298;
+
+ // OPEN: TV Settings > TV Inputs (Inputs & Devices)
+ // OS: P
+ SETTINGS_TV_INPUTS_CATEGORY = 1299;
+
+ // OPEN: TV Settings > Device
+ // OS: P
+ SETTINGS_TV_DEVICE_CATEGORY = 1300;
+
+ // OPEN: TV Settings > Network > Proxy settings
+ // OS: P
+ DIALOG_TV_NETWORK_PROXY = 1301;
+
+ // Events for battery saver turning on/off and/or the interactive state changes.
+ // OS: P
+ BATTERY_SAVER = 1302;
+
+ // Device interactive state -- i.e. the screen ON (=1) or OFF (=1)
+ // OS: P
+ FIELD_INTERACTIVE = 1303;
+
+ // Time spent in milliseconds in the current mode.
+ // OS: P
+ FIELD_DURATION_MILLIS = 1304;
+
+ // Battery level in uA (0 - ~3,000,000 depending on device) when the current "mode" started.
+ // OS: P
+ FIELD_START_BATTERY_UA = 1305;
+
+ // Battery level in uA (0 - ~3,000,000 depending on device) when this event was created.
+ // OS: P
+ FIELD_END_BATTERY_UA = 1306;
+
+ // Battery level in % (0-100) when the current "mode" started.
+ // OS: P
+ FIELD_START_BATTERY_PERCENT = 1307;
+
+ // Battery level in % (0-100) when this event was created.
+ // OS: P
+ FIELD_END_BATTERY_PERCENT = 1308;
+
// ---- End P Constants, all P constants go above this line ----
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto
index 08fdb97..608970f 100644
--- a/proto/src/system_messages.proto
+++ b/proto/src/system_messages.proto
@@ -204,6 +204,10 @@
// Package: android
NOTE_USB_TETHER = 47;
+ // Inform that DND settings have changed on OS upgrade
+ // Package: android
+ NOTE_ZEN_UPGRADE = 48;
+
// ADD_NEW_IDS_ABOVE_THIS_LINE
// Legacy IDs with arbitrary values appear below
// Legacy IDs existed as stable non-conflicting constants prior to the O release
@@ -253,6 +257,7 @@
// Notify the user about public volume state changes..
// Package: com.android.systemui
+
NOTE_STORAGE_PUBLIC = 0x53505542; // 1397773634
// Notify the user about private volume state changes.
diff --git a/rs/OWNERS b/rs/OWNERS
new file mode 100644
index 0000000..61853d3
--- /dev/null
+++ b/rs/OWNERS
@@ -0,0 +1,5 @@
+butlermichael@google.com
+dgross@google.com
+jeanluc@google.com
+miaowang@google.com
+yangni@google.com
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
index c36bb6d..5b5d18f 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
@@ -446,8 +446,10 @@
mMagnificationRegion.getBounds(viewport);
final MagnificationSpec spec = mCurrentMagnificationSpec;
final float oldScale = spec.scale;
- final float oldCenterX = (viewport.width() / 2.0f - spec.offsetX) / oldScale;
- final float oldCenterY = (viewport.height() / 2.0f - spec.offsetY) / oldScale;
+ final float oldCenterX
+ = (viewport.width() / 2.0f - spec.offsetX + viewport.left) / oldScale;
+ final float oldCenterY
+ = (viewport.height() / 2.0f - spec.offsetY + viewport.top) / oldScale;
final float normPivotX = (pivotX - spec.offsetX) / oldScale;
final float normPivotY = (pivotY - spec.offsetY) / oldScale;
final float offsetX = (oldCenterX - normPivotX) * (oldScale / scale);
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
index 52ab85c..6c6dd5b 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
@@ -402,9 +402,9 @@
com.android.internal.R.dimen.config_screen_magnification_scaling_threshold,
scaleValue, false);
mScalingThreshold = scaleValue.getFloat();
- mScaleGestureDetector = new ScaleGestureDetector(context, this);
+ mScaleGestureDetector = new ScaleGestureDetector(context, this, Handler.getMain());
mScaleGestureDetector.setQuickScaleEnabled(false);
- mScrollGestureDetector = new GestureDetector(context, this);
+ mScrollGestureDetector = new GestureDetector(context, this, Handler.getMain());
}
@Override
@@ -638,7 +638,7 @@
@VisibleForTesting boolean mShortcutTriggered;
- @VisibleForTesting Handler mHandler = new Handler(this);
+ @VisibleForTesting Handler mHandler = new Handler(Looper.getMainLooper(), this);
public DetectingState(Context context) {
mLongTapMinDelay = ViewConfiguration.getLongPressTimeout();
@@ -654,7 +654,9 @@
final int type = message.what;
switch (type) {
case MESSAGE_ON_TRIPLE_TAP_AND_HOLD: {
- onTripleTapAndHold(/* down */ (MotionEvent) message.obj);
+ MotionEvent down = (MotionEvent) message.obj;
+ transitionToViewportDraggingStateAndClear(down);
+ down.recycle();
}
break;
case MESSAGE_TRANSITION_TO_DELEGATING_STATE: {
@@ -720,8 +722,7 @@
// over insta-delegating on 3tap&swipe
// (which is a rare combo to be used aside from magnification)
if (isMultiTapTriggered(2 /* taps */)) {
- transitionTo(mViewportDraggingState);
- clear();
+ transitionToViewportDraggingStateAndClear(event);
} else {
transitionToDelegatingStateAndClear();
}
@@ -806,7 +807,8 @@
/** -> {@link ViewportDraggingState} */
public void afterLongTapTimeoutTransitionToDraggingState(MotionEvent event) {
mHandler.sendMessageDelayed(
- mHandler.obtainMessage(MESSAGE_ON_TRIPLE_TAP_AND_HOLD, event),
+ mHandler.obtainMessage(MESSAGE_ON_TRIPLE_TAP_AND_HOLD,
+ MotionEvent.obtain(event)),
ViewConfiguration.getLongPressTimeout());
}
@@ -890,7 +892,7 @@
}
}
- void onTripleTapAndHold(MotionEvent down) {
+ void transitionToViewportDraggingStateAndClear(MotionEvent down) {
if (DEBUG_DETECTING) Slog.i(LOG_TAG, "onTripleTapAndHold()");
clear();
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index d5a722b..4b3abea 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -24,7 +24,6 @@
import static com.android.server.autofill.Helper.sPartitionMaxCount;
import static com.android.server.autofill.Helper.sVerbose;
-import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -56,7 +55,12 @@
import android.provider.Settings;
import android.service.autofill.FillEventHistory;
import android.service.autofill.UserData;
+import android.text.TextUtils;
+import android.text.TextUtils.SimpleStringSplitter;
+import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.LocalLog;
+import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -84,6 +88,7 @@
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
+import java.util.Set;
/**
* Entry point service for autofill management.
@@ -98,6 +103,8 @@
static final String RECEIVER_BUNDLE_EXTRA_SESSIONS = "sessions";
+ private static final char COMPAT_PACKAGE_DELIMITER = ':';
+
private final Context mContext;
private final AutoFillUI mUi;
@@ -123,6 +130,9 @@
private final LocalLog mUiLatencyHistory = new LocalLog(20);
private final LocalLog mWtfHistory = new LocalLog(50);
+ private final AutofillCompatState mAutofillCompatState = new AutofillCompatState();
+ private final LocalService mLocalService = new LocalService();
+
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -271,7 +281,7 @@
@Override
public void onStart() {
publishBinderService(AUTOFILL_MANAGER_SERVICE, new AutoFillManagerServiceStub());
- publishLocalService(AutofillManagerInternal.class, new LocalService());
+ publishLocalService(AutofillManagerInternal.class, mLocalService);
}
@Override
@@ -317,6 +327,11 @@
mUiLatencyHistory, mWtfHistory, resolvedUserId, mUi,
mDisabledUsers.get(resolvedUserId));
mServicesCache.put(userId, service);
+ final ArrayMap<String, Pair<Long, String>> compatPackages =
+ service.getCompatibilityPackagesLocked();
+ if (compatPackages != null) {
+ addCompatibilityModeRequests(compatPackages, userId);
+ }
}
return service;
}
@@ -482,6 +497,7 @@
if (service != null) {
mServicesCache.delete(userId);
service.destroyLocked();
+ mAutofillCompatState.removeCompatibilityModeRequests(userId);
}
}
@@ -498,18 +514,60 @@
*/
@GuardedBy("mLock")
private void updateCachedServiceLocked(int userId, boolean disabled) {
- AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
+ AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
if (service != null) {
service.destroySessionsLocked();
service.updateLocked(disabled);
if (!service.isEnabledLocked()) {
removeCachedServiceLocked(userId);
+ } else {
+ final ArrayMap<String, Pair<Long, String>> compatPackages =
+ service.getCompatibilityPackagesLocked();
+ if (compatPackages != null) {
+ addCompatibilityModeRequests(compatPackages, userId);
+ }
}
}
}
- private final class LocalService extends AutofillManagerInternal {
+ private void addCompatibilityModeRequests(
+ @NonNull ArrayMap<String, Pair<Long, String>> compatPackages, int userId) {
+ final Set<String> whiteListedPackages = Build.IS_ENG ? null
+ : getWhitelistedCompatModePackages();
+ final int compatPackageCount = compatPackages.size();
+ for (int i = 0; i < compatPackageCount; i++) {
+ final String packageName = compatPackages.keyAt(i);
+ if (!Build.IS_ENG && (whiteListedPackages == null
+ || !whiteListedPackages.contains(packageName))) {
+ Slog.w(TAG, "Ignoring not whitelisted compat package " + packageName);
+ continue;
+ }
+ final Long maxVersionCode = compatPackages.valueAt(i).first;
+ if (maxVersionCode != null) {
+ mAutofillCompatState.addCompatibilityModeRequest(packageName,
+ maxVersionCode, userId);
+ }
+ }
+ }
+ private @Nullable Set<String> getWhitelistedCompatModePackages() {
+ final String compatPackagesSetting = Settings.Global.getString(
+ mContext.getContentResolver(),
+ Settings.Global.AUTOFILL_COMPAT_ALLOWED_PACKAGES);
+ if (TextUtils.isEmpty(compatPackagesSetting)) {
+ return null;
+ }
+ final Set<String> compatPackages = new ArraySet<>();
+ final SimpleStringSplitter splitter = new SimpleStringSplitter(
+ COMPAT_PACKAGE_DELIMITER);
+ splitter.setString(compatPackagesSetting);
+ while (splitter.hasNext()) {
+ compatPackages.add(splitter.next());
+ }
+ return compatPackages;
+ }
+
+ private final class LocalService extends AutofillManagerInternal {
@Override
public void onBackKeyPressed() {
if (sDebug) Slog.d(TAG, "onBackKeyPressed()");
@@ -519,13 +577,59 @@
@Override
public boolean isCompatibilityModeRequested(@NonNull String packageName,
long versionCode, @UserIdInt int userId) {
+ return mAutofillCompatState.isCompatibilityModeRequested(
+ packageName, versionCode, userId);
+ }
+ }
+
+ private static class AutofillCompatState {
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private SparseArray<ArrayMap<String, Long>> mUserSpecs;
+
+ boolean isCompatibilityModeRequested(@NonNull String packageName,
+ long versionCode, @UserIdInt int userId) {
synchronized (mLock) {
- final AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
- if (service != null) {
- return service.isCompatibilityModeRequestedLocked(packageName, versionCode);
+ if (mUserSpecs == null) {
+ return false;
+ }
+ final ArrayMap<String, Long> userSpec = mUserSpecs.get(userId);
+ if (userSpec == null) {
+ return false;
+ }
+ final Long maxVersionCode = userSpec.get(packageName);
+ if (maxVersionCode == null) {
+ return false;
+ }
+ return versionCode <= maxVersionCode;
+ }
+ }
+
+ void addCompatibilityModeRequest(@NonNull String packageName,
+ long versionCode, @UserIdInt int userId) {
+ synchronized (mLock) {
+ if (mUserSpecs == null) {
+ mUserSpecs = new SparseArray<>();
+ }
+ ArrayMap<String, Long> userSpec = mUserSpecs.get(userId);
+ if (userSpec == null) {
+ userSpec = new ArrayMap<>();
+ mUserSpecs.put(userId, userSpec);
+ }
+ userSpec.put(packageName, versionCode);
+ }
+ }
+
+ void removeCompatibilityModeRequests(@UserIdInt int userId) {
+ synchronized (mLock) {
+ if (mUserSpecs != null) {
+ mUserSpecs.remove(userId);
+ if (mUserSpecs.size() <= 0) {
+ mUserSpecs = null;
+ }
}
}
- return false;
}
}
@@ -580,7 +684,7 @@
@Override
public int startSession(IBinder activityToken, IBinder appCallback, AutofillId autofillId,
Rect bounds, AutofillValue value, int userId, boolean hasCallback, int flags,
- ComponentName componentName) {
+ ComponentName componentName, boolean compatMode) {
activityToken = Preconditions.checkNotNull(activityToken, "activityToken");
appCallback = Preconditions.checkNotNull(appCallback, "appCallback");
@@ -599,7 +703,7 @@
synchronized (mLock) {
final AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
return service.startSessionLocked(activityToken, getCallingUid(), appCallback,
- autofillId, bounds, value, hasCallback, flags, componentName);
+ autofillId, bounds, value, hasCallback, flags, componentName, compatMode);
}
}
@@ -770,7 +874,7 @@
public int updateOrRestartSession(IBinder activityToken, IBinder appCallback,
AutofillId autoFillId, Rect bounds, AutofillValue value, int userId,
boolean hasCallback, int flags, ComponentName componentName, int sessionId,
- int action) {
+ int action, boolean compatMode) {
boolean restart = false;
synchronized (mLock) {
final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
@@ -783,7 +887,7 @@
}
if (restart) {
return startSession(activityToken, appCallback, autoFillId, bounds, value, userId,
- hasCallback, flags, componentName);
+ hasCallback, flags, componentName, compatMode);
}
// Nothing changed...
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 2dcc6da..712ea36 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -64,6 +64,7 @@
import android.util.ArraySet;
import android.util.DebugUtils;
import android.util.LocalLog;
+import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
@@ -220,6 +221,17 @@
return mInfo.getServiceInfo().applicationInfo.uid;
}
+
+ @GuardedBy("mLock")
+ @Nullable
+ String getUrlBarResourceIdForCompatModeLocked(@NonNull String packageName) {
+ if (mInfo == null) {
+ Slog.w(TAG, "getUrlBarResourceIdForCompatModeLocked(): no mInfo");
+ return null;
+ }
+ return mInfo.getUrlBarResourceId(packageName);
+ }
+
@Nullable
String getServicePackageName() {
final ComponentName serviceComponent = getServiceComponentName();
@@ -345,7 +357,7 @@
int startSessionLocked(@NonNull IBinder activityToken, int uid,
@NonNull IBinder appCallbackToken, @NonNull AutofillId autofillId,
@NonNull Rect virtualBounds, @Nullable AutofillValue value, boolean hasCallback,
- int flags, @NonNull ComponentName componentName) {
+ int flags, @NonNull ComponentName componentName, boolean compatMode) {
if (!isEnabledLocked()) {
return 0;
}
@@ -375,7 +387,7 @@
pruneAbandonedSessionsLocked();
final Session newSession = createSessionByTokenLocked(activityToken, uid, appCallbackToken,
- hasCallback, componentName, flags);
+ hasCallback, componentName, compatMode, flags);
if (newSession == null) {
return NO_SESSION;
}
@@ -481,7 +493,7 @@
@GuardedBy("mLock")
private Session createSessionByTokenLocked(@NonNull IBinder activityToken, int uid,
@NonNull IBinder appCallbackToken, boolean hasCallback,
- @NonNull ComponentName componentName, int flags) {
+ @NonNull ComponentName componentName, boolean compatMode, int flags) {
// use random ids so that one app cannot know that another app creates sessions
int sessionId;
int tries = 0;
@@ -499,7 +511,8 @@
final Session newSession = new Session(this, mUi, mContext, mHandlerCaller, mUserId, mLock,
sessionId, uid, activityToken, appCallbackToken, hasCallback, mUiLatencyHistory,
- mWtfHistory, mInfo.getServiceInfo().getComponentName(), componentName, flags);
+ mWtfHistory, mInfo.getServiceInfo().getComponentName(), componentName, compatMode,
+ flags);
mSessions.put(newSession.id, newSession);
return newSession;
@@ -857,7 +870,7 @@
}
mUserData = userData;
// Log it
- int numberFields = mUserData == null ? 0: mUserData.getRemoteIds().length;
+ int numberFields = mUserData == null ? 0: mUserData.getCategoryIds().length;
mMetricsLogger.write(Helper.newLogMaker(MetricsEvent.AUTOFILL_USERDATA_UPDATED,
getServicePackageName(), null)
.setCounterValue(numberFields));
@@ -894,7 +907,10 @@
pw.print(prefix); pw.print("Disabled: "); pw.println(mDisabled);
pw.print(prefix); pw.print("Field classification enabled: ");
pw.println(isFieldClassificationEnabledLocked());
- pw.print(prefix); pw.print("Compat pkgs: "); pw.println(getWhitelistedCompatModePackages());
+ final ArrayMap<String, Pair<Long, String>> compatPkgs = getCompatibilityPackagesLocked();
+ if (compatPkgs != null) {
+ pw.print(prefix); pw.print("Compat pkgs: "); pw.println(compatPkgs.keySet());
+ }
pw.print(prefix); pw.print("Setup complete: "); pw.println(mSetupComplete);
pw.print(prefix); pw.print("Last prune: "); pw.println(mLastPrune);
@@ -1018,23 +1034,11 @@
}
@GuardedBy("mLock")
- boolean isCompatibilityModeRequestedLocked(@NonNull String packageName,
- long versionCode) {
- if (mInfo == null || !mInfo.isCompatibilityModeRequested(packageName, versionCode)) {
- return false;
+ @Nullable ArrayMap<String, Pair<Long, String>> getCompatibilityPackagesLocked() {
+ if (mInfo != null) {
+ return mInfo.getCompatibilityPackages();
}
- if (!Build.IS_ENG) {
- // TODO: Build a map and watch for settings changes (this is called on app start)
- final String whiteListedPackages = getWhitelistedCompatModePackages();
- return whiteListedPackages != null && whiteListedPackages.contains(packageName);
- }
- return true;
- }
-
- private String getWhitelistedCompatModePackages() {
- return Settings.Global.getString(
- mContext.getContentResolver(),
- Settings.Global.AUTOFILL_COMPAT_ALLOWED_PACKAGES);
+ return null;
}
private void sendStateToClients(boolean resetClient) {
diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index 02a62e1..5ef467d 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -18,11 +18,14 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.assist.AssistStructure;
+import android.app.assist.AssistStructure.ViewNode;
import android.metrics.LogMaker;
import android.os.Bundle;
import android.service.autofill.Dataset;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.Slog;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillValue;
@@ -31,11 +34,14 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.LinkedList;
import java.util.Objects;
import java.util.Set;
public final class Helper {
+ private static final String TAG = "AutofillHelper";
+
/**
* Defines a logging flag that can be dynamically changed at runtime using
* {@code cmd autofill set log_level debug}.
@@ -121,4 +127,61 @@
pw.print(text.length()); pw.println("_chars");
}
}
+
+ /**
+ * Finds the {@link ViewNode} that has the requested {@code autofillId}, if any.
+ */
+ @Nullable
+ public static ViewNode findViewNodeByAutofillId(@NonNull AssistStructure structure,
+ @NonNull AutofillId autofillId) {
+ return findViewNode(structure, (node) -> {
+ return autofillId.equals(node.getAutofillId());
+ });
+ }
+
+ private static ViewNode findViewNode(@NonNull AssistStructure structure,
+ @NonNull ViewNodeFilter filter) {
+ final LinkedList<ViewNode> nodesToProcess = new LinkedList<>();
+ final int numWindowNodes = structure.getWindowNodeCount();
+ for (int i = 0; i < numWindowNodes; i++) {
+ nodesToProcess.add(structure.getWindowNodeAt(i).getRootViewNode());
+ }
+ while (!nodesToProcess.isEmpty()) {
+ final ViewNode node = nodesToProcess.removeFirst();
+ if (filter.matches(node)) {
+ return node;
+ }
+ for (int i = 0; i < node.getChildCount(); i++) {
+ nodesToProcess.addLast(node.getChildAt(i));
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Sanitize the {@code webDomain} property of the URL bar node on compat mode.
+ */
+ public static void sanitizeUrlBar(@NonNull AssistStructure structure,
+ @NonNull String urlBarId) {
+ final ViewNode urlBarNode = findViewNode(structure, (node) -> {
+ return urlBarId.equals(node.getIdEntry());
+ });
+ if (urlBarNode != null) {
+ final String domain = urlBarNode.getText().toString();
+ if (domain.isEmpty()) {
+ if (sDebug) Slog.d(TAG, "sanitizeUrlBar(): empty on " + urlBarId);
+ return;
+ }
+ urlBarNode.setWebDomain(domain);
+ if (sDebug) {
+ Slog.d(TAG, "sanitizeUrlBar(): id=" + urlBarId + ", domain="
+ + urlBarNode.getWebDomain());
+ }
+ }
+ }
+
+ private interface ViewNodeFilter {
+ boolean matches(ViewNode node);
+ }
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 4a24704..d047581 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -140,6 +140,9 @@
/** Component that's being auto-filled */
@NonNull private final ComponentName mComponentName;
+ /** Whether the app being autofilled is running in compat mode. */
+ private final boolean mCompatMode;
+
@GuardedBy("mLock")
private final ArrayMap<AutofillId, ViewState> mViewStates = new ArrayMap<>();
@@ -263,6 +266,15 @@
componentNameFromApp == null ? "null"
: componentNameFromApp.flattenToShortString()));
}
+ if (mCompatMode) {
+ // Sanitize URL bar, if needed
+ final String urlBarId = mService.getUrlBarResourceIdForCompatModeLocked(
+ mComponentName.getPackageName());
+ if (sDebug) Slog.d(TAG, "url_bar in compat mode: " + urlBarId);
+ if (urlBarId != null) {
+ Helper.sanitizeUrlBar(structure, urlBarId);
+ }
+ }
structure.sanitizeForParceling(true);
// Flags used to start the session.
@@ -476,7 +488,7 @@
@NonNull IBinder client, boolean hasCallback, @NonNull LocalLog uiLatencyHistory,
@NonNull LocalLog wtfHistory,
@NonNull ComponentName serviceComponentName, @NonNull ComponentName componentName,
- int flags) {
+ boolean compatMode, int flags) {
id = sessionId;
mFlags = flags;
this.uid = uid;
@@ -491,6 +503,7 @@
mUiLatencyHistory = uiLatencyHistory;
mWtfHistory = wtfHistory;
mComponentName = componentName;
+ mCompatMode = compatMode;
mClient = IAutoFillManagerClient.Stub.asInterface(client);
mMetricsLogger.write(newLogMaker(MetricsEvent.AUTOFILL_SESSION_STARTED)
@@ -1161,12 +1174,12 @@
@NonNull UserData userData, @NonNull Collection<ViewState> viewStates) {
final String[] userValues = userData.getValues();
- final String[] remoteIds = userData.getRemoteIds();
+ final String[] categoryIds = userData.getCategoryIds();
// Sanity check
- if (userValues == null || remoteIds == null || userValues.length != remoteIds.length) {
+ if (userValues == null || categoryIds == null || userValues.length != categoryIds.length) {
final int valuesLength = userValues == null ? -1 : userValues.length;
- final int idsLength = remoteIds == null ? -1 : remoteIds.length;
+ final int idsLength = categoryIds == null ? -1 : categoryIds.length;
Slog.w(TAG, "setScores(): user data mismatch: values.length = "
+ valuesLength + ", ids.length = " + idsLength);
return;
@@ -1183,12 +1196,12 @@
final int viewsSize = viewStates.size();
// First, we get all scores.
- final AutofillId[] fieldIds = new AutofillId[viewsSize];
+ final AutofillId[] autofillIds = new AutofillId[viewsSize];
final ArrayList<AutofillValue> currentValues = new ArrayList<>(viewsSize);
int k = 0;
for (ViewState viewState : viewStates) {
currentValues.add(viewState.getCurrentValue());
- fieldIds[k++] = viewState.id;
+ autofillIds[k++] = viewState.id;
}
// Then use the results, asynchronously
@@ -1208,32 +1221,53 @@
}
int i = 0, j = 0;
try {
+ // Iteract over all autofill fields first
for (i = 0; i < viewsSize; i++) {
- final AutofillId fieldId = fieldIds[i];
+ final AutofillId autofillId = autofillIds[i];
- ArrayList<Match> matches = null;
+ // Search the best scores for each category (as some categories could have
+ // multiple user values
+ ArrayMap<String, Float> scoresByField = null;
for (j = 0; j < userValues.length; j++) {
- String remoteId = remoteIds[j];
+ final String categoryId = categoryIds[j];
final float score = scores.scores[i][j];
if (score > 0) {
+ if (scoresByField == null) {
+ scoresByField = new ArrayMap<>(userValues.length);
+ }
+ final Float currentScore = scoresByField.get(categoryId);
+ if (currentScore != null && currentScore > score) {
+ if (sVerbose) {
+ Slog.v(TAG, "skipping score " + score
+ + " because it's less than " + currentScore);
+ }
+ continue;
+ }
if (sVerbose) {
Slog.v(TAG, "adding score " + score + " at index " + j + " and id "
- + fieldId);
+ + autofillId);
}
- if (matches == null) {
- matches = new ArrayList<>(userValues.length);
- }
- matches.add(new Match(remoteId, score));
+ scoresByField.put(categoryId, score);
}
else if (sVerbose) {
- Slog.v(TAG, "skipping score 0 at index " + j + " and id " + fieldId);
+ Slog.v(TAG, "skipping score 0 at index " + j + " and id " + autofillId);
}
}
- if (matches != null) {
- detectedFieldIds.add(fieldId);
- detectedFieldClassifications.add(new FieldClassification(matches));
+ if (scoresByField == null) {
+ if (sVerbose) Slog.v(TAG, "no score for autofillId=" + autofillId);
+ continue;
}
- }
+
+ // Then create the matches for that autofill id
+ final ArrayList<Match> matches = new ArrayList<>(scoresByField.size());
+ for (j = 0; j < scoresByField.size(); j++) {
+ final String fieldId = scoresByField.keyAt(j);
+ final float score = scoresByField.valueAt(j);
+ matches.add(new Match(fieldId, score));
+ }
+ detectedFieldIds.add(autofillId);
+ detectedFieldClassifications.add(new FieldClassification(matches));
+ } // for i
} catch (ArrayIndexOutOfBoundsException e) {
wtf(e, "Error accessing FC score at [%d, %d] (%s): %s", i, j, scores, e);
return;
@@ -1537,7 +1571,7 @@
final int numContexts = mContexts.size();
for (int i = numContexts - 1; i >= 0; i--) {
final FillContext context = mContexts.get(i);
- final ViewNode node = context.findViewNodeByAutofillId(id);
+ final ViewNode node = Helper.findViewNodeByAutofillId(context.getStructure(), id);
if (node != null) {
final AutofillValue value = node.getAutofillValue();
if (sDebug) {
@@ -1561,7 +1595,7 @@
for (int i = numContexts - 1; i >= 0; i--) {
final FillContext context = mContexts.get(i);
- final ViewNode node = context.findViewNodeByAutofillId(id);
+ final ViewNode node = Helper.findViewNodeByAutofillId(context.getStructure(), id);
if (node != null && node.getAutofillOptions() != null) {
return node.getAutofillOptions();
}
@@ -2288,6 +2322,7 @@
pw.print(prefix); pw.print("mHasCallback: "); pw.println(mHasCallback);
pw.print(prefix); pw.print("mClientState: "); pw.println(
Helper.bundleToString(mClientState));
+ pw.print(prefix); pw.print("mCompatMode: "); pw.println(mCompatMode);
pw.print(prefix); pw.print("mSelectedDatasetIds: "); pw.println(mSelectedDatasetIds);
mRemoteFillService.dump(prefix, pw);
}
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index 8240e4b..c023efb 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -24,6 +24,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
+import android.content.pm.PackageManager;
import android.graphics.Point;
import android.graphics.Rect;
import android.service.autofill.Dataset;
@@ -37,6 +38,7 @@
import android.view.View;
import android.view.View.MeasureSpec;
import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
import android.view.autofill.AutofillId;
@@ -98,22 +100,28 @@
private @Nullable AnnounceFilterResult mAnnounceFilterResult;
+ private final boolean mFullScreen;
private int mContentWidth;
private int mContentHeight;
private boolean mDestroyed;
+ public static boolean isFullScreen(Context context) {
+ return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
+ }
+
FillUi(@NonNull Context context, @NonNull FillResponse response,
- @NonNull AutofillId focusedViewId, @NonNull @Nullable String filterText,
- @NonNull OverlayControl overlayControl, @NonNull Callback callback) {
+ @NonNull AutofillId focusedViewId, @NonNull @Nullable String filterText,
+ @NonNull OverlayControl overlayControl, @NonNull Callback callback) {
mContext = context;
mCallback = callback;
+ mFullScreen = isFullScreen(context);
final LayoutInflater inflater = LayoutInflater.from(context);
final ViewGroup decor = (ViewGroup) inflater.inflate(
- R.layout.autofill_dataset_picker, null);
-
+ mFullScreen ? R.layout.autofill_dataset_picker_fullscreen
+ : R.layout.autofill_dataset_picker, null);
final RemoteViews.OnClickHandler interceptionHandler = new RemoteViews.OnClickHandler() {
@Override
@@ -130,31 +138,41 @@
mListView = null;
mAdapter = null;
+ // insert authentication item under autofill_dataset_container or decor
+ ViewGroup container = decor.findViewById(R.id.autofill_dataset_container);
+ if (container == null) {
+ container = decor;
+ }
final View content;
try {
content = response.getPresentation().apply(context, decor, interceptionHandler);
- decor.addView(content);
+ container.addView(content);
} catch (RuntimeException e) {
callback.onCanceled();
Slog.e(TAG, "Error inflating remote views", e);
mWindow = null;
return;
}
+ content.setFocusable(true);
+ content.setOnClickListener(v -> mCallback.onResponsePicked(response));
Point maxSize = mTempPoint;
resolveMaxWindowSize(context, maxSize);
+ // fullScreen mode occupy the full width defined by autofill_dataset_picker_max_width
+ content.getLayoutParams().width = mFullScreen ? maxSize.x
+ : ViewGroup.LayoutParams.WRAP_CONTENT;
+ content.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;
final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(maxSize.x,
MeasureSpec.AT_MOST);
final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(maxSize.y,
MeasureSpec.AT_MOST);
decor.measure(widthMeasureSpec, heightMeasureSpec);
- decor.setOnClickListener(v -> mCallback.onResponsePicked(response));
mContentWidth = content.getMeasuredWidth();
mContentHeight = content.getMeasuredHeight();
mWindow = new AnchoredWindow(decor, overlayControl);
- mCallback.requestShowFillUi(mContentWidth, mContentHeight, mWindowPresenter);
+ requestShowFillUi();
} else {
final int datasetCount = response.getDatasets().size();
@@ -261,6 +279,15 @@
}
}
+ void requestShowFillUi() {
+ if (mFullScreen) {
+ mCallback.requestShowFillUi(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
+ mWindowPresenter);
+ } else {
+ mCallback.requestShowFillUi(mContentWidth, mContentHeight, mWindowPresenter);
+ }
+ }
+
/**
* Creates a remoteview interceptor used to block clicks.
*/
@@ -289,7 +316,13 @@
mCallback.requestHideFillUi();
} else {
if (updateContentSize()) {
- mCallback.requestShowFillUi(mContentWidth, mContentHeight, mWindowPresenter);
+ if (mFullScreen) {
+ LayoutParams lp = mListView.getLayoutParams();
+ lp.width = mContentWidth;
+ lp.height = mContentHeight;
+ mListView.setLayoutParams(lp);
+ }
+ requestShowFillUi();
}
if (mAdapter.getCount() > VISIBLE_OPTIONS_MAX_COUNT) {
mListView.setVerticalScrollBarEnabled(true);
@@ -310,7 +343,7 @@
// ViewState doesn't not support filtering - typically when it's for an authenticated
// FillResponse.
if (TextUtils.isEmpty(filterText)) {
- mCallback.requestShowFillUi(mContentWidth, mContentHeight, mWindowPresenter);
+ requestShowFillUi();
} else {
mCallback.requestHideFillUi();
}
@@ -366,23 +399,39 @@
final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(maxSize.y,
MeasureSpec.AT_MOST);
final int itemCount = mAdapter.getCount();
+ if (mFullScreen) {
+ // fullScreen mode occupy the full width defined by autofill_dataset_picker_max_width
+ changed = true;
+ mContentWidth = maxSize.x;
+ }
for (int i = 0; i < itemCount; i++) {
final View view = mAdapter.getItem(i).view;
view.measure(widthMeasureSpec, heightMeasureSpec);
- final int clampedMeasuredWidth = Math.min(view.getMeasuredWidth(), maxSize.x);
- final int newContentWidth = Math.max(mContentWidth, clampedMeasuredWidth);
- if (newContentWidth != mContentWidth) {
- mContentWidth = newContentWidth;
- changed = true;
- }
- // Update the width to fit only the first items up to max count
- if (i < VISIBLE_OPTIONS_MAX_COUNT) {
- final int clampedMeasuredHeight = Math.min(view.getMeasuredHeight(), maxSize.y);
- final int newContentHeight = mContentHeight + clampedMeasuredHeight;
- if (newContentHeight != mContentHeight) {
- mContentHeight = newContentHeight;
+ if (mFullScreen) {
+ // for fullscreen, add up all children height until hit max height.
+ final int newContentHeight = mContentHeight + view.getMeasuredHeight();
+ final int clampedNewHeight = Math.min(newContentHeight, maxSize.y);
+ if (clampedNewHeight != mContentHeight) {
+ mContentHeight = clampedNewHeight;
+ } else if (view.getMeasuredHeight() > 0) {
+ break;
+ }
+ } else {
+ final int clampedMeasuredWidth = Math.min(view.getMeasuredWidth(), maxSize.x);
+ final int newContentWidth = Math.max(mContentWidth, clampedMeasuredWidth);
+ if (newContentWidth != mContentWidth) {
+ mContentWidth = newContentWidth;
changed = true;
}
+ // Update the width to fit only the first items up to max count
+ if (i < VISIBLE_OPTIONS_MAX_COUNT) {
+ final int clampedMeasuredHeight = Math.min(view.getMeasuredHeight(), maxSize.y);
+ final int newContentHeight = mContentHeight + clampedMeasuredHeight;
+ if (newContentHeight != mContentHeight) {
+ mContentHeight = newContentHeight;
+ changed = true;
+ }
+ }
}
}
return changed;
@@ -575,6 +624,7 @@
public void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("mCallback: "); pw.println(mCallback != null);
+ pw.print(prefix); pw.print("mFullScreen: "); pw.println(mFullScreen);
pw.print(prefix); pw.print("mListView: "); pw.println(mListView);
pw.print(prefix); pw.print("mAdapter: "); pw.println(mAdapter);
pw.print(prefix); pw.print("mFilterText: ");
diff --git a/services/backup/OWNERS b/services/backup/OWNERS
new file mode 100644
index 0000000..1c9a43a
--- /dev/null
+++ b/services/backup/OWNERS
@@ -0,0 +1,7 @@
+artikz@google.com
+brufino@google.com
+bryanmawhinney@google.com
+ctate@google.com
+jorlow@google.com
+mkarpinski@google.com
+
diff --git a/services/backup/java/com/android/server/backup/TransportManager.java b/services/backup/java/com/android/server/backup/TransportManager.java
index 7e179e5..501ff29 100644
--- a/services/backup/java/com/android/server/backup/TransportManager.java
+++ b/services/backup/java/com/android/server/backup/TransportManager.java
@@ -26,6 +26,7 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.os.Bundle;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.ArrayMap;
@@ -57,6 +58,8 @@
@VisibleForTesting
public static final String SERVICE_ACTION_TRANSPORT_HOST = "android.backup.TRANSPORT_HOST";
+ private static final String EXTRA_TRANSPORT_REGISTRATION = "transport_registration";
+
private final Intent mTransportServiceIntent = new Intent(SERVICE_ACTION_TRANSPORT_HOST);
private final Context mContext;
private final PackageManager mPackageManager;
@@ -582,8 +585,12 @@
String transportString = transportComponent.flattenToShortString();
String callerLogString = "TransportManager.registerTransport()";
- TransportClient transportClient =
- mTransportClientManager.getTransportClient(transportComponent, callerLogString);
+
+ Bundle extras = new Bundle();
+ extras.putBoolean(EXTRA_TRANSPORT_REGISTRATION, true);
+
+ TransportClient transportClient = mTransportClientManager.getTransportClient(
+ transportComponent, extras, callerLogString);
final IBackupTransport transport;
try {
transport = transportClient.connectOrThrow(callerLogString);
diff --git a/services/backup/java/com/android/server/backup/transport/TransportClientManager.java b/services/backup/java/com/android/server/backup/transport/TransportClientManager.java
index 4041932..96e7d2f 100644
--- a/services/backup/java/com/android/server/backup/transport/TransportClientManager.java
+++ b/services/backup/java/com/android/server/backup/transport/TransportClientManager.java
@@ -22,10 +22,9 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-
+import android.os.Bundle;
import com.android.server.backup.TransportManager;
import com.android.server.backup.transport.TransportUtils.Priority;
-
import java.io.PrintWriter;
import java.util.Map;
import java.util.WeakHashMap;
@@ -59,6 +58,32 @@
public TransportClient getTransportClient(ComponentName transportComponent, String caller) {
Intent bindIntent =
new Intent(SERVICE_ACTION_TRANSPORT_HOST).setComponent(transportComponent);
+
+ return getTransportClient(transportComponent, caller, bindIntent);
+ }
+
+ /**
+ * Retrieves a {@link TransportClient} for the transport identified by {@param
+ * transportComponent} whose binding intent will have the {@param extras} extras.
+ *
+ * @param transportComponent The {@link ComponentName} of the transport.
+ * @param extras A {@link Bundle} of extras to pass to the binding intent.
+ * @param caller A {@link String} identifying the caller for logging/debugging purposes. Check
+ * {@link TransportClient#connectAsync(TransportConnectionListener, String)} for more
+ * details.
+ * @return A {@link TransportClient}.
+ */
+ public TransportClient getTransportClient(
+ ComponentName transportComponent, Bundle extras, String caller) {
+ Intent bindIntent =
+ new Intent(SERVICE_ACTION_TRANSPORT_HOST).setComponent(transportComponent);
+ bindIntent.putExtras(extras);
+
+ return getTransportClient(transportComponent, caller, bindIntent);
+ }
+
+ private TransportClient getTransportClient(
+ ComponentName transportComponent, String caller, Intent bindIntent) {
synchronized (mTransportClientsLock) {
TransportClient transportClient =
new TransportClient(
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 10fad62..a422b7c 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -2584,7 +2584,7 @@
if (mAlarmBatches.size() > 0) {
final Batch firstWakeup = findFirstWakeupBatchLocked();
final Batch firstBatch = mAlarmBatches.get(0);
- if (firstWakeup != null && mNextWakeup != firstWakeup.start) {
+ if (firstWakeup != null) {
mNextWakeup = firstWakeup.start;
mLastWakeupSet = SystemClock.elapsedRealtime();
setLocked(ELAPSED_REALTIME_WAKEUP, firstWakeup.start);
@@ -2598,7 +2598,7 @@
nextNonWakeup = mNextNonWakeupDeliveryTime;
}
}
- if (nextNonWakeup != 0 && mNextNonWakeup != nextNonWakeup) {
+ if (nextNonWakeup != 0) {
mNextNonWakeup = nextNonWakeup;
setLocked(ELAPSED_REALTIME, nextNonWakeup);
}
@@ -3229,6 +3229,8 @@
expectedMaxWhenElapsed, nowELAPSED, pw);
pw.print(" whenElapsed="); TimeUtils.formatDuration(whenElapsed,
nowELAPSED, pw);
+ pw.print(" maxWhenElapsed="); TimeUtils.formatDuration(maxWhenElapsed,
+ nowELAPSED, pw);
pw.print(" when=");
if (isRtc) {
pw.print(sdf.format(new Date(when)));
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index efad7d5..f633003 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -30,6 +30,7 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
@@ -1290,11 +1291,7 @@
for (Network network : networks) {
nai = getNetworkAgentInfoForNetwork(network);
nc = getNetworkCapabilitiesInternal(nai);
- // nc is a copy of the capabilities in nai, so it's fine to mutate it
- // TODO : don't remove the UIDs when communicating with processes
- // that have the NETWORK_SETTINGS permission.
if (nc != null) {
- nc.setSingleUid(userId);
result.put(network, nc);
}
}
@@ -1362,7 +1359,9 @@
if (nai != null) {
synchronized (nai) {
if (nai.networkCapabilities != null) {
- return new NetworkCapabilities(nai.networkCapabilities);
+ // TODO : don't remove the UIDs when communicating with processes
+ // that have the NETWORK_SETTINGS permission.
+ return networkCapabilitiesWithoutUids(nai.networkCapabilities);
}
}
}
@@ -1375,6 +1374,10 @@
return getNetworkCapabilitiesInternal(getNetworkAgentInfoForNetwork(network));
}
+ private NetworkCapabilities networkCapabilitiesWithoutUids(NetworkCapabilities nc) {
+ return new NetworkCapabilities(nc).setUids(null);
+ }
+
@Override
public NetworkState[] getAllNetworkState() {
// Require internal since we're handing out IMSI details
@@ -1384,6 +1387,10 @@
for (Network network : getAllNetworks()) {
final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
if (nai != null) {
+ // TODO (b/73321673) : NetworkState contains a copy of the
+ // NetworkCapabilities, which may contain UIDs of apps to which the
+ // network applies. Should the UIDs be cleared so as not to leak or
+ // interfere ?
result.add(nai.getNetworkState());
}
}
@@ -4542,10 +4549,12 @@
lp.ensureDirectlyConnectedRoutes();
// TODO: Instead of passing mDefaultRequest, provide an API to determine whether a Network
// satisfies mDefaultRequest.
+ final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
- new Network(reserveNetId()), new NetworkInfo(networkInfo), lp,
- new NetworkCapabilities(networkCapabilities), currentScore,
+ new Network(reserveNetId()), new NetworkInfo(networkInfo), lp, nc, currentScore,
mContext, mTrackerHandler, new NetworkMisc(networkMisc), mDefaultRequest, this);
+ // Make sure the network capabilities reflect what the agent info says.
+ nai.networkCapabilities = mixInCapabilities(nai, nc);
synchronized (this) {
nai.networkMonitor.systemReady = mSystemReady;
}
@@ -4774,6 +4783,11 @@
} else {
newNc.addCapability(NET_CAPABILITY_FOREGROUND);
}
+ if (nai.isSuspended()) {
+ newNc.removeCapability(NET_CAPABILITY_NOT_SUSPENDED);
+ } else {
+ newNc.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
+ }
return newNc;
}
@@ -4954,7 +4968,7 @@
releasePendingNetworkRequestWithDelay(pendingIntent);
}
- private static void callCallbackForRequest(NetworkRequestInfo nri,
+ private void callCallbackForRequest(NetworkRequestInfo nri,
NetworkAgentInfo networkAgent, int notificationType, int arg1) {
if (nri.messenger == null) {
return; // Default request has no msgr
@@ -4967,16 +4981,19 @@
putParcelable(bundle, networkAgent.network);
}
switch (notificationType) {
+ case ConnectivityManager.CALLBACK_AVAILABLE: {
+ putParcelable(bundle, new NetworkCapabilities(networkAgent.networkCapabilities));
+ putParcelable(bundle, new LinkProperties(networkAgent.linkProperties));
+ break;
+ }
case ConnectivityManager.CALLBACK_LOSING: {
msg.arg1 = arg1;
break;
}
case ConnectivityManager.CALLBACK_CAP_CHANGED: {
+ // networkAgent can't be null as it has been accessed a few lines above.
final NetworkCapabilities nc =
- new NetworkCapabilities(networkAgent.networkCapabilities);
- // TODO : don't remove the UIDs when communicating with processes
- // that have the NETWORK_SETTINGS permission.
- nc.setSingleUid(nri.mUid);
+ networkCapabilitiesWithoutUids(networkAgent.networkCapabilities);
putParcelable(bundle, nc);
break;
}
@@ -5509,6 +5526,10 @@
if (networkAgent.getCurrentScore() != oldScore) {
rematchAllNetworksAndRequests(networkAgent, oldScore);
}
+ updateCapabilities(networkAgent.getCurrentScore(), networkAgent,
+ networkAgent.networkCapabilities);
+ // TODO (b/73132094) : remove this call once the few users of onSuspended and
+ // onResumed have been removed.
notifyNetworkCallbacks(networkAgent, (state == NetworkInfo.State.SUSPENDED ?
ConnectivityManager.CALLBACK_SUSPENDED :
ConnectivityManager.CALLBACK_RESUMED));
@@ -5545,14 +5566,6 @@
}
callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_AVAILABLE, 0);
- // Whether a network is currently suspended is also an important
- // element of state to be transferred (it would not otherwise be
- // delivered by any currently available mechanism).
- if (nai.networkInfo.getState() == NetworkInfo.State.SUSPENDED) {
- callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_SUSPENDED, 0);
- }
- callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_CAP_CHANGED, 0);
- callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_IP_CHANGED, 0);
}
private void sendLegacyNetworkBroadcast(NetworkAgentInfo nai, DetailedState state, int type) {
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index bdeb231..7cd007b 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -120,7 +120,6 @@
import android.service.vr.IVrStateCallbacks;
import android.text.TextUtils;
import android.text.style.SuggestionSpan;
-import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.EventLog;
@@ -183,7 +182,6 @@
public class InputMethodManagerService extends IInputMethodManager.Stub
implements ServiceConnection, Handler.Callback {
static final boolean DEBUG = false;
- static final boolean DEBUG_RESTORE = DEBUG || false;
static final String TAG = "InputMethodManagerService";
@Retention(SOURCE)
@@ -911,15 +909,6 @@
|| Intent.ACTION_USER_REMOVED.equals(action)) {
updateCurrentProfileIds();
return;
- } else if (Intent.ACTION_SETTING_RESTORED.equals(action)) {
- final String name = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
- if (Settings.Secure.ENABLED_INPUT_METHODS.equals(name)) {
- final String prevValue = intent.getStringExtra(
- Intent.EXTRA_SETTING_PREVIOUS_VALUE);
- final String newValue = intent.getStringExtra(
- Intent.EXTRA_SETTING_NEW_VALUE);
- restoreEnabledInputMethods(mContext, prevValue, newValue);
- }
} else if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {
onActionLocaleChanged();
} else if (ACTION_SHOW_INPUT_METHOD_PICKER.equals(action)) {
@@ -984,44 +973,6 @@
}
}
- // Apply the results of a restore operation to the set of enabled IMEs. Note that this
- // does not attempt to validate on the fly with any installed device policy, so must only
- // be run in the context of initial device setup.
- //
- // TODO: Move this method to InputMethodUtils with adding unit tests.
- static void restoreEnabledInputMethods(Context context, String prevValue, String newValue) {
- if (DEBUG_RESTORE) {
- Slog.i(TAG, "Restoring enabled input methods:");
- Slog.i(TAG, "prev=" + prevValue);
- Slog.i(TAG, " new=" + newValue);
- }
- // 'new' is the just-restored state, 'prev' is what was in settings prior to the restore
- ArrayMap<String, ArraySet<String>> prevMap =
- InputMethodUtils.parseInputMethodsAndSubtypesString(prevValue);
- ArrayMap<String, ArraySet<String>> newMap =
- InputMethodUtils.parseInputMethodsAndSubtypesString(newValue);
-
- // Merge the restored ime+subtype enabled states into the live state
- for (ArrayMap.Entry<String, ArraySet<String>> entry : newMap.entrySet()) {
- final String imeId = entry.getKey();
- ArraySet<String> prevSubtypes = prevMap.get(imeId);
- if (prevSubtypes == null) {
- prevSubtypes = new ArraySet<>(2);
- prevMap.put(imeId, prevSubtypes);
- }
- prevSubtypes.addAll(entry.getValue());
- }
-
- final String mergedImesAndSubtypesString =
- InputMethodUtils.buildInputMethodsAndSubtypesString(prevMap);
- if (DEBUG_RESTORE) {
- Slog.i(TAG, "Merged IME string:");
- Slog.i(TAG, " " + mergedImesAndSubtypesString);
- }
- Settings.Secure.putString(context.getContentResolver(),
- Settings.Secure.ENABLED_INPUT_METHODS, mergedImesAndSubtypesString);
- }
-
final class MyPackageMonitor extends PackageMonitor {
/**
* Package names that are known to contain {@link InputMethodService}.
@@ -1577,7 +1528,6 @@
broadcastFilter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
broadcastFilter.addAction(Intent.ACTION_USER_ADDED);
broadcastFilter.addAction(Intent.ACTION_USER_REMOVED);
- broadcastFilter.addAction(Intent.ACTION_SETTING_RESTORED);
broadcastFilter.addAction(Intent.ACTION_LOCALE_CHANGED);
broadcastFilter.addAction(ACTION_SHOW_INPUT_METHOD_PICKER);
mContext.registerReceiver(new ImmsBroadcastReceiver(), broadcastFilter);
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 6747be3..5e5eacb 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -64,6 +64,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.NoSuchElementException;
/**
* Since phone process can be restarted, this class provides a centralized place
@@ -90,6 +91,8 @@
IBinder binder;
+ TelephonyRegistryDeathRecipient deathRecipient;
+
IPhoneStateListener callback;
IOnSubscriptionsChangedListener onSubscriptionsChangedListenerCallback;
@@ -251,6 +254,21 @@
}
};
+ private class TelephonyRegistryDeathRecipient implements IBinder.DeathRecipient {
+
+ private final IBinder binder;
+
+ TelephonyRegistryDeathRecipient(IBinder binder) {
+ this.binder = binder;
+ }
+
+ @Override
+ public void binderDied() {
+ if (DBG) log("binderDied " + binder);
+ remove(binder);
+ }
+ }
+
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -378,23 +396,14 @@
}
}
- Record r;
synchronized (mRecords) {
// register
- find_and_add: {
- IBinder b = callback.asBinder();
- final int N = mRecords.size();
- for (int i = 0; i < N; i++) {
- r = mRecords.get(i);
- if (b == r.binder) {
- break find_and_add;
- }
- }
- r = new Record();
- r.binder = b;
- mRecords.add(r);
- if (DBG) log("listen oscl: add new record");
+ IBinder b = callback.asBinder();
+ Record r = add(b);
+
+ if (r == null) {
+ return;
}
r.onSubscriptionsChangedListenerCallback = callback;
@@ -496,20 +505,11 @@
synchronized (mRecords) {
// register
- Record r;
- find_and_add: {
- IBinder b = callback.asBinder();
- final int N = mRecords.size();
- for (int i = 0; i < N; i++) {
- r = mRecords.get(i);
- if (b == r.binder) {
- break find_and_add;
- }
- }
- r = new Record();
- r.binder = b;
- mRecords.add(r);
- if (DBG) log("listen: add new record");
+ IBinder b = callback.asBinder();
+ Record r = add(b);
+
+ if (r == null) {
+ return;
}
r.callback = callback;
@@ -697,16 +697,57 @@
return record.canReadPhoneState ? mCallIncomingNumber[phoneId] : "";
}
+ private Record add(IBinder binder) {
+ Record r;
+
+ synchronized (mRecords) {
+ final int N = mRecords.size();
+ for (int i = 0; i < N; i++) {
+ r = mRecords.get(i);
+ if (binder == r.binder) {
+ // Already existed.
+ return r;
+ }
+ }
+ r = new Record();
+ r.binder = binder;
+ r.deathRecipient = new TelephonyRegistryDeathRecipient(binder);
+
+ try {
+ binder.linkToDeath(r.deathRecipient, 0);
+ } catch (RemoteException e) {
+ if (VDBG) log("LinkToDeath remote exception sending to r=" + r + " e=" + e);
+ // Binder already died. Return null.
+ return null;
+ }
+
+ mRecords.add(r);
+ if (DBG) log("add new record");
+ }
+
+ return r;
+ }
+
private void remove(IBinder binder) {
synchronized (mRecords) {
final int recordCount = mRecords.size();
for (int i = 0; i < recordCount; i++) {
- if (mRecords.get(i).binder == binder) {
+ Record r = mRecords.get(i);
+ if (r.binder == binder) {
if (DBG) {
- Record r = mRecords.get(i);
- log("remove: binder=" + binder + "r.callingPackage" + r.callingPackage
- + "r.callback" + r.callback);
+ log("remove: binder=" + binder + " r.callingPackage " + r.callingPackage
+ + " r.callback " + r.callback);
}
+
+ if (r.deathRecipient != null) {
+ try {
+ binder.unlinkToDeath(r.deathRecipient, 0);
+ } catch (NoSuchElementException e) {
+ if (VDBG) log("UnlinkToDeath NoSuchElementException sending to r="
+ + r + " e=" + e);
+ }
+ }
+
mRecords.remove(i);
return;
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 230f69d..5fc4373 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1043,14 +1043,20 @@
throw new SecurityException("Instant app " + r.appInfo.packageName
+ " does not have permission to create foreground services");
default:
- mAm.enforcePermission(
- android.Manifest.permission.INSTANT_APP_FOREGROUND_SERVICE,
- r.app.pid, r.appInfo.uid, "startForeground");
+ try {
+ if (AppGlobals.getPackageManager().checkPermission(
+ android.Manifest.permission.INSTANT_APP_FOREGROUND_SERVICE,
+ r.appInfo.packageName, UserHandle.getUserId(r.appInfo.uid))
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Instant app " + r.appInfo.packageName
+ + " does not have permission to create foreground"
+ + "services");
+ }
+ } catch (RemoteException e) {
+ throw new SecurityException("Failed to check instant app permission." ,
+ e);
+ }
}
- } else if (r.appInfo.targetSdkVersion >= Build.VERSION_CODES.P) {
- mAm.enforcePermission(
- android.Manifest.permission.FOREGROUND_SERVICE,
- r.app.pid, r.appInfo.uid, "startForeground");
}
if (r.fgRequired) {
if (DEBUG_SERVICE || DEBUG_BACKGROUND_CHECK) {
@@ -1089,7 +1095,7 @@
active.mNumActive++;
}
r.isForeground = true;
- StatsLog.write(StatsLog.FOREGROUND_SERVICE_STATE_CHANGED, r.userId, r.shortName,
+ StatsLog.write(StatsLog.FOREGROUND_SERVICE_STATE_CHANGED, r.appInfo.uid, r.shortName,
StatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER);
}
r.postNotification();
@@ -1106,7 +1112,7 @@
decActiveForegroundAppLocked(smap, r);
}
r.isForeground = false;
- StatsLog.write(StatsLog.FOREGROUND_SERVICE_STATE_CHANGED, r.userId, r.shortName,
+ StatsLog.write(StatsLog.FOREGROUND_SERVICE_STATE_CHANGED, r.appInfo.uid, r.shortName,
StatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT);
if (r.app != null) {
mAm.updateLruProcessLocked(r.app, false, null);
@@ -2532,7 +2538,7 @@
cancelForegroundNotificationLocked(r);
if (r.isForeground) {
decActiveForegroundAppLocked(smap, r);
- StatsLog.write(StatsLog.FOREGROUND_SERVICE_STATE_CHANGED, r.userId, r.shortName,
+ StatsLog.write(StatsLog.FOREGROUND_SERVICE_STATE_CHANGED, r.appInfo.uid, r.shortName,
StatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT);
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
index 0a7d3fd..8367916 100644
--- a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
+++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
@@ -65,7 +65,7 @@
static final boolean DEBUG_NETWORK = DEBUG_ALL || false;
static final boolean DEBUG_OOM_ADJ = DEBUG_ALL || false;
static final boolean DEBUG_OOM_ADJ_REASON = DEBUG_ALL || false;
- static final boolean DEBUG_PAUSE = DEBUG_ALL || false;
+ static final boolean DEBUG_PAUSE = DEBUG_ALL || true;
static final boolean DEBUG_POWER = DEBUG_ALL || false;
static final boolean DEBUG_POWER_QUICK = DEBUG_POWER || false;
static final boolean DEBUG_PROCESS_OBSERVERS = DEBUG_ALL || false;
@@ -81,7 +81,7 @@
static final boolean DEBUG_FOREGROUND_SERVICE = DEBUG_ALL || false;
static final boolean DEBUG_SERVICE_EXECUTING = DEBUG_ALL || false;
static final boolean DEBUG_STACK = DEBUG_ALL || false;
- static final boolean DEBUG_STATES = DEBUG_ALL_ACTIVITIES || false;
+ static final boolean DEBUG_STATES = DEBUG_ALL_ACTIVITIES || true;
static final boolean DEBUG_SWITCH = DEBUG_ALL || false;
static final boolean DEBUG_TASKS = DEBUG_ALL || false;
static final boolean DEBUG_TRANSITION = DEBUG_ALL || false;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index cd8b6d7..5f8a5ab 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -38,7 +38,6 @@
import static android.app.ActivityThread.PROC_START_SEQ_IDENT;
import static android.app.AppOpsManager.OP_ASSIST_STRUCTURE;
import static android.app.AppOpsManager.OP_NONE;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
@@ -381,6 +380,7 @@
import android.view.Gravity;
import android.view.IRecentsAnimationRunner;
import android.view.LayoutInflater;
+import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationDefinition;
import android.view.View;
import android.view.WindowManager;
@@ -454,7 +454,6 @@
import com.android.server.utils.PriorityDump;
import com.android.server.vr.VrManagerInternal;
import com.android.server.wm.PinnedStackWindowController;
-import com.android.server.wm.RecentsAnimationController;
import com.android.server.wm.WindowManagerService;
import dalvik.system.VMRuntime;
@@ -581,6 +580,10 @@
// How long we wait until we timeout on key dispatching during instrumentation.
static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
+ // Disable hidden API checks for the newly started instrumentation.
+ // Must be kept in sync with Am.
+ private static final int INSTRUMENTATION_FLAG_DISABLE_HIDDEN_API_CHECKS = 1 << 0;
+
// How long to wait in getAssistContextExtras for the activity and foreground services
// to respond with the result.
static final int PENDING_ASSIST_EXTRAS_TIMEOUT = 500;
@@ -1908,6 +1911,9 @@
final ActivityManagerConstants mConstants;
+ // Encapsulates the global setting "hidden_api_blacklist_exemptions"
+ final HiddenApiBlacklist mHiddenApiBlacklist;
+
PackageManagerInternal mPackageManagerInt;
// VoiceInteraction session ID that changes for each new request except when
@@ -2825,6 +2831,42 @@
}
}
+ /**
+ * Encapsulates the globla setting "hidden_api_blacklist_exemptions", including tracking the
+ * latest value via a content observer.
+ */
+ static class HiddenApiBlacklist extends ContentObserver {
+
+ private final Context mContext;
+ private boolean mBlacklistDisabled;
+
+ public HiddenApiBlacklist(Handler handler, Context context) {
+ super(handler);
+ mContext = context;
+ }
+
+ public void registerObserver() {
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS),
+ false,
+ this);
+ update();
+ }
+
+ private void update() {
+ mBlacklistDisabled = "*".equals(Settings.Global.getString(mContext.getContentResolver(),
+ Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS));
+ }
+
+ boolean isDisabled() {
+ return mBlacklistDisabled;
+ }
+
+ public void onChange(boolean selfChange) {
+ update();
+ }
+ }
+
@VisibleForTesting
public ActivityManagerService(Injector injector) {
mInjector = injector;
@@ -2859,6 +2901,7 @@
mLifecycleManager = null;
mProcStartHandlerThread = null;
mProcStartHandler = null;
+ mHiddenApiBlacklist = null;
}
// Note: This method is invoked on the main thread but may need to attach various
@@ -3002,6 +3045,8 @@
}
};
+ mHiddenApiBlacklist = new HiddenApiBlacklist(mHandler, mContext);
+
Watchdog.getInstance().addMonitor(this);
Watchdog.getInstance().addThread(mHandler);
@@ -3962,12 +4007,19 @@
startProcessLocked(app, hostingType, hostingNameStr, null /* abiOverride */);
}
+ @GuardedBy("this")
+ private final boolean startProcessLocked(ProcessRecord app,
+ String hostingType, String hostingNameStr, String abiOverride) {
+ return startProcessLocked(app, hostingType, hostingNameStr,
+ false /* disableHiddenApiChecks */, abiOverride);
+ }
+
/**
* @return {@code true} if process start is successful, false otherwise.
*/
@GuardedBy("this")
private final boolean startProcessLocked(ProcessRecord app, String hostingType,
- String hostingNameStr, String abiOverride) {
+ String hostingNameStr, boolean disableHiddenApiChecks, String abiOverride) {
if (app.pendingStart) {
return true;
}
@@ -4090,10 +4142,12 @@
runtimeFlags |= Zygote.ONLY_USE_SYSTEM_OAT_FILES;
}
- if (app.info.isAllowedToUseHiddenApi()) {
- // This app is allowed to use undocumented and private APIs. Set
- // up its runtime with the appropriate flag.
- runtimeFlags |= Zygote.DISABLE_HIDDEN_API_CHECKS;
+ if (!app.info.isAllowedToUseHiddenApi() &&
+ !disableHiddenApiChecks &&
+ !mHiddenApiBlacklist.isDisabled()) {
+ // This app is not allowed to use undocumented and private APIs, or blacklisting is
+ // enabled. Set up its runtime with the appropriate flag.
+ runtimeFlags |= Zygote.ENABLE_HIDDEN_API_CHECKS;
}
String invokeWith = null;
@@ -4371,7 +4425,7 @@
"updateUsageStats: comp=" + component + "res=" + resumed);
final BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
StatsLog.write(StatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED,
- component.userId, component.realActivity.getPackageName(),
+ component.app.uid, component.realActivity.getPackageName(),
component.realActivity.getShortClassName(), resumed ?
StatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED__ACTIVITY__MOVE_TO_FOREGROUND :
StatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED__ACTIVITY__MOVE_TO_BACKGROUND);
@@ -8889,20 +8943,6 @@
/**
* This can be called with or without the global lock held.
*/
- void enforcePermission(String permission, int pid, int uid, String func) {
- if (checkPermission(permission, pid, uid) == PackageManager.PERMISSION_GRANTED) {
- return;
- }
-
- String msg = "Permission Denial: " + func + " from pid=" + pid + ", uid=" + uid
- + " requires " + permission;
- Slog.w(TAG, msg);
- throw new SecurityException(msg);
- }
-
- /**
- * This can be called with or without the global lock held.
- */
void enforceCallerIsRecentsOrHasPermission(String permission, String func) {
if (!mRecentTasks.isCallerRecents(Binder.getCallingUid())) {
enforceCallingPermission(permission, func);
@@ -10073,6 +10113,75 @@
}
/**
+ * Updates (grants or revokes) a persitable URI permission.
+ *
+ * @param uri URI to be granted or revoked.
+ * @param prefix if {@code false}, permission apply to this specific URI; if {@code true}, it
+ * applies to all URIs that are prefixed by this URI.
+ * @param packageName target package.
+ * @param grant if {@code true} a new permission will be granted, otherwise an existing
+ * permission will be revoked.
+ * @param userId user handle
+ *
+ * @return whether or not the requested succeeded.
+ *
+ * @deprecated TODO(b/72055774): caller should use takePersistableUriPermission() or
+ * releasePersistableUriPermission() instead, but such change will be made in a separate CL
+ * so it can be easily reverted if it breaks existing functionality.
+ */
+ @Deprecated // STOPSHIP if not removed
+ @Override
+ public boolean updatePersistableUriPermission(Uri uri, boolean prefix, String packageName,
+ boolean grant, int userId) {
+ enforceCallingPermission(android.Manifest.permission.GET_APP_GRANTED_URI_PERMISSIONS,
+ "updatePersistableUriPermission");
+ final int uid = mPackageManagerInt.getPackageUid(packageName, 0, userId);
+
+ final GrantUri grantUri = new GrantUri(userId, uri, prefix);
+
+ boolean persistChanged = false;
+ synchronized (this) {
+ if (grant) { // Grant
+ final String authority = uri.getAuthority();
+ final ProviderInfo pi = getProviderInfoLocked(authority, userId, 0);
+ if (pi == null) {
+ Slog.w(TAG, "No content provider found for authority " + authority);
+ return false;
+ }
+ final UriPermission permission = findOrCreateUriPermissionLocked(pi.packageName,
+ packageName, uid, grantUri);
+ if (permission.isNew()) {
+ final int modeFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
+ permission.initPersistedModes(modeFlags, System.currentTimeMillis());
+ persistChanged = true;
+ } else {
+ // Caller should not try to grant permission that is already granted.
+ Slog.w(TAG_URI_PERMISSION,
+ "permission already granted for " + grantUri.toSafeString());
+ return false;
+ }
+ persistChanged |= maybePrunePersistedUriGrantsLocked(uid);
+ } else { // Revoke
+ final UriPermission permission = findUriPermissionLocked(uid, grantUri);
+ if (permission == null) {
+ // Caller should not try to revoke permission that is not granted.
+ Slog.v(TAG_URI_PERMISSION, "no permission for " + grantUri.toSafeString());
+ return false;
+ } else {
+ permission.modeFlags = 0;
+ removeUriPermissionIfNeededLocked(permission);
+ persistChanged = true;
+ }
+ }
+ if (persistChanged) {
+ schedulePersistUriGrants();
+ }
+ }
+ return true;
+ }
+
+ /**
* @param uri This uri must NOT contain an embedded userId.
* @param userId The userId in which the uri is to be resolved.
*/
@@ -11336,9 +11445,6 @@
throw new IllegalArgumentException("Invalid task, not in foreground");
}
- // When a task is locked, dismiss the pinned stack if it exists
- mStackSupervisor.removeStacksInWindowingModes(WINDOWING_MODE_PINNED);
-
// {@code isSystemCaller} is used to distinguish whether this request is initiated by the
// system or a specific app.
// * System-initiated requests will only start the pinned mode (screen pinning)
@@ -11348,6 +11454,9 @@
final int callingUid = Binder.getCallingUid();
long ident = Binder.clearCallingIdentity();
try {
+ // When a task is locked, dismiss the pinned stack if it exists
+ mStackSupervisor.removeStacksInWindowingModes(WINDOWING_MODE_PINNED);
+
mLockTaskController.startLockTaskMode(task, isSystemCaller, callingUid);
} finally {
Binder.restoreCallingIdentity(ident);
@@ -12756,6 +12865,12 @@
@GuardedBy("this")
final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated,
String abiOverride) {
+ return addAppLocked(info, customProcess, isolated, false /* disableHiddenApiChecks */,
+ abiOverride);
+ }
+
+ final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated,
+ boolean disableHiddenApiChecks, String abiOverride) {
ProcessRecord app;
if (!isolated) {
app = getProcessRecordLocked(customProcess != null ? customProcess : info.processName,
@@ -12787,7 +12902,8 @@
if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
mPersistentStartingProcesses.add(app);
startProcessLocked(app, "added application",
- customProcess != null ? customProcess : app.processName, abiOverride);
+ customProcess != null ? customProcess : app.processName, disableHiddenApiChecks,
+ abiOverride);
}
return app;
@@ -14592,6 +14708,7 @@
NETWORK_ACCESS_TIMEOUT_MS, NETWORK_ACCESS_TIMEOUT_DEFAULT_MS);
final boolean supportsLeanbackOnly =
mContext.getPackageManager().hasSystemFeature(FEATURE_LEANBACK_ONLY);
+ mHiddenApiBlacklist.registerObserver();
// Transfer any global setting for forcing RTL layout, into a System Property
SystemProperties.set(DEVELOPMENT_FORCE_RTL, forceRtl ? "1":"0");
@@ -18564,6 +18681,7 @@
final long myTotalPss = mi.getTotalPss();
final long myTotalSwapPss = mi.getTotalSwappedOutPss();
totalPss += myTotalPss;
+ totalSwapPss += myTotalSwapPss;
nativeProcTotalPss += myTotalPss;
MemItem pssItem = new MemItem(st.name + " (pid " + st.pid + ")",
@@ -21596,7 +21714,10 @@
mUsageStatsService.reportEvent(ii.targetPackage, userId,
UsageEvents.Event.SYSTEM_INTERACTION);
}
- ProcessRecord app = addAppLocked(ai, defProcess, false, abiOverride);
+ boolean disableHiddenApiChecks =
+ (flags & INSTRUMENTATION_FLAG_DISABLE_HIDDEN_API_CHECKS) != 0;
+ ProcessRecord app = addAppLocked(ai, defProcess, false, disableHiddenApiChecks,
+ abiOverride);
app.instr = activeInstr;
activeInstr.mFinished = false;
activeInstr.mRunningProcesses.add(app);
@@ -25697,9 +25818,11 @@
}
synchronized (ActivityManagerService.this) {
- return mActivityStartController.startActivitiesInPackage(packageUid, packageName,
+ return mActivityStartController.startActivitiesInPackage(
+ packageUid, packageName,
intents, resolvedTypes, null /* resultTo */,
- SafeActivityOptions.fromBundle(bOptions), userId);
+ SafeActivityOptions.fromBundle(bOptions), userId,
+ false /* validateIncomingUser */);
}
}
@@ -26306,4 +26429,20 @@
}
}
}
+
+ @Override
+ public void registerRemoteAnimationForNextActivityStart(String packageName,
+ RemoteAnimationAdapter adapter) throws RemoteException {
+ enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS,
+ "registerRemoteAnimationForNextActivityStart");
+ synchronized (this) {
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ mActivityStartController.registerRemoteAnimationForNextActivityStart(packageName,
+ adapter);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 24a77c7..fa0df56 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -2608,7 +2608,7 @@
pw.println(" specified then send to all users.");
pw.println(" --receiver-permission <PERMISSION>: Require receiver to hold permission.");
pw.println(" instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]");
- pw.println(" [--user <USER_ID> | current]");
+ pw.println(" [--user <USER_ID> | current] [--no-hidden-api-checks]");
pw.println(" [--no-window-animation] [--abi <ABI>] <COMPONENT>");
pw.println(" Start an Instrumentation. Typically this target <COMPONENT> is in the");
pw.println(" form <TEST_PACKAGE>/<RUNNER_CLASS> or only <TEST_PACKAGE> if there");
@@ -2626,6 +2626,7 @@
pw.println(" test runners.");
pw.println(" --user <USER_ID> | current: Specify user instrumentation runs in;");
pw.println(" current user if not specified.");
+ pw.println(" --no-hidden-api-checks: disable restrictions on use of hidden API.");
pw.println(" --no-window-animation: turn off window animations while running.");
pw.println(" --abi <ABI>: Launch the instrumented process with the selected ABI.");
pw.println(" This assumes that the process supports the selected ABI.");
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 9838851..ddba349 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -380,8 +380,9 @@
}
String getLifecycleDescription(String reason) {
- return "component:" + intent.getComponent().flattenToShortString() + ", state=" + state
- + ", reason=" + reason + ", time=" + System.currentTimeMillis();
+ return "name= " + this + ", component=" + intent.getComponent().flattenToShortString()
+ + ", package=" + packageName + ", state=" + state + ", reason=" + reason + ", time="
+ + System.currentTimeMillis();
}
void dump(PrintWriter pw, String prefix) {
@@ -2583,7 +2584,8 @@
if (andResume) {
lifecycleItem = ResumeActivityItem.obtain(service.isNextTransitionForward());
} else {
- lifecycleItem = PauseActivityItem.obtain();
+ lifecycleItem = PauseActivityItem.obtain()
+ .setDescription(getLifecycleDescription("relaunchActivityLocked"));
}
final ClientTransaction transaction = ClientTransaction.obtain(app.thread, appToken);
transaction.addCallback(callbackItem);
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 055a1aa..812de88 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1444,7 +1444,8 @@
mService.mLifecycleManager.scheduleTransaction(prev.app.thread, prev.appToken,
PauseActivityItem.obtain(prev.finishing, userLeaving,
- prev.configChangeFlags, pauseImmediately));
+ prev.configChangeFlags, pauseImmediately).setDescription(
+ prev.getLifecycleDescription("startPausingLocked")));
} catch (Exception e) {
// Ignore exception, if process died other code will cleanup.
Slog.w(TAG, "Exception thrown during pause", e);
@@ -1524,7 +1525,8 @@
if (r.finishing) {
if (DEBUG_PAUSE) Slog.v(TAG,
"Executing finish of failed to pause activity: " + r);
- finishCurrentActivityLocked(r, FINISH_AFTER_VISIBLE, false);
+ finishCurrentActivityLocked(r, FINISH_AFTER_VISIBLE, false,
+ "activityPausedLocked");
}
}
}
@@ -1541,7 +1543,8 @@
prev.state = ActivityState.PAUSED;
if (prev.finishing) {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Executing finish of activity: " + prev);
- prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE, false);
+ prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE, false,
+ "completedPausedLocked");
} else if (prev.app != null) {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueue pending stop if needed: " + prev
+ " wasStopping=" + wasStopping + " visible=" + prev.visible);
@@ -3673,8 +3676,8 @@
final int finishMode = (r.visible || r.nowVisible) ? FINISH_AFTER_VISIBLE
: FINISH_AFTER_PAUSE;
- final boolean removedActivity = finishCurrentActivityLocked(r, finishMode, oomAdj)
- == null;
+ final boolean removedActivity = finishCurrentActivityLocked(r, finishMode, oomAdj,
+ "finishActivityLocked") == null;
// The following code is an optimization. When the last non-task overlay activity
// is removed from the task, we remove the entire task from the stack. However,
@@ -3715,7 +3718,8 @@
static final int FINISH_AFTER_PAUSE = 1;
static final int FINISH_AFTER_VISIBLE = 2;
- final ActivityRecord finishCurrentActivityLocked(ActivityRecord r, int mode, boolean oomAdj) {
+ final ActivityRecord finishCurrentActivityLocked(ActivityRecord r, int mode, boolean oomAdj,
+ String reason) {
// First things first: if this activity is currently visible,
// and the resumed activity is not yet visible, then hold off on
// finishing until the resumed one becomes visible.
@@ -3758,7 +3762,7 @@
|| prevState == STOPPED
|| prevState == ActivityState.INITIALIZING) {
r.makeFinishingLocked();
- boolean activityRemoved = destroyActivityLocked(r, true, "finish-imm");
+ boolean activityRemoved = destroyActivityLocked(r, true, "finish-imm:" + reason);
if (finishingActivityInNonFocusedStack) {
// Finishing activity that was in paused state and it was in not currently focused
@@ -3794,7 +3798,8 @@
continue;
}
Slog.d(TAG, "finishAllActivitiesLocked: finishing " + r + " immediately");
- finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, false);
+ finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, false,
+ "finishAllActivitiesLocked");
}
}
if (noActivitiesInStack) {
@@ -4882,7 +4887,8 @@
+ r.intent.getComponent().flattenToShortString());
// Force the destroy to skip right to removal.
r.app = null;
- finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, false);
+ finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, false,
+ "handleAppCrashedLocked");
}
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 4928e90..5c30764 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1453,7 +1453,8 @@
lifecycleItem = ResumeActivityItem.obtain(mService.isNextTransitionForward())
.setDescription(r.getLifecycleDescription("realStartActivityLocked"));
} else {
- lifecycleItem = PauseActivityItem.obtain();
+ lifecycleItem = PauseActivityItem.obtain()
+ .setDescription(r.getLifecycleDescription("realStartActivityLocked"));
}
clientTransaction.setLifecycleStateRequest(lifecycleItem);
@@ -1955,7 +1956,8 @@
final ActivityStack stack = r.getStack();
if (stack != null) {
if (r.finishing) {
- stack.finishCurrentActivityLocked(r, ActivityStack.FINISH_IMMEDIATELY, false);
+ stack.finishCurrentActivityLocked(r, ActivityStack.FINISH_IMMEDIATELY, false,
+ "activityIdleInternalLocked");
} else {
stack.stopActivityLocked(r);
}
diff --git a/services/core/java/com/android/server/am/ActivityStartController.java b/services/core/java/com/android/server/am/ActivityStartController.java
index 5551914..868f90d 100644
--- a/services/core/java/com/android/server/am/ActivityStartController.java
+++ b/services/core/java/com/android/server/am/ActivityStartController.java
@@ -41,6 +41,7 @@
import android.os.Message;
import android.provider.Settings;
import android.util.Slog;
+import android.view.RemoteAnimationAdapter;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.am.ActivityStackSupervisor.PendingActivityLaunch;
@@ -85,6 +86,8 @@
private final Handler mHandler;
+ private final PendingRemoteAnimationRegistry mPendingRemoteAnimationRegistry;
+
private final class StartHandler extends Handler {
public StartHandler(Looper looper) {
super(looper, null, true);
@@ -123,6 +126,8 @@
mHandler = new StartHandler(mService.mHandlerThread.getLooper());
mFactory = factory;
mFactory.setController(this);
+ mPendingRemoteAnimationRegistry = new PendingRemoteAnimationRegistry(service,
+ service.mHandler);
}
/**
@@ -245,11 +250,25 @@
.execute();
}
+ /**
+ * Start intents as a package.
+ *
+ * @param uid Make a call as if this UID did.
+ * @param callingPackage Make a call as if this package did.
+ * @param intents Intents to start.
+ * @param userId Start the intents on this user.
+ * @param validateIncomingUser Set true to skip checking {@code userId} with the calling UID.
+ */
final int startActivitiesInPackage(int uid, String callingPackage, Intent[] intents,
- String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, int userId) {
+ String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, int userId,
+ boolean validateIncomingUser) {
final String reason = "startActivityInPackage";
- userId = mService.mUserController.handleIncomingUser(Binder.getCallingPid(),
- Binder.getCallingUid(), userId, false, ALLOW_FULL_ONLY, reason, null);
+ if (validateIncomingUser) {
+ userId = mService.mUserController.handleIncomingUser(Binder.getCallingPid(),
+ Binder.getCallingUid(), userId, false, ALLOW_FULL_ONLY, reason, null);
+ } else {
+ mService.mUserController.ensureNotSpecialUser(userId);
+ }
// TODO: Switch to user app stacks here.
return startActivities(null, uid, callingPackage, intents, resolvedTypes, resultTo, options,
userId, reason);
@@ -385,6 +404,15 @@
return mPendingActivityLaunches.size() < pendingLaunches;
}
+ void registerRemoteAnimationForNextActivityStart(String packageName,
+ RemoteAnimationAdapter adapter) {
+ mPendingRemoteAnimationRegistry.addPendingAnimation(packageName, adapter);
+ }
+
+ PendingRemoteAnimationRegistry getPendingRemoteAnimationRegistry() {
+ return mPendingRemoteAnimationRegistry;
+ }
+
void dump(PrintWriter pw, String prefix, String dumpPackage) {
pw.print(prefix);
pw.print("mLastHomeActivityStartResult=");
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 055b89b..8205265 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -708,6 +708,8 @@
ActivityOptions checkedOptions = options != null
? options.getOptions(intent, aInfo, callerApp, mSupervisor)
: null;
+ checkedOptions = mService.getActivityStartController().getPendingRemoteAnimationRegistry()
+ .overrideOptionsIfNeeded(callingPackage, checkedOptions);
if (mService.mController != null) {
try {
// The Intent we give to the watcher has the extra data
@@ -930,6 +932,7 @@
// Don't modify the client's object!
intent = new Intent(intent);
if (componentSpecified
+ && !(Intent.ACTION_VIEW.equals(intent.getAction()) && intent.getData() == null)
&& !Intent.ACTION_INSTALL_INSTANT_APP_PACKAGE.equals(intent.getAction())
&& !Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE.equals(intent.getAction())
&& mService.getPackageManagerInternalLocked()
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index ef82f36..fba0377 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -43,7 +43,10 @@
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
@@ -65,12 +68,13 @@
// There is some accuracy error in wifi reports so allow some slop in the results.
private static final long MAX_WIFI_STATS_SAMPLE_ERROR_MILLIS = 750;
- private final ExecutorService mExecutorService = Executors.newSingleThreadExecutor(
- (ThreadFactory) r -> {
- Thread t = new Thread(r, "batterystats-worker");
- t.setPriority(Thread.NORM_PRIORITY);
- return t;
- });
+ private final ScheduledExecutorService mExecutorService =
+ Executors.newSingleThreadScheduledExecutor(
+ (ThreadFactory) r -> {
+ Thread t = new Thread(r, "batterystats-worker");
+ t.setPriority(Thread.NORM_PRIORITY);
+ return t;
+ });
private final Context mContext;
private final BatteryStatsImpl mStats;
@@ -85,8 +89,20 @@
private String mCurrentReason = null;
@GuardedBy("this")
+ private boolean mOnBattery;
+
+ @GuardedBy("this")
+ private boolean mOnBatteryScreenOff;
+
+ @GuardedBy("this")
+ private boolean mUseLatestStates = true;
+
+ @GuardedBy("this")
private final IntArray mUidsToRemove = new IntArray();
+ @GuardedBy("this")
+ private Future<?> mWakelockChangesUpdate;
+
private final Object mWorkerLock = new Object();
@GuardedBy("mWorkerLock")
@@ -157,6 +173,50 @@
return null;
}
+ @Override
+ public Future<?> scheduleCpuSyncDueToScreenStateChange(
+ boolean onBattery, boolean onBatteryScreenOff) {
+ synchronized (BatteryExternalStatsWorker.this) {
+ if (mCurrentFuture == null || (mUpdateFlags & UPDATE_CPU) == 0) {
+ mOnBattery = onBattery;
+ mOnBatteryScreenOff = onBatteryScreenOff;
+ mUseLatestStates = false;
+ }
+ return scheduleSyncLocked("screen-state", UPDATE_CPU);
+ }
+ }
+
+ @Override
+ public Future<?> scheduleCpuSyncDueToWakelockChange(long delayMillis) {
+ if (mExecutorService.isShutdown()) {
+ return CompletableFuture.failedFuture(new IllegalStateException("worker shutdown"));
+ }
+
+ if (mWakelockChangesUpdate != null) {
+ // If there's already a scheduled task, leave it as is if we're trying to re-schedule
+ // it again with a delay, otherwise cancel and re-schedule it.
+ if (delayMillis == 0) {
+ mWakelockChangesUpdate.cancel(false);
+ } else {
+ return mWakelockChangesUpdate;
+ }
+ }
+
+ mWakelockChangesUpdate = mExecutorService.schedule(() -> {
+ scheduleSync("wakelock-change", UPDATE_CPU);
+ scheduleRunnable(() -> mStats.postBatteryNeedsCpuUpdateMsg());
+ mWakelockChangesUpdate = null;
+ }, delayMillis, TimeUnit.MILLISECONDS);
+ return mWakelockChangesUpdate;
+ }
+
+ @Override
+ public void cancelCpuSyncDueToWakelockChange() {
+ if (mWakelockChangesUpdate != null) {
+ mWakelockChangesUpdate.cancel(false);
+ }
+ }
+
public synchronized Future<?> scheduleWrite() {
if (mExecutorService.isShutdown()) {
return CompletableFuture.failedFuture(new IllegalStateException("worker shutdown"));
@@ -204,14 +264,21 @@
final int updateFlags;
final String reason;
final int[] uidsToRemove;
+ final boolean onBattery;
+ final boolean onBatteryScreenOff;
+ final boolean useLatestStates;
synchronized (BatteryExternalStatsWorker.this) {
updateFlags = mUpdateFlags;
reason = mCurrentReason;
uidsToRemove = mUidsToRemove.size() > 0 ? mUidsToRemove.toArray() : EmptyArray.INT;
+ onBattery = mOnBattery;
+ onBatteryScreenOff = mOnBatteryScreenOff;
+ useLatestStates = mUseLatestStates;
mUpdateFlags = 0;
mCurrentReason = null;
mUidsToRemove.clear();
mCurrentFuture = null;
+ mUseLatestStates = true;
}
synchronized (mWorkerLock) {
@@ -219,7 +286,8 @@
Slog.d(TAG, "begin updateExternalStatsSync reason=" + reason);
}
try {
- updateExternalStatsLocked(reason, updateFlags);
+ updateExternalStatsLocked(reason, updateFlags, onBattery,
+ onBatteryScreenOff, useLatestStates);
} finally {
if (DEBUG) {
Slog.d(TAG, "end updateExternalStatsSync");
@@ -250,7 +318,8 @@
};
@GuardedBy("mWorkerLock")
- private void updateExternalStatsLocked(final String reason, int updateFlags) {
+ private void updateExternalStatsLocked(final String reason, int updateFlags,
+ boolean onBattery, boolean onBatteryScreenOff, boolean useLatestStates) {
// We will request data from external processes asynchronously, and wait on a timeout.
SynchronousResultReceiver wifiReceiver = null;
SynchronousResultReceiver bluetoothReceiver = null;
@@ -306,7 +375,14 @@
reason, 0);
if ((updateFlags & UPDATE_CPU) != 0) {
- mStats.updateCpuTimeLocked();
+ if (useLatestStates) {
+ onBattery = mStats.isOnBatteryLocked();
+ onBatteryScreenOff = mStats.isOnBatteryScreenOffLocked();
+ }
+ mStats.updateCpuTimeLocked(onBattery, onBatteryScreenOff);
+ }
+
+ if ((updateFlags & UPDATE_ALL) != 0) {
mStats.updateKernelWakelocksLocked();
mStats.updateKernelMemoryBandwidthLocked();
}
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index ea52782..9d1adb2 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -1057,7 +1057,7 @@
// to block such a low level service like BatteryService on external stats like WiFi.
mWorker.scheduleRunnable(() -> {
synchronized (mStats) {
- final boolean onBattery = plugType == BatteryStatsImpl.BATTERY_PLUGGED_NONE;
+ final boolean onBattery = BatteryStatsImpl.isOnBattery(plugType, status);
if (mStats.isOnBattery() == onBattery) {
// The battery state has not changed, so we don't need to sync external
// stats immediately.
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 8e9d85d..264609f 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -335,7 +335,8 @@
allResolvedTypes[allResolvedTypes.length-1] = resolvedType;
res = owner.getActivityStartController().startActivitiesInPackage(
uid, key.packageName, allIntents, allResolvedTypes,
- resultTo, mergedOptions, userId);
+ resultTo, mergedOptions, userId,
+ true /* validateIncomingUser */);
} else {
res = owner.getActivityStartController().startActivityInPackage(uid,
callingPid, callingUid, key.packageName, finalIntent,
diff --git a/services/core/java/com/android/server/am/PendingRemoteAnimationRegistry.java b/services/core/java/com/android/server/am/PendingRemoteAnimationRegistry.java
new file mode 100644
index 0000000..77713f5
--- /dev/null
+++ b/services/core/java/com/android/server/am/PendingRemoteAnimationRegistry.java
@@ -0,0 +1,86 @@
+/*
+ * 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.am;
+
+import android.annotation.Nullable;
+import android.app.ActivityOptions;
+import android.os.Handler;
+import android.util.ArrayMap;
+import android.view.RemoteAnimationAdapter;
+
+/**
+ * Registry to keep track of remote animations to be run for activity starts from a certain package.
+ *
+ * @see ActivityManagerService#registerRemoteAnimationForNextActivityStart
+ */
+class PendingRemoteAnimationRegistry {
+
+ private static final long TIMEOUT_MS = 3000;
+
+ private final ArrayMap<String, Entry> mEntries = new ArrayMap<>();
+ private final Handler mHandler;
+ private final ActivityManagerService mService;
+
+ PendingRemoteAnimationRegistry(ActivityManagerService service, Handler handler) {
+ mService = service;
+ mHandler = handler;
+ }
+
+ /**
+ * Adds a remote animation to be run for all activity starts originating from a certain package.
+ */
+ void addPendingAnimation(String packageName, RemoteAnimationAdapter adapter) {
+ mEntries.put(packageName, new Entry(packageName, adapter));
+ }
+
+ /**
+ * Overrides the activity options with a registered remote animation for a certain calling
+ * package if such a remote animation is registered.
+ */
+ ActivityOptions overrideOptionsIfNeeded(String callingPackage,
+ @Nullable ActivityOptions options) {
+ final Entry entry = mEntries.get(callingPackage);
+ if (entry == null) {
+ return options;
+ }
+ if (options == null) {
+ options = ActivityOptions.makeRemoteAnimation(entry.adapter);
+ } else {
+ options.setRemoteAnimationAdapter(entry.adapter);
+ }
+ mEntries.remove(callingPackage);
+ return options;
+ }
+
+ private class Entry {
+ final String packageName;
+ final RemoteAnimationAdapter adapter;
+
+ Entry(String packageName, RemoteAnimationAdapter adapter) {
+ this.packageName = packageName;
+ this.adapter = adapter;
+ mHandler.postDelayed(() -> {
+ synchronized (mService) {
+ final Entry entry = mEntries.get(packageName);
+ if (entry == this) {
+ mEntries.remove(packageName);
+ }
+ }
+ }, TIMEOUT_MS);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/am/RecentsAnimation.java b/services/core/java/com/android/server/am/RecentsAnimation.java
index db4e09f..6dcf041 100644
--- a/services/core/java/com/android/server/am/RecentsAnimation.java
+++ b/services/core/java/com/android/server/am/RecentsAnimation.java
@@ -28,7 +28,9 @@
import android.content.ComponentName;
import android.content.Intent;
import android.os.Handler;
+import android.os.RemoteException;
import android.os.Trace;
+import android.util.Slog;
import android.view.IRecentsAnimationRunner;
import com.android.server.wm.RecentsAnimationController.RecentsAnimationCallbacks;
import com.android.server.wm.WindowManagerService;
@@ -63,6 +65,7 @@
mHandler = new Handler(mStackSupervisor.mLooper);
mWindowManager = wm;
mUserController = userController;
+
mCancelAnimationRunnable = () -> {
// The caller has not finished the animation in a predefined amount of time, so
// force-cancel the animation
@@ -73,13 +76,33 @@
void startRecentsActivity(Intent intent, IRecentsAnimationRunner recentsAnimationRunner,
ComponentName recentsComponent, int recentsUid) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "RecentsAnimation#startRecentsActivity");
+
+ if (!mWindowManager.canStartRecentsAnimation()) {
+ notifyAnimationCancelBeforeStart(recentsAnimationRunner);
+ return;
+ }
+
+ // If the existing home activity is already on top, then cancel
+ ActivityRecord homeActivity = mStackSupervisor.getHomeActivity();
+ final boolean hasExistingHomeActivity = homeActivity != null;
+ if (hasExistingHomeActivity) {
+ final ActivityDisplay display = homeActivity.getDisplay();
+ mRestoreHomeBehindStack = display.getStackAboveHome();
+ if (mRestoreHomeBehindStack == null) {
+ notifyAnimationCancelBeforeStart(recentsAnimationRunner);
+ return;
+ }
+ }
+
mWindowManager.deferSurfaceLayout();
try {
- // Cancel the previous recents animation if necessary
- mWindowManager.cancelRecentsAnimation();
- final boolean hasExistingHomeActivity = mStackSupervisor.getHomeActivity() != null;
- if (!hasExistingHomeActivity) {
+ final ActivityDisplay display;
+ if (hasExistingHomeActivity) {
+ // Move the home activity into place for the animation if it is not already top most
+ display = homeActivity.getDisplay();
+ display.moveHomeStackBehindBottomMostVisibleStack();
+ } else {
// No home activity
final ActivityOptions opts = ActivityOptions.makeBasic();
opts.setLaunchActivityType(ACTIVITY_TYPE_HOME);
@@ -95,25 +118,20 @@
.execute();
mWindowManager.prepareAppTransition(TRANSIT_NONE, false);
+ homeActivity = mStackSupervisor.getHomeActivity();
+ display = homeActivity.getDisplay();
+
// TODO: Maybe wait for app to draw in this particular case?
}
- final ActivityRecord homeActivity = mStackSupervisor.getHomeActivity();
- final ActivityDisplay display = homeActivity.getDisplay();
-
- // Save the initial position of the home activity stack to be restored to after the
- // animation completes
- mRestoreHomeBehindStack = hasExistingHomeActivity
- ? display.getStackAboveHome()
- : null;
-
- // Move the home activity into place for the animation
- display.moveHomeStackBehindBottomMostVisibleStack();
-
// Mark the home activity as launch-behind to bump its visibility for the
// duration of the gesture that is driven by the recents component
homeActivity.mLaunchTaskBehind = true;
+ // Post a timeout for the animation. This needs to happen before initializing the
+ // recents animation on the WM side since we may decide to cancel the animation there
+ mHandler.postDelayed(mCancelAnimationRunnable, RECENTS_ANIMATION_TIMEOUT);
+
// Fetch all the surface controls and pass them to the client to get the animation
// started
mWindowManager.initializeRecentsAnimation(recentsAnimationRunner, this,
@@ -122,9 +140,6 @@
// If we updated the launch-behind state, update the visibility of the activities after
// we fetch the visible tasks to be controlled by the animation
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, PRESERVE_WINDOWS);
-
- // Post a timeout for the animation
- mHandler.postDelayed(mCancelAnimationRunnable, RECENTS_ANIMATION_TIMEOUT);
} finally {
mWindowManager.continueSurfaceLayout();
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
@@ -178,4 +193,15 @@
});
}
}
+
+ /**
+ * Called only when the animation should be canceled prior to starting.
+ */
+ private void notifyAnimationCancelBeforeStart(IRecentsAnimationRunner recentsAnimationRunner) {
+ try {
+ recentsAnimationRunner.onAnimationCanceled();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to cancel recents animation before start", e);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/am/UriPermission.java b/services/core/java/com/android/server/am/UriPermission.java
index 1e071aa..3bf1cf4 100644
--- a/services/core/java/com/android/server/am/UriPermission.java
+++ b/services/core/java/com/android/server/am/UriPermission.java
@@ -124,6 +124,10 @@
updateModeFlags();
}
+ boolean isNew() {
+ return persistedCreateTime == INVALID_TIME;
+ }
+
void grantModes(int modeFlags, UriPermissionOwner owner) {
final boolean persistable = (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0;
modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index d54e264..bfc787e 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -1489,9 +1489,8 @@
}
}
}
- if (!allowAll && targetUserId < 0) {
- throw new IllegalArgumentException(
- "Call does not support special user #" + targetUserId);
+ if (!allowAll) {
+ ensureNotSpecialUser(targetUserId);
}
// Check shell permission
if (callingUid == Process.SHELL_UID && targetUserId >= UserHandle.USER_SYSTEM) {
@@ -1508,6 +1507,13 @@
? getCurrentUserId(): userId;
}
+ void ensureNotSpecialUser(int userId) {
+ if (userId >= 0) {
+ return;
+ }
+ throw new IllegalArgumentException("Call does not support special user #" + userId);
+ }
+
void registerUserSwitchObserver(IUserSwitchObserver observer, String name) {
Preconditions.checkNotNull(name, "Observer name cannot be null");
if (mInjector.checkCallingPermission(INTERACT_ACROSS_USERS_FULL)
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index e95608f..76e0d89 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -70,6 +70,7 @@
import android.media.AudioSystem;
import android.media.IAudioFocusDispatcher;
import android.media.IAudioRoutesObserver;
+import android.media.IAudioServerStateDispatcher;
import android.media.IAudioService;
import android.media.IPlaybackConfigDispatcher;
import android.media.IRecordingConfigDispatcher;
@@ -242,6 +243,7 @@
private static final int MSG_INDICATE_SYSTEM_READY = 26;
private static final int MSG_ACCESSORY_PLUG_MEDIA_UNMUTE = 27;
private static final int MSG_NOTIFY_VOL_EVENT = 28;
+ private static final int MSG_DISPATCH_AUDIO_SERVER_STATE = 29;
// start of messages handled under wakelock
// these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
// and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
@@ -390,6 +392,8 @@
case AudioSystem.AUDIO_STATUS_SERVER_DIED:
sendMsg(mAudioHandler, MSG_AUDIO_SERVER_DIED,
SENDMSG_NOOP, 0, 0, null, 0);
+ sendMsg(mAudioHandler, MSG_DISPATCH_AUDIO_SERVER_STATE,
+ SENDMSG_QUEUE, 0, 0, null, 0);
break;
default:
break;
@@ -547,8 +551,6 @@
// Used to play ringtones outside system_server
private volatile IRingtonePlayer mRingtonePlayer;
- private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
-
// Request to override default use of A2DP for media.
private boolean mBluetoothA2dpEnabled;
private final Object mBluetoothA2dpEnabledLock = new Object();
@@ -567,8 +569,6 @@
AudioSystem.DEVICE_OUT_AUX_LINE;
int mFullVolumeDevices = 0;
- // TODO merge orientation and rotation
- private final boolean mMonitorOrientation;
private final boolean mMonitorRotation;
private boolean mDockAudioMediaEnabled = true;
@@ -784,13 +784,6 @@
intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
- // TODO merge orientation and rotation
- mMonitorOrientation = SystemProperties.getBoolean("ro.audio.monitorOrientation", false);
- if (mMonitorOrientation) {
- Log.v(TAG, "monitoring device orientation");
- // initialize orientation in AudioSystem
- setOrientationForAudioSystem();
- }
mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false);
if (mMonitorRotation) {
RotationHelper.init(mContext, mAudioHandler);
@@ -959,10 +952,7 @@
// Restore ringer mode
setRingerModeInt(getRingerModeInternal(), false);
- // Reset device orientation (if monitored for this device)
- if (mMonitorOrientation) {
- setOrientationForAudioSystem();
- }
+ // Reset device rotation (if monitored for this device)
if (mMonitorRotation) {
RotationHelper.updateOrientation();
}
@@ -1000,6 +990,21 @@
onIndicateSystemReady();
// indicate the end of reconfiguration phase to audio HAL
AudioSystem.setParameters("restarting=false");
+
+ sendMsg(mAudioHandler, MSG_DISPATCH_AUDIO_SERVER_STATE,
+ SENDMSG_QUEUE, 1, 0, null, 0);
+ }
+
+ private void onDispatchAudioServerStateChange(boolean state) {
+ synchronized (mAudioServerStateListeners) {
+ for (AsdProxy asdp : mAudioServerStateListeners.values()) {
+ try {
+ asdp.callback().dispatchAudioServerStateChange(state);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Could not call dispatchAudioServerStateChange()", e);
+ }
+ }
+ }
}
private void createAudioSystemThread() {
@@ -1023,14 +1028,16 @@
}
private void checkAllAliasStreamVolumes() {
- synchronized (VolumeStreamState.class) {
- int numStreamTypes = AudioSystem.getNumStreamTypes();
- for (int streamType = 0; streamType < numStreamTypes; streamType++) {
- mStreamStates[streamType]
- .setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]], TAG);
- // apply stream volume
- if (!mStreamStates[streamType].mIsMuted) {
- mStreamStates[streamType].applyAllVolumes();
+ synchronized (mSettingsLock) {
+ synchronized (VolumeStreamState.class) {
+ int numStreamTypes = AudioSystem.getNumStreamTypes();
+ for (int streamType = 0; streamType < numStreamTypes; streamType++) {
+ mStreamStates[streamType]
+ .setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]], TAG);
+ // apply stream volume
+ if (!mStreamStates[streamType].mIsMuted) {
+ mStreamStates[streamType].applyAllVolumes();
+ }
}
}
}
@@ -1136,13 +1143,16 @@
if (updateVolumes && mStreamStates != null) {
updateDefaultVolumes();
- mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias],
- caller);
-
- mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].mVolumeIndexSettingName =
- System.VOLUME_SETTINGS_INT[a11yStreamAlias];
- mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].setAllIndexes(
- mStreamStates[a11yStreamAlias], caller);
+ synchronized (mSettingsLock) {
+ synchronized (VolumeStreamState.class) {
+ mStreamStates[AudioSystem.STREAM_DTMF]
+ .setAllIndexes(mStreamStates[dtmfStreamAlias], caller);
+ mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].mVolumeIndexSettingName =
+ System.VOLUME_SETTINGS_INT[a11yStreamAlias];
+ mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].setAllIndexes(
+ mStreamStates[a11yStreamAlias], caller);
+ }
+ }
if (sIndependentA11yVolume) {
// restore the a11y values from the settings
mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].readSettings();
@@ -4585,39 +4595,36 @@
* @param srcStream
* @param caller
*/
+ // must be sync'd on mSettingsLock before VolumeStreamState.class
+ @GuardedBy("VolumeStreamState.class")
public void setAllIndexes(VolumeStreamState srcStream, String caller) {
if (mStreamType == srcStream.mStreamType) {
return;
}
- synchronized (mSettingsLock) {
- synchronized (VolumeStreamState.class) {
- int srcStreamType = srcStream.getStreamType();
- // apply default device volume from source stream to all devices first in case
- // some devices are present in this stream state but not in source stream state
- int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
- index = rescaleIndex(index, srcStreamType, mStreamType);
- for (int i = 0; i < mIndexMap.size(); i++) {
- mIndexMap.put(mIndexMap.keyAt(i), index);
- }
- // Now apply actual volume for devices in source stream state
- SparseIntArray srcMap = srcStream.mIndexMap;
- for (int i = 0; i < srcMap.size(); i++) {
- int device = srcMap.keyAt(i);
- index = srcMap.valueAt(i);
- index = rescaleIndex(index, srcStreamType, mStreamType);
+ int srcStreamType = srcStream.getStreamType();
+ // apply default device volume from source stream to all devices first in case
+ // some devices are present in this stream state but not in source stream state
+ int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
+ index = rescaleIndex(index, srcStreamType, mStreamType);
+ for (int i = 0; i < mIndexMap.size(); i++) {
+ mIndexMap.put(mIndexMap.keyAt(i), index);
+ }
+ // Now apply actual volume for devices in source stream state
+ SparseIntArray srcMap = srcStream.mIndexMap;
+ for (int i = 0; i < srcMap.size(); i++) {
+ int device = srcMap.keyAt(i);
+ index = srcMap.valueAt(i);
+ index = rescaleIndex(index, srcStreamType, mStreamType);
- setIndex(index, device, caller);
- }
- }
+ setIndex(index, device, caller);
}
}
- @GuardedBy("mSettingsLock")
+ // must be sync'd on mSettingsLock before VolumeStreamState.class
+ @GuardedBy("VolumeStreamState.class")
public void setAllIndexesToMax() {
- synchronized (VolumeStreamState.class) {
- for (int i = 0; i < mIndexMap.size(); i++) {
- mIndexMap.put(mIndexMap.keyAt(i), mIndexMax);
- }
+ for (int i = 0; i < mIndexMap.size(); i++) {
+ mIndexMap.put(mIndexMap.keyAt(i), mIndexMax);
}
}
@@ -5089,6 +5096,10 @@
onAudioServerDied();
break;
+ case MSG_DISPATCH_AUDIO_SERVER_STATE:
+ onDispatchAudioServerStateChange(msg.arg1 == 1);
+ break;
+
case MSG_UNLOAD_SOUND_EFFECTS:
onUnloadSoundEffects();
break;
@@ -6169,24 +6180,15 @@
// Device orientation
//==========================================================================================
/**
- * Handles device configuration changes that may map to a change in the orientation
- * or orientation.
- * Monitoring orientation and rotation is optional, and is defined by the definition and value
- * of the "ro.audio.monitorOrientation" and "ro.audio.monitorRotation" system properties.
+ * Handles device configuration changes that may map to a change in rotation.
+ * Monitoring rotation is optional, and is defined by the definition and value
+ * of the "ro.audio.monitorRotation" system property.
*/
private void handleConfigurationChanged(Context context) {
try {
- // reading new orientation "safely" (i.e. under try catch) in case anything
- // goes wrong when obtaining resources and configuration
+ // reading new configuration "safely" (i.e. under try catch) in case anything
+ // goes wrong.
Configuration config = context.getResources().getConfiguration();
- // TODO merge rotation and orientation
- if (mMonitorOrientation) {
- int newOrientation = config.orientation;
- if (newOrientation != mDeviceOrientation) {
- mDeviceOrientation = newOrientation;
- setOrientationForAudioSystem();
- }
- }
sendMsg(mAudioHandler,
MSG_CONFIGURE_SAFE_MEDIA_VOLUME,
SENDMSG_REPLACE,
@@ -6201,15 +6203,17 @@
mCameraSoundForced = cameraSoundForced;
if (cameraSoundForcedChanged) {
if (!mIsSingleVolume) {
- VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
- if (cameraSoundForced) {
- s.setAllIndexesToMax();
- mRingerModeAffectedStreams &=
- ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
- } else {
- s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM], TAG);
- mRingerModeAffectedStreams |=
- (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
+ synchronized (VolumeStreamState.class) {
+ VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
+ if (cameraSoundForced) {
+ s.setAllIndexesToMax();
+ mRingerModeAffectedStreams &=
+ ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
+ } else {
+ s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM], TAG);
+ mRingerModeAffectedStreams |=
+ (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
+ }
}
// take new state into account for streams muted by ringer mode
setRingerModeInt(getRingerModeInternal(), false);
@@ -6238,30 +6242,6 @@
}
}
- //TODO move to an external "orientation helper" class
- private void setOrientationForAudioSystem() {
- switch (mDeviceOrientation) {
- case Configuration.ORIENTATION_LANDSCAPE:
- //Log.i(TAG, "orientation is landscape");
- AudioSystem.setParameters("orientation=landscape");
- break;
- case Configuration.ORIENTATION_PORTRAIT:
- //Log.i(TAG, "orientation is portrait");
- AudioSystem.setParameters("orientation=portrait");
- break;
- case Configuration.ORIENTATION_SQUARE:
- //Log.i(TAG, "orientation is square");
- AudioSystem.setParameters("orientation=square");
- break;
- case Configuration.ORIENTATION_UNDEFINED:
- //Log.i(TAG, "orientation is undefined");
- AudioSystem.setParameters("orientation=undefined");
- break;
- default:
- Log.e(TAG, "Unknown orientation");
- }
- }
-
// Handles request to override default use of A2DP for media.
// Must be called synchronized on mConnectedDevices
public void setBluetoothA2dpOnInt(boolean on, String eventSource) {
@@ -7341,6 +7321,77 @@
//======================
+ // Audioserver state displatch
+ //======================
+ private class AsdProxy implements IBinder.DeathRecipient {
+ private final IAudioServerStateDispatcher mAsd;
+
+ AsdProxy(IAudioServerStateDispatcher asd) {
+ mAsd = asd;
+ }
+
+ public void binderDied() {
+ synchronized (mAudioServerStateListeners) {
+ mAudioServerStateListeners.remove(mAsd.asBinder());
+ }
+ }
+
+ IAudioServerStateDispatcher callback() {
+ return mAsd;
+ }
+ }
+
+ private HashMap<IBinder, AsdProxy> mAudioServerStateListeners =
+ new HashMap<IBinder, AsdProxy>();
+
+ private void checkMonitorAudioServerStatePermission() {
+ if (!(mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.MODIFY_PHONE_STATE) ==
+ PackageManager.PERMISSION_GRANTED ||
+ mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.MODIFY_AUDIO_ROUTING) ==
+ PackageManager.PERMISSION_GRANTED)) {
+ throw new SecurityException("Not allowed to monitor audioserver state");
+ }
+ }
+
+ public void registerAudioServerStateDispatcher(IAudioServerStateDispatcher asd) {
+ checkMonitorAudioServerStatePermission();
+ synchronized (mAudioServerStateListeners) {
+ if (mAudioServerStateListeners.containsKey(asd.asBinder())) {
+ Slog.w(TAG, "Cannot re-register audio server state dispatcher");
+ return;
+ }
+ AsdProxy asdp = new AsdProxy(asd);
+ try {
+ asd.asBinder().linkToDeath(asdp, 0/*flags*/);
+ } catch (RemoteException e) {
+
+ }
+ mAudioServerStateListeners.put(asd.asBinder(), asdp);
+ }
+ }
+
+ public void unregisterAudioServerStateDispatcher(IAudioServerStateDispatcher asd) {
+ checkMonitorAudioServerStatePermission();
+ synchronized (mAudioServerStateListeners) {
+ AsdProxy asdp = mAudioServerStateListeners.remove(asd.asBinder());
+ if (asdp == null) {
+ Slog.w(TAG, "Trying to unregister unknown audioserver state dispatcher for pid "
+ + Binder.getCallingPid() + " / uid " + Binder.getCallingUid());
+ return;
+ } else {
+ asd.asBinder().unlinkToDeath(asdp, 0/*flags*/);
+ }
+ }
+ }
+
+ public boolean isAudioServerRunning() {
+ checkMonitorAudioServerStatePermission();
+ return (AudioSystem.checkAudioFlinger() == AudioSystem.AUDIO_STATUS_OK);
+ }
+
+ //======================
// misc
//======================
private HashMap<IBinder, AudioPolicyProxy> mAudioPolicies =
diff --git a/services/core/java/com/android/server/audio/OWNERS b/services/core/java/com/android/server/audio/OWNERS
new file mode 100644
index 0000000..b70de29
--- /dev/null
+++ b/services/core/java/com/android/server/audio/OWNERS
@@ -0,0 +1,2 @@
+jmtrivi@google.com
+elaurent@google.com
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 85b70ca..a24f97e 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -392,6 +392,15 @@
return !isVPN() && numForegroundNetworkRequests() == 0 && mNumBackgroundNetworkRequests > 0;
}
+ /**
+ * Returns whether this network is currently suspended. A network is suspended if it is still
+ * connected but data temporarily fails to transfer. See {@link NetworkInfo.State#SUSPENDED}
+ * and {@link NetworkCapabilities#NET_CAPABILITY_NOT_SUSPENDED}.
+ */
+ public boolean isSuspended() {
+ return networkInfo.getState() == NetworkInfo.State.SUSPENDED;
+ }
+
// Does this network satisfy request?
public boolean satisfies(NetworkRequest request) {
return created &&
@@ -458,7 +467,7 @@
public NetworkState getNetworkState() {
synchronized (this) {
- // Network objects are outwardly immutable so there is no point to duplicating.
+ // Network objects are outwardly immutable so there is no point in duplicating.
// Duplicating also precludes sharing socket factories and connection pools.
final String subscriberId = (networkMisc != null) ? networkMisc.subscriberId : null;
return new NetworkState(new NetworkInfo(networkInfo),
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index c3f020a..95a0246 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -97,9 +97,7 @@
@Override
public void onBootPhase(int phase) {
- if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
- mService.systemReady();
- }
+ mService.onBootPhase(phase);
}
@@ -300,8 +298,15 @@
localeFilter, null, null);
}
- void systemReady() {
- getSyncManager();
+ void onBootPhase(int phase) {
+ switch (phase) {
+ case SystemService.PHASE_SYSTEM_SERVICES_READY:
+ getSyncManager();
+ break;
+ }
+ if (mSyncManager != null) {
+ mSyncManager.onBootPhase(phase);
+ }
}
/**
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index de17ec7..d87a1bb 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -89,6 +89,7 @@
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.util.ArrayUtils;
import com.android.server.LocalServices;
+import com.android.server.SystemService;
import com.android.server.job.JobSchedulerInternal;
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
@@ -102,7 +103,6 @@
import com.android.server.content.SyncStorageEngine.AuthorityInfo;
import com.android.server.content.SyncStorageEngine.EndPoint;
import com.android.server.content.SyncStorageEngine.OnSyncRequestListener;
-import com.android.server.job.JobSchedulerInternal.JobStorePersistStats;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -158,18 +158,6 @@
}
/**
- * When retrying a sync for the first time use this delay. After that
- * the retry time will double until it reached MAX_SYNC_RETRY_TIME.
- * In milliseconds.
- */
- private static final long INITIAL_SYNC_RETRY_TIME_IN_MS = 30 * 1000; // 30 seconds
-
- /**
- * Default the max sync retry time to this value.
- */
- private static final long DEFAULT_MAX_SYNC_RETRY_TIME_IN_SECONDS = 60 * 60; // one hour
-
- /**
* How long to wait before retrying a sync that failed due to one already being in progress.
*/
private static final int DELAY_RETRY_SYNC_IN_PROGRESS_IN_SECONDS = 10;
@@ -449,6 +437,7 @@
};
private final SyncHandler mSyncHandler;
+ private final SyncManagerConstants mConstants;
private volatile boolean mBootCompleted = false;
private volatile boolean mJobServiceReady = false;
@@ -616,6 +605,7 @@
}, mSyncHandler);
mRand = new Random(System.currentTimeMillis());
+ mConstants = new SyncManagerConstants(context);
IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
context.registerReceiver(mConnectivityIntentReceiver, intentFilter);
@@ -756,6 +746,14 @@
mSyncHandler.post(() -> mLogger.log("onStopUser: user=", userHandle));
}
+ public void onBootPhase(int phase) {
+ // Note SyncManager only receives PHASE_SYSTEM_SERVICES_READY and after.
+ switch (phase) {
+ case SystemService.PHASE_SYSTEM_SERVICES_READY:
+ mConstants.start();
+ break;
+ }
+ }
private void whiteListExistingSyncAdaptersIfNeeded() {
if (!mSyncStorageEngine.shouldGrantSyncAdaptersAccountAccess()) {
@@ -903,7 +901,10 @@
}
if (isLoggable) {
Log.d(TAG, "one-time sync for: " + requestedAccount + " " + extras.toString() + " "
- + requestedAuthority);
+ + requestedAuthority
+ + " reason=" + reason
+ + " checkIfAccountReady=" + checkIfAccountReady
+ + " isAppStandbyExempted=" + isAppStandbyExempted);
}
AccountAndUser[] accounts = null;
@@ -1368,18 +1369,18 @@
return;
}
// Subsequent delays are the double of the previous delay.
- newDelayInMs = previousSettings.second * 2;
+ newDelayInMs =
+ (long) (previousSettings.second * mConstants.getRetryTimeIncreaseFactor());
}
if (newDelayInMs <= 0) {
// The initial delay is the jitterized INITIAL_SYNC_RETRY_TIME_IN_MS.
- newDelayInMs = jitterize(INITIAL_SYNC_RETRY_TIME_IN_MS,
- (long)(INITIAL_SYNC_RETRY_TIME_IN_MS * 1.1));
+ final long initialRetryMs = mConstants.getInitialSyncRetryTimeInSeconds() * 1000;
+ newDelayInMs = jitterize(initialRetryMs, (long)(initialRetryMs * 1.1));
}
// Cap the delay.
- long maxSyncRetryTimeInSeconds = Settings.Global.getLong(mContext.getContentResolver(),
- Settings.Global.SYNC_MAX_RETRY_DELAY_IN_SECONDS,
- DEFAULT_MAX_SYNC_RETRY_TIME_IN_SECONDS);
+ final long maxSyncRetryTimeInSeconds = mConstants.getMaxSyncRetryTimeInSeconds();
+
if (newDelayInMs > maxSyncRetryTimeInSeconds * 1000) {
newDelayInMs = maxSyncRetryTimeInSeconds * 1000;
}
@@ -1930,6 +1931,7 @@
protected void dump(FileDescriptor fd, PrintWriter pw, boolean dumpAll) {
final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
dumpSyncState(ipw);
+ mConstants.dump(pw, "");
dumpSyncAdapters(ipw);
if (dumpAll) {
@@ -3573,7 +3575,13 @@
reschedulePeriodicSyncH(syncOperation);
}
} else {
- Log.d(TAG, "failed sync operation " + syncOperation + ", " + syncResult);
+ Log.w(TAG, "failed sync operation " + syncOperation + ", " + syncResult);
+
+ syncOperation.retries++;
+ if (syncOperation.retries > mConstants.getMaxRetriesWithAppStandbyExemption()) {
+ syncOperation.isAppStandbyExempted = false;
+ }
+
// the operation failed so increase the backoff time
increaseBackoffSetting(syncOperation.target);
if (!syncOperation.isPeriodic) {
diff --git a/services/core/java/com/android/server/content/SyncManagerConstants.java b/services/core/java/com/android/server/content/SyncManagerConstants.java
new file mode 100644
index 0000000..3139d54
--- /dev/null
+++ b/services/core/java/com/android/server/content/SyncManagerConstants.java
@@ -0,0 +1,150 @@
+/*
+ * 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.content;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.provider.Settings;
+import android.provider.Settings.Global;
+import android.util.KeyValueListParser;
+import android.util.Slog;
+
+import com.android.internal.os.BackgroundThread;
+
+import java.io.PrintWriter;
+
+public class SyncManagerConstants extends ContentObserver {
+ private static final String TAG = "SyncManagerConfig";
+
+ private final Object mLock = new Object();
+ private final Context mContext;
+
+ private static final String KEY_INITIAL_SYNC_RETRY_TIME_IN_SECONDS =
+ "initial_sync_retry_time_in_seconds";
+ private static final int DEF_INITIAL_SYNC_RETRY_TIME_IN_SECONDS = 30;
+ private int mInitialSyncRetryTimeInSeconds = DEF_INITIAL_SYNC_RETRY_TIME_IN_SECONDS;
+
+ private static final String KEY_RETRY_TIME_INCREASE_FACTOR =
+ "retry_time_increase_factor";
+ private static final float DEF_RETRY_TIME_INCREASE_FACTOR = 2.0f;
+ private float mRetryTimeIncreaseFactor = DEF_RETRY_TIME_INCREASE_FACTOR;
+
+ private static final String KEY_MAX_SYNC_RETRY_TIME_IN_SECONDS =
+ "max_sync_retry_time_in_seconds";
+ private static final int DEF_MAX_SYNC_RETRY_TIME_IN_SECONDS = 60 * 60;
+ private int mMaxSyncRetryTimeInSeconds = DEF_MAX_SYNC_RETRY_TIME_IN_SECONDS;
+
+ private static final String KEY_MAX_RETRIES_WITH_APP_STANDBY_EXEMPTION =
+ "max_retries_with_app_standby_exemption";
+ private static final int DEF_MAX_RETRIES_WITH_APP_STANDBY_EXEMPTION = 5;
+ private int mMaxRetriesWithAppStandbyExemption = DEF_MAX_RETRIES_WITH_APP_STANDBY_EXEMPTION;
+
+ protected SyncManagerConstants(Context context) {
+ super(null);
+ mContext = context;
+ refresh();
+ }
+
+ public void start() {
+ BackgroundThread.getHandler().post(() -> {
+ mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor(
+ Settings.Global.SYNC_MANAGER_CONSTANTS), false, this);
+ refresh();
+ });
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ refresh();
+ }
+
+ private void refresh() {
+ synchronized (mLock) {
+
+ String newValue = Settings.Global.getString(mContext.getContentResolver(),
+ Global.SYNC_MANAGER_CONSTANTS);
+ final KeyValueListParser parser = new KeyValueListParser(',');
+ try {
+ parser.setString(newValue);
+ } catch (IllegalArgumentException e) {
+ Slog.wtf(TAG, "Bad constants: " + newValue);
+ }
+
+ mInitialSyncRetryTimeInSeconds = parser.getInt(
+ KEY_INITIAL_SYNC_RETRY_TIME_IN_SECONDS,
+ DEF_INITIAL_SYNC_RETRY_TIME_IN_SECONDS);
+
+ mMaxSyncRetryTimeInSeconds = parser.getInt(
+ KEY_MAX_SYNC_RETRY_TIME_IN_SECONDS,
+ DEF_MAX_SYNC_RETRY_TIME_IN_SECONDS);
+
+ mRetryTimeIncreaseFactor = parser.getFloat(
+ KEY_RETRY_TIME_INCREASE_FACTOR,
+ DEF_RETRY_TIME_INCREASE_FACTOR);
+
+ mMaxRetriesWithAppStandbyExemption = parser.getInt(
+ KEY_MAX_RETRIES_WITH_APP_STANDBY_EXEMPTION,
+ DEF_MAX_RETRIES_WITH_APP_STANDBY_EXEMPTION);
+ }
+ }
+
+ public int getInitialSyncRetryTimeInSeconds() {
+ synchronized (mLock) {
+ return mInitialSyncRetryTimeInSeconds;
+ }
+ }
+
+ public float getRetryTimeIncreaseFactor() {
+ synchronized (mLock) {
+ return mRetryTimeIncreaseFactor;
+ }
+ }
+
+ public int getMaxSyncRetryTimeInSeconds() {
+ synchronized (mLock) {
+ return mMaxSyncRetryTimeInSeconds;
+ }
+ }
+
+ public int getMaxRetriesWithAppStandbyExemption() {
+ synchronized (mLock) {
+ return mMaxRetriesWithAppStandbyExemption;
+ }
+ }
+
+ public void dump(PrintWriter pw, String prefix) {
+ synchronized (mLock) {
+ pw.print(prefix);
+ pw.println("SyncManager Config:");
+
+ pw.print(prefix);
+ pw.print(" mInitialSyncRetryTimeInSeconds=");
+ pw.println(mInitialSyncRetryTimeInSeconds);
+
+ pw.print(prefix);
+ pw.print(" mRetryTimeIncreaseFactor=");
+ pw.println(mRetryTimeIncreaseFactor);
+
+ pw.print(prefix);
+ pw.print(" mMaxSyncRetryTimeInSeconds=");
+ pw.println(mMaxSyncRetryTimeInSeconds);
+
+ pw.print(prefix);
+ pw.print(" mMaxRetriesWithAppStandbyExemption=");
+ pw.println(mMaxRetriesWithAppStandbyExemption);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/content/SyncOperation.java b/services/core/java/com/android/server/content/SyncOperation.java
index f6b4819..96bdaea 100644
--- a/services/core/java/com/android/server/content/SyncOperation.java
+++ b/services/core/java/com/android/server/content/SyncOperation.java
@@ -408,6 +408,10 @@
extrasToStringBuilder(extras, sb);
}
}
+ if (retries > 0) {
+ sb.append(" Retries=");
+ sb.append(retries);
+ }
return sb.toString();
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 23de592..fa39ce4 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -500,6 +500,7 @@
}
public void onSwitchUser(@UserIdInt int newUserId) {
+ handleSettingsChange();
mBrightnessTracker.onSwitchUser(newUserId);
}
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index b5f94b1..3da3551 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -915,7 +915,7 @@
notifyLockoutResetMonitors();
}
- private class FingerprintServiceLockoutResetMonitor {
+ private class FingerprintServiceLockoutResetMonitor implements IBinder.DeathRecipient {
private static final long WAKELOCK_TIMEOUT_MS = 2000;
private final IFingerprintServiceLockoutResetCallback mCallback;
@@ -926,6 +926,11 @@
mCallback = callback;
mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"lockout reset callback");
+ try {
+ mCallback.asBinder().linkToDeath(FingerprintServiceLockoutResetMonitor.this, 0);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "caught remote exception in linkToDeath", e);
+ }
}
public void sendLockoutReset() {
@@ -959,6 +964,12 @@
removeLockoutResetCallback(FingerprintServiceLockoutResetMonitor.this);
}
};
+
+ @Override
+ public void binderDied() {
+ Slog.e(TAG, "Lockout reset callback binder died");
+ mHandler.post(mRemoveCallbackRunnable);
+ }
}
private IBiometricsFingerprintClientCallback mDaemonCallback =
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 47a4fb2..c33d7f4 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -23,6 +23,7 @@
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
+import android.app.AlarmManager;
import android.app.AppGlobals;
import android.app.IUidObserver;
import android.app.job.IJobScheduler;
@@ -184,6 +185,7 @@
IBatteryStats mBatteryStats;
DeviceIdleController.LocalService mLocalDeviceIdleController;
AppStateTracker mAppStateTracker;
+ final UsageStatsManagerInternal mUsageStats;
/**
* Set to true once we are allowed to run third party apps.
@@ -225,7 +227,10 @@
*/
final long[] mNextBucketHeartbeat = { 0, 0, 0, 0, Long.MAX_VALUE };
long mHeartbeat = 0;
- long mLastHeartbeatTime = 0;
+ long mLastHeartbeatTime = sElapsedRealtimeClock.millis();
+
+ static final String HEARTBEAT_TAG = "*job.heartbeat*";
+ final HeartbeatAlarmListener mHeartbeatAlarm = new HeartbeatAlarmListener();
// -- Pre-allocated temporaries only for use in assignJobsToContextsLocked --
@@ -495,6 +500,9 @@
STANDBY_BEATS[3] = mParser.getInt(KEY_STANDBY_RARE_BEATS,
DEFAULT_STANDBY_RARE_BEATS);
}
+
+ // Reset the heartbeat alarm based on the new heartbeat duration
+ setNextHeartbeatAlarm();
}
void dump(PrintWriter pw) {
@@ -1090,9 +1098,9 @@
mJobSchedulerStub = new JobSchedulerStub();
// Set up the app standby bucketing tracker
- UsageStatsManagerInternal usageStats = LocalServices.getService(UsageStatsManagerInternal.class);
- mStandbyTracker = new StandbyTracker(usageStats);
- usageStats.addAppIdleStateChangeListener(mStandbyTracker);
+ mStandbyTracker = new StandbyTracker();
+ mUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
+ mUsageStats.addAppIdleStateChangeListener(mStandbyTracker);
// The job store needs to call back
publishLocalService(JobSchedulerInternal.class, new LocalService());
@@ -1177,6 +1185,7 @@
mAppStateTracker = Preconditions.checkNotNull(
LocalServices.getService(AppStateTracker.class));
+ setNextHeartbeatAlarm();
// Register br for package removals and user removals.
final IntentFilter filter = new IntentFilter();
@@ -1418,6 +1427,23 @@
periodicToReschedule.getLastFailedRunTime());
}
+ long heartbeatWhenJobsLastRun(String packageName, final @UserIdInt int userId) {
+ final long heartbeat;
+ final long timeSinceLastJob = mUsageStats.getTimeSinceLastJobRun(packageName, userId);
+ synchronized (mLock) {
+ heartbeat = mHeartbeat - (timeSinceLastJob / mConstants.STANDBY_HEARTBEAT_TIME);
+ }
+ if (DEBUG_STANDBY) {
+ Slog.v(TAG, "Last job heartbeat " + heartbeat + " for " + packageName + "/" + userId
+ + " delta=" + timeSinceLastJob);
+ }
+ return heartbeat;
+ }
+
+ long heartbeatWhenJobsLastRun(JobStatus job) {
+ return heartbeatWhenJobsLastRun(job.getSourcePackageName(), job.getSourceUserId());
+ }
+
// JobCompletedListener implementations.
/**
@@ -1560,9 +1586,7 @@
noteJobsNonpending(mPendingJobs);
mPendingJobs.clear();
stopNonReadyActiveJobsLocked();
- boolean updated = updateStandbyHeartbeatLocked();
mJobs.forEachJob(mReadyQueueFunctor);
- if (updated) updateNextStandbyHeartbeatsLocked();
mReadyQueueFunctor.postProcess();
if (DEBUG) {
@@ -1716,36 +1740,78 @@
noteJobsNonpending(mPendingJobs);
mPendingJobs.clear();
stopNonReadyActiveJobsLocked();
- boolean updated = updateStandbyHeartbeatLocked();
mJobs.forEachJob(mMaybeQueueFunctor);
- if (updated) updateNextStandbyHeartbeatsLocked();
mMaybeQueueFunctor.postProcess();
}
- private boolean updateStandbyHeartbeatLocked() {
- final long sinceLast = sElapsedRealtimeClock.millis() - mLastHeartbeatTime;
- final long beatsElapsed = sinceLast / mConstants.STANDBY_HEARTBEAT_TIME;
- if (beatsElapsed > 0) {
- mHeartbeat += beatsElapsed;
- mLastHeartbeatTime += beatsElapsed * mConstants.STANDBY_HEARTBEAT_TIME;
- if (DEBUG_STANDBY) {
- Slog.v(TAG, "Advancing standby heartbeat by " + beatsElapsed + " to " + mHeartbeat);
+ /**
+ * Heartbeat tracking. The heartbeat alarm is intentionally non-wakeup.
+ */
+ class HeartbeatAlarmListener implements AlarmManager.OnAlarmListener {
+
+ @Override
+ public void onAlarm() {
+ synchronized (mLock) {
+ final long sinceLast = sElapsedRealtimeClock.millis() - mLastHeartbeatTime;
+ final long beatsElapsed = sinceLast / mConstants.STANDBY_HEARTBEAT_TIME;
+ if (beatsElapsed > 0) {
+ mLastHeartbeatTime += beatsElapsed * mConstants.STANDBY_HEARTBEAT_TIME;
+ advanceHeartbeatLocked(beatsElapsed);
+ }
}
- return true;
+ setNextHeartbeatAlarm();
}
- return false;
}
- private void updateNextStandbyHeartbeatsLocked() {
- // don't update ACTIVE or NEVER bucket milestones
+ // Intentionally does not touch the alarm timing
+ void advanceHeartbeatLocked(long beatsElapsed) {
+ mHeartbeat += beatsElapsed;
+ if (DEBUG_STANDBY) {
+ Slog.v(TAG, "Advancing standby heartbeat by " + beatsElapsed
+ + " to " + mHeartbeat);
+ }
+ // Don't update ACTIVE or NEVER bucket milestones. Note that mHeartbeat
+ // will be equal to mNextBucketHeartbeat[bucket] for one beat, during which
+ // new jobs scheduled by apps in that bucket will be permitted to run
+ // immediately.
+ boolean didAdvanceBucket = false;
for (int i = 1; i < mNextBucketHeartbeat.length - 1; i++) {
- while (mHeartbeat >= mNextBucketHeartbeat[i]) {
+ // Did we reach or cross a bucket boundary?
+ if (mHeartbeat >= mNextBucketHeartbeat[i]) {
+ didAdvanceBucket = true;
+ }
+ while (mHeartbeat > mNextBucketHeartbeat[i]) {
mNextBucketHeartbeat[i] += mConstants.STANDBY_BEATS[i];
}
if (DEBUG_STANDBY) {
- Slog.v(TAG, " Bucket " + i + " next heartbeat " + mNextBucketHeartbeat[i]);
+ Slog.v(TAG, " Bucket " + i + " next heartbeat "
+ + mNextBucketHeartbeat[i]);
}
}
+
+ if (didAdvanceBucket) {
+ if (DEBUG_STANDBY) {
+ Slog.v(TAG, "Hit bucket boundary; reevaluating job runnability");
+ }
+ mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
+ }
+ }
+
+ void setNextHeartbeatAlarm() {
+ final long heartbeatLength;
+ synchronized (mLock) {
+ heartbeatLength = mConstants.STANDBY_HEARTBEAT_TIME;
+ }
+ final long now = sElapsedRealtimeClock.millis();
+ final long nextBeatOrdinal = (now + heartbeatLength) / heartbeatLength;
+ final long nextHeartbeat = nextBeatOrdinal * heartbeatLength;
+ if (DEBUG_STANDBY) {
+ Slog.i(TAG, "Setting heartbeat alarm for " + nextHeartbeat
+ + " = " + TimeUtils.formatDuration(nextHeartbeat - now));
+ }
+ AlarmManager am = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
+ am.setExact(AlarmManager.ELAPSED_REALTIME, nextHeartbeat,
+ HEARTBEAT_TAG, mHeartbeatAlarm, mHandler);
}
/**
@@ -1811,17 +1877,20 @@
if (!mInParole && !job.getJob().isExemptedFromAppStandby()) {
final int bucket = job.getStandbyBucket();
if (mHeartbeat < mNextBucketHeartbeat[bucket]) {
- // Only skip this job if it's still waiting for the end of its (initial) nominal
+ // Only skip this job if the app is still waiting for the end of its nominal
// bucket interval. Once it's waited that long, we let it go ahead and clear.
// The final (NEVER) bucket is special; we never age those apps' jobs into
// runnability.
+ final long appLastRan = heartbeatWhenJobsLastRun(job);
if (bucket >= mConstants.STANDBY_BEATS.length
- || (mHeartbeat < job.getBaseHeartbeat() + mConstants.STANDBY_BEATS[bucket])) {
+ || (mHeartbeat > appLastRan
+ && mHeartbeat < appLastRan + mConstants.STANDBY_BEATS[bucket])) {
// TODO: log/trace that we're deferring the job due to bucketing if we hit this
if (job.getWhenStandbyDeferred() == 0) {
if (DEBUG_STANDBY) {
Slog.v(TAG, "Bucket deferral: " + mHeartbeat + " < "
- + mNextBucketHeartbeat[job.getStandbyBucket()] + " for " + job);
+ + (appLastRan + mConstants.STANDBY_BEATS[bucket])
+ + " for " + job);
}
job.setWhenStandbyDeferred(sElapsedRealtimeClock.millis());
}
@@ -2078,18 +2147,19 @@
// ACTIVE => everything can be run right away
// NEVER => we won't run them anyway, so let them go in the future
// as soon as the app enters normal use
+ if (DEBUG_STANDBY) {
+ Slog.v(TAG, "Base heartbeat forced ZERO for new job in "
+ + packageName + "/" + userId);
+ }
return 0;
}
- final long timeSinceLastJob = mStandbyTracker.getTimeSinceLastJobRun(
- packageName, userId);
- final long bucketLength = mConstants.STANDBY_BEATS[appStandbyBucket];
- final long bucketsAgo = timeSinceLastJob / bucketLength;
-
- // If we haven't run any jobs for more than the app's current bucket period, just
- // consider anything new to be immediately runnable. Otherwise, base it on the
- // bucket at which we last ran jobs.
- return (bucketsAgo > bucketLength) ? 0 : (getCurrentHeartbeat() - bucketsAgo);
+ final long baseHeartbeat = heartbeatWhenJobsLastRun(packageName, userId);
+ if (DEBUG_STANDBY) {
+ Slog.v(TAG, "Base heartbeat " + baseHeartbeat + " for new job in "
+ + packageName + "/" + userId);
+ }
+ return baseHeartbeat;
}
/**
@@ -2166,15 +2236,6 @@
* Tracking of app assignments to standby buckets
*/
final class StandbyTracker extends AppIdleStateChangeListener {
- final UsageStatsManagerInternal mUsageStats;
-
- StandbyTracker(UsageStatsManagerInternal usageStats) {
- mUsageStats = usageStats;
- }
-
- public long getTimeSinceLastJobRun(String packageName, final @UserIdInt int userId) {
- return mUsageStats.getTimeSinceLastJobRun(packageName, userId);
- }
// AppIdleStateChangeListener interface for live updates
@@ -2256,6 +2317,7 @@
else return 0;
}
+ // Static to support external callers
public static int standbyBucketForPackage(String packageName, int userId, long elapsedNow) {
UsageStatsManagerInternal usageStats = LocalServices.getService(
UsageStatsManagerInternal.class);
@@ -2337,9 +2399,9 @@
if (callingUid != Process.SYSTEM_UID) {
throw new SecurityException("Job has invalid flags");
}
- if (job.hasLateConstraint() || job.hasEarlyConstraint()) {
- Slog.wtf(TAG, "Jobs with time-constraints mustn't have"
- +" FLAG_EXEMPT_FROM_APP_STANDBY. Job=" + job);
+ if (job.isPeriodic()) {
+ Slog.wtf(TAG, "Periodic jobs mustn't have"
+ + " FLAG_EXEMPT_FROM_APP_STANDBY. Job=" + job);
}
}
}
@@ -2682,6 +2744,7 @@
}
}
+ // Shell command infrastructure
int getJobState(PrintWriter pw, String pkgName, int userId, int jobId) {
try {
final int uid = AppGlobals.getPackageManager().getPackageUid(pkgName, 0,
@@ -2759,6 +2822,21 @@
return 0;
}
+ // Shell command infrastructure
+ int executeHeartbeatCommand(PrintWriter pw, int numBeats) {
+ if (numBeats < 1) {
+ pw.println(getCurrentHeartbeat());
+ return 0;
+ }
+
+ pw.print("Advancing standby heartbeat by ");
+ pw.println(numBeats);
+ synchronized (mLock) {
+ advanceHeartbeatLocked(numBeats);
+ }
+ return 0;
+ }
+
private String printContextIdToJobMap(JobStatus[] map, String initial) {
StringBuilder s = new StringBuilder(initial + ": ");
for (int i=0; i<map.length; i++) {
diff --git a/services/core/java/com/android/server/job/JobSchedulerShellCommand.java b/services/core/java/com/android/server/job/JobSchedulerShellCommand.java
index d630aab..63225f3 100644
--- a/services/core/java/com/android/server/job/JobSchedulerShellCommand.java
+++ b/services/core/java/com/android/server/job/JobSchedulerShellCommand.java
@@ -64,6 +64,8 @@
return getStorageNotLow(pw);
case "get-job-state":
return getJobState(pw);
+ case "heartbeat":
+ return doHeartbeat(pw);
default:
return handleDefaultCommands(cmd);
}
@@ -333,6 +335,20 @@
}
}
+ private int doHeartbeat(PrintWriter pw) throws Exception {
+ checkPermission("manipulate scheduler heartbeat");
+
+ final String arg = getNextArg();
+ final int numBeats = (arg != null) ? Integer.parseInt(arg) : 0;
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return mInternal.executeHeartbeatCommand(pw, numBeats);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
@Override
public void onHelp() {
final PrintWriter pw = getOutPrintWriter();
@@ -359,6 +375,9 @@
pw.println(" Options:");
pw.println(" -u or --user: specify which user's job is to be run; the default is");
pw.println(" the primary or system user");
+ pw.println(" heartbeat [num]");
+ pw.println(" With no argument, prints the current standby heartbeat. With a positive");
+ pw.println(" argument, advances the standby heartbeat by that number.");
pw.println(" monitor-battery [on|off]");
pw.println(" Control monitoring of all battery changes. Off by default. Turning");
pw.println(" on makes get-battery-seq useful.");
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index 4988974..1f8cf76 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -240,11 +240,6 @@
}
}
- UsageStatsManagerInternal usageStats =
- LocalServices.getService(UsageStatsManagerInternal.class);
- usageStats.setLastJobRunTime(job.getSourcePackageName(), job.getSourceUserId(),
- mExecutionStartTimeElapsed);
-
// Once we'e begun executing a job, we by definition no longer care whether
// it was inflated from disk with not-yet-coherent delay/deadline bounds.
job.clearPersistedUtcTimes();
@@ -267,12 +262,16 @@
removeOpTimeOutLocked();
return false;
}
+ mJobPackageTracker.noteActive(job);
try {
mBatteryStats.noteJobStart(job.getBatteryName(), job.getSourceUid());
} catch (RemoteException e) {
// Whatever.
}
- mJobPackageTracker.noteActive(job);
+ UsageStatsManagerInternal usageStats =
+ LocalServices.getService(UsageStatsManagerInternal.class);
+ usageStats.setLastJobRunTime(job.getSourcePackageName(), job.getSourceUserId(),
+ mExecutionStartTimeElapsed);
mAvailable = false;
mStoppedReason = null;
mStoppedTime = 0;
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index 08ff7bd..3867306 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -1346,6 +1346,15 @@
}
pw.print(prefix); pw.print("Standby bucket: ");
pw.println(bucketName(standbyBucket));
+ if (standbyBucket > 0) {
+ pw.print(prefix); pw.print("Base heartbeat: ");
+ pw.println(baseHeartbeat);
+ }
+ if (whenStandbyDeferred != 0) {
+ pw.print(prefix); pw.print(" Deferred since: ");
+ TimeUtils.formatDuration(whenStandbyDeferred, elapsedRealtimeMillis, pw);
+ pw.println();
+ }
pw.print(prefix); pw.print("Enqueue time: ");
TimeUtils.formatDuration(enqueueTime, elapsedRealtimeMillis, pw);
pw.println();
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java b/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java
index c9c9329..c4f1f3d 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java
@@ -19,9 +19,6 @@
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT;
-import com.android.internal.widget.LockPatternUtils;
-import com.android.internal.widget.LockPatternUtils.StrongAuthTracker;
-
import android.app.AlarmManager;
import android.app.AlarmManager.OnAlarmListener;
import android.app.admin.DevicePolicyManager;
@@ -29,10 +26,9 @@
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.fingerprint.FingerprintManager;
-import android.os.Binder;
-import android.os.DeadObjectException;
import android.os.Handler;
import android.os.Message;
+import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
@@ -40,7 +36,7 @@
import android.util.Slog;
import android.util.SparseIntArray;
-import java.util.ArrayList;
+import com.android.internal.widget.LockPatternUtils.StrongAuthTracker;
/**
* Keeps track of requests for strong authentication.
@@ -58,7 +54,7 @@
private static final String STRONG_AUTH_TIMEOUT_ALARM_TAG =
"LockSettingsStrongAuth.timeoutForUser";
- private final ArrayList<IStrongAuthTracker> mStrongAuthTrackers = new ArrayList<>();
+ private final RemoteCallbackList<IStrongAuthTracker> mTrackers = new RemoteCallbackList<>();
private final SparseIntArray mStrongAuthForUser = new SparseIntArray();
private final ArrayMap<Integer, StrongAuthTimeoutAlarmListener>
mStrongAuthTimeoutAlarmListenerForUser = new ArrayMap<>();
@@ -82,12 +78,7 @@
}
private void handleAddStrongAuthTracker(IStrongAuthTracker tracker) {
- for (int i = 0; i < mStrongAuthTrackers.size(); i++) {
- if (mStrongAuthTrackers.get(i).asBinder() == tracker.asBinder()) {
- return;
- }
- }
- mStrongAuthTrackers.add(tracker);
+ mTrackers.register(tracker);
for (int i = 0; i < mStrongAuthForUser.size(); i++) {
int key = mStrongAuthForUser.keyAt(i);
@@ -101,12 +92,7 @@
}
private void handleRemoveStrongAuthTracker(IStrongAuthTracker tracker) {
- for (int i = 0; i < mStrongAuthTrackers.size(); i++) {
- if (mStrongAuthTrackers.get(i).asBinder() == tracker.asBinder()) {
- mStrongAuthTrackers.remove(i);
- return;
- }
- }
+ mTrackers.unregister(tracker);
}
private void handleRequireStrongAuth(int strongAuthReason, int userId) {
@@ -157,16 +143,19 @@
}
private void notifyStrongAuthTrackers(int strongAuthReason, int userId) {
- for (int i = 0; i < mStrongAuthTrackers.size(); i++) {
- try {
- mStrongAuthTrackers.get(i).onStrongAuthRequiredChanged(strongAuthReason, userId);
- } catch (DeadObjectException e) {
- Slog.d(TAG, "Removing dead StrongAuthTracker.");
- mStrongAuthTrackers.remove(i);
+ int i = mTrackers.beginBroadcast();
+ try {
+ while (i > 0) {
i--;
- } catch (RemoteException e) {
- Slog.e(TAG, "Exception while notifying StrongAuthTracker.", e);
+ try {
+ mTrackers.getBroadcastItem(i).onStrongAuthRequiredChanged(
+ strongAuthReason, userId);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Exception while notifying StrongAuthTracker.", e);
+ }
}
+ } finally {
+ mTrackers.finishBroadcast();
}
}
@@ -243,4 +232,5 @@
}
}
};
+
}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/OWNERS b/services/core/java/com/android/server/locksettings/recoverablekeystore/OWNERS
new file mode 100644
index 0000000..bb487fb
--- /dev/null
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/OWNERS
@@ -0,0 +1,4 @@
+aseemk@google.com
+bozhu@google.com
+dementyev@google.com
+robertberry@google.com
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
index 9f82268..23a66ba 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
@@ -170,11 +170,13 @@
certXml = CertXml.parse(recoveryServiceCertFile);
} catch (CertParsingException e) {
// TODO: Do not use raw key bytes anymore once the other components are updated
- Log.d(TAG, "Failed to parse the cert file", e);
+ Log.d(TAG, "Failed to parse the input as a cert file: " + HexDump.toHexString(
+ recoveryServiceCertFile));
PublicKey publicKey = parseEcPublicKey(recoveryServiceCertFile);
if (mDatabase.setRecoveryServicePublicKey(userId, uid, publicKey) > 0) {
mDatabase.setShouldCreateSnapshot(userId, uid, true);
}
+ Log.d(TAG, "Successfully set the input as the raw public key");
return;
}
@@ -655,7 +657,7 @@
// Ignore the exception to continue to recover the other application keys.
}
}
- if (keyMaterialByAlias.isEmpty()) {
+ if (!applicationKeys.isEmpty() && keyMaterialByAlias.isEmpty()) {
Log.e(TAG, "Failed to recover any of the application keys.");
throw new ServiceSpecificException(ERROR_DECRYPTION_FAILED,
"Failed to recover any of the application keys.");
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index b877184..21d86c4 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -29,6 +29,7 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
@@ -76,6 +77,7 @@
import android.view.KeyEvent;
import android.view.ViewConfiguration;
+import com.android.internal.os.BackgroundThread;
import com.android.internal.util.DumpUtils;
import com.android.server.SystemService;
import com.android.server.Watchdog;
@@ -180,9 +182,8 @@
updateUser();
+ registerPackageBroadcastReceivers();
// TODO(jaewan): Query per users
- // TODO(jaewan): Add listener to know changes in list of services.
- // Refer TvInputManagerService.registerBroadcastReceivers()
buildMediaSessionService2List();
}
@@ -437,12 +438,74 @@
mHandler.postSessionsChanged(session.getUserId());
}
+ private void registerPackageBroadcastReceivers() {
+ // TODO(jaewan): Only consider changed packages when building session service list
+ // when we make this multi-user aware. At that time,
+ // use PackageMonitor.getChangingUserId() to know which user has changed.
+ IntentFilter filter = new IntentFilter();
+ filter.addDataScheme("package");
+ filter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ filter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
+ filter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
+ filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+ filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
+ filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
+
+ getContext().registerReceiverAsUser(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final int changeUserId = intent.getIntExtra(
+ Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+ if (changeUserId == UserHandle.USER_NULL) {
+ Log.w(TAG, "Intent broadcast does not contain user handle: "+ intent);
+ return;
+ }
+ // Check if the package is replacing (i.e. reinstalling)
+ final boolean isReplacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
+ // TODO(jaewan): Add multi-user support with this.
+ // final int uid = intent.getIntExtra(Intent.EXTRA_UID, 0);
+
+ if (DEBUG) {
+ Log.d(TAG, "Received change in packages, intent=" + intent);
+ }
+ switch (intent.getAction()) {
+ case Intent.ACTION_PACKAGE_ADDED:
+ case Intent.ACTION_PACKAGE_REMOVED:
+ case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE:
+ case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE:
+ if (isReplacing) {
+ // Ignore if the package(s) are replacing. In that case, followings will
+ // happen in order.
+ // 1. ACTION_PACKAGE_REMOVED with isReplacing=true
+ // 2. ACTION_PACKAGE_ADDED with isReplacing=true
+ // 3. ACTION_PACKAGE_REPLACED
+ // (Note that ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE and
+ // ACTION_EXTERNAL_APPLICATIONS_AVAILABLE will be also called with
+ // isReplacing=true for both ASEC hosted packages and packages in
+ // external storage)
+ // Since we only want to update session service list once, ignore
+ // actions above when replacing.
+ // Replacing will be handled only once with the ACTION_PACKAGE_REPLACED.
+ break;
+ }
+ // pass-through
+ case Intent.ACTION_PACKAGE_CHANGED:
+ case Intent.ACTION_PACKAGES_SUSPENDED:
+ case Intent.ACTION_PACKAGES_UNSUSPENDED:
+ case Intent.ACTION_PACKAGE_REPLACED:
+ buildMediaSessionService2List();
+ }
+ }
+ }, UserHandle.ALL, filter, null, BackgroundThread.getHandler());
+ }
+
private void buildMediaSessionService2List() {
if (DEBUG) {
Log.d(TAG, "buildMediaSessionService2List");
}
-
- // TODO(jaewan): Query per users.
+ // TODO(jaewan): Also query for managed profile users.
// TODO(jaewan): Similar codes are also at the updatable. Can't we share codes?
PackageManager manager = getContext().getPackageManager();
List<ResolveInfo> services = new ArrayList<>();
@@ -458,9 +521,13 @@
services.addAll(sessionServices);
}
synchronized (mLock) {
- mSessions.clear();
- if (services == null) {
- return;
+ // List to keep the session services that need be removed because they don't exist
+ // in the 'services' above.
+ List<MediaSession2Record> removeCandidates = new ArrayList<>();
+ for (int i = 0; i < mSessions.size(); i++) {
+ if (mSessions.get(i).getToken().getType() != TYPE_SESSION) {
+ removeCandidates.add(mSessions.get(i));
+ }
}
for (int i = 0; i < services.size(); i++) {
if (services.get(i) == null || services.get(i).serviceInfo == null) {
@@ -475,17 +542,35 @@
} catch (NameNotFoundException e) {
continue;
}
-
+ SessionToken2 token;
try {
- SessionToken2 token = new SessionToken2(getContext(),
+ token = new SessionToken2(getContext(),
serviceInfo.packageName, serviceInfo.name, uid);
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "Invalid session service", e);
+ continue;
+ }
+ boolean found = false;
+ for (int j = 0; j < mSessions.size(); j++) {
+ if (token.equals(mSessions.get(j).getToken())) {
+ // If the token already exists, keep it in the mSessions.
+ removeCandidates.remove(mSessions.get(j));
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ // New session service is found.
MediaSession2Record record = new MediaSession2Record(getContext(),
token, mSessionDestroyedListener);
mSessions.add(record);
- } catch (IllegalArgumentException e) {
- Log.d(TAG, "Invalid session service", e);
}
}
+ for (int i = 0; i < removeCandidates.size(); i++) {
+ removeCandidates.get(i).onSessionDestroyed();
+ mSessions.remove(removeCandidates.get(i));
+ }
+ removeCandidates.clear();
}
if (DEBUG) {
Log.d(TAG, "Found " + mSessions.size() + " session services");
@@ -1503,12 +1588,14 @@
return tokens;
}
+ // TODO(jaewan): Protect this API with permission
@Override
public void addSessionTokensListener(ISessionTokensListener listener, int userId,
String packageName) {
// TODO(jaewan): Implement.
}
+ // TODO(jaewan): Protect this API with permission
@Override
public void removeSessionTokensListener(ISessionTokensListener listener) {
// TODO(jaewan): Implement
diff --git a/services/core/java/com/android/server/media/OWNERS b/services/core/java/com/android/server/media/OWNERS
new file mode 100644
index 0000000..6f8d823
--- /dev/null
+++ b/services/core/java/com/android/server/media/OWNERS
@@ -0,0 +1,2 @@
+lajos@google.com
+elaurent@google.com
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index f346629..e2b2d46 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -145,6 +145,7 @@
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.Binder;
+import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
@@ -2759,6 +2760,13 @@
return;
}
+ // Fourth check: is caller a testing app on a debug build?
+ final boolean enableDebug = Build.IS_USERDEBUG || Build.IS_ENG;
+ if (enableDebug && callingPackage
+ .equals(SystemProperties.get("fw.sub_plan_owner." + subId, null))) {
+ return;
+ }
+
// Final check: does the caller hold a permission?
mContext.enforceCallingOrSelfPermission(MANAGE_SUBSCRIPTION_PLANS, TAG);
}
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 1ad8c74..8d2f0dd 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -15,6 +15,7 @@
*/
package com.android.server.notification;
+import static android.app.NotificationChannel.USER_LOCKED_IMPORTANCE;
import static android.app.NotificationManager.IMPORTANCE_MIN;
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
@@ -22,6 +23,8 @@
import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.service.notification.NotificationListenerService.Ranking
.USER_SENTIMENT_NEUTRAL;
+import static android.service.notification.NotificationListenerService.Ranking
+ .USER_SENTIMENT_POSITIVE;
import android.app.Notification;
import android.app.NotificationChannel;
@@ -163,6 +166,7 @@
mLight = calculateLights();
mAdjustments = new ArrayList<>();
mStats = new NotificationStats();
+ calculateUserSentiment();
}
private boolean isPreChannelsNotification() {
@@ -320,7 +324,7 @@
if (mPreChannelsNotification
&& (importance == IMPORTANCE_UNSPECIFIED
|| (getChannel().getUserLockedFields()
- & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0)) {
+ & USER_LOCKED_IMPORTANCE) == 0)) {
if (!stats.isNoisy && requestedImportance > IMPORTANCE_LOW) {
requestedImportance = IMPORTANCE_LOW;
}
@@ -585,8 +589,12 @@
setOverrideGroupKey(groupOverrideKey);
}
if (signals.containsKey(Adjustment.KEY_USER_SENTIMENT)) {
- setUserSentiment(adjustment.getSignals().getInt(
- Adjustment.KEY_USER_SENTIMENT, USER_SENTIMENT_NEUTRAL));
+ // Only allow user sentiment update from assistant if user hasn't already
+ // expressed a preference for this channel
+ if ((getChannel().getUserLockedFields() & USER_LOCKED_IMPORTANCE) == 0) {
+ setUserSentiment(adjustment.getSignals().getInt(
+ Adjustment.KEY_USER_SENTIMENT, USER_SENTIMENT_NEUTRAL));
+ }
}
}
}
@@ -845,10 +853,6 @@
}
}
- public boolean isImportanceFromUser() {
- return mImportance == mUserImportance;
- }
-
public NotificationChannel getChannel() {
return mChannel;
}
@@ -857,6 +861,7 @@
if (channel != null) {
mChannel = channel;
calculateImportance();
+ calculateUserSentiment();
}
}
@@ -900,6 +905,12 @@
mSnoozeCriteria = snoozeCriteria;
}
+ private void calculateUserSentiment() {
+ if ((getChannel().getUserLockedFields() & USER_LOCKED_IMPORTANCE) != 0) {
+ mUserSentiment = USER_SENTIMENT_POSITIVE;
+ }
+ }
+
private void setUserSentiment(int userSentiment) {
mUserSentiment = userSentiment;
}
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index b0e3820..dc936d2 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -640,9 +640,11 @@
if (updatedChannel.getLockscreenVisibility() == Notification.VISIBILITY_PUBLIC) {
updatedChannel.setLockscreenVisibility(Ranking.VISIBILITY_NO_OVERRIDE);
}
- updatedChannel.unlockFields(updatedChannel.getUserLockedFields());
- updatedChannel.lockFields(channel.getUserLockedFields());
+ if (!fromUser) {
+ updatedChannel.unlockFields(updatedChannel.getUserLockedFields());
+ }
if (fromUser) {
+ updatedChannel.lockFields(channel.getUserLockedFields());
lockFieldsForUpdate(channel, updatedChannel);
}
r.channels.put(updatedChannel.getId(), updatedChannel);
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 7e3b551..0a87097 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -18,8 +18,10 @@
import android.app.AppOpsManager;
import android.app.AutomaticZenRule;
+import android.app.Notification;
import android.app.NotificationManager;
import android.app.NotificationManager.Policy;
+import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
@@ -44,6 +46,7 @@
import android.os.Process;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.provider.Settings;
import android.provider.Settings.Global;
import android.service.notification.Condition;
import android.service.notification.ConditionProviderService;
@@ -61,6 +64,8 @@
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.server.LocalServices;
import libcore.io.IoUtils;
@@ -89,6 +94,7 @@
private final H mHandler;
private final SettingsObserver mSettingsObserver;
@VisibleForTesting protected final AppOpsManager mAppOps;
+ @VisibleForTesting protected final NotificationManager mNotificationManager;
protected ZenModeConfig mDefaultConfig;
private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
private final ZenModeFiltering mFiltering;
@@ -112,12 +118,14 @@
protected String mDefaultRuleEveryNightName;
protected String mDefaultRuleEventsName;
+ @VisibleForTesting protected boolean mIsBootComplete;
public ZenModeHelper(Context context, Looper looper, ConditionProviders conditionProviders) {
mContext = context;
mHandler = new H(looper);
addCallback(mMetrics);
mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+ mNotificationManager = context.getSystemService(NotificationManager.class);
mDefaultConfig = new ZenModeConfig();
setDefaultZenRules(mContext);
@@ -197,6 +205,8 @@
mHandler.postMetricsTimer();
cleanUpZenRules();
evaluateZenMode("onSystemReady", true);
+ mIsBootComplete = true;
+ showZenUpgradeNotification(mZenMode);
}
public void onUserSwitched(int user) {
@@ -612,6 +622,10 @@
throws XmlPullParserException, IOException {
final ZenModeConfig config = ZenModeConfig.readXml(parser);
if (config != null) {
+ if (config.version < ZenModeConfig.XML_VERSION) {
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Global.SHOW_ZEN_UPGRADE_NOTIFICATION, 1);
+ }
if (forRestore) {
//TODO: http://b/22388012
if (config.user != UserHandle.USER_SYSTEM) {
@@ -755,8 +769,10 @@
return Global.getInt(mContext.getContentResolver(), Global.ZEN_MODE, Global.ZEN_MODE_OFF);
}
- private void setZenModeSetting(int zen) {
+ @VisibleForTesting
+ protected void setZenModeSetting(int zen) {
Global.putInt(mContext.getContentResolver(), Global.ZEN_MODE, zen);
+ showZenUpgradeNotification(zen);
}
private int getPreviousRingerModeSetting() {
@@ -1139,6 +1155,41 @@
}
}
+ private void showZenUpgradeNotification(int zen) {
+ final boolean showNotification = mIsBootComplete
+ && zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
+ && Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.SHOW_ZEN_UPGRADE_NOTIFICATION, 0) != 0;
+
+ if (showNotification) {
+ mNotificationManager.notify(TAG, SystemMessage.NOTE_ZEN_UPGRADE,
+ createZenUpgradeNotification());
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Global.SHOW_ZEN_UPGRADE_NOTIFICATION, 0);
+ }
+ }
+
+ @VisibleForTesting
+ protected Notification createZenUpgradeNotification() {
+ Intent intent = new Intent(Settings.ACTION_ZEN_MODE_PRIORITY_SETTINGS)
+ .setPackage("com.android.settings")
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ final Bundle extras = new Bundle();
+ extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
+ mContext.getResources().getString(R.string.global_action_settings));
+ return new Notification.Builder(mContext, SystemNotificationChannels.SYSTEM_CHANGES)
+ .setSmallIcon(R.drawable.ic_settings_24dp)
+ .setContentTitle(mContext.getResources().getString(
+ R.string.zen_upgrade_notification_title))
+ .setContentText(mContext.getResources().getString(
+ R.string.zen_upgrade_notification_content))
+ .setAutoCancel(true)
+ .setLocalOnly(true)
+ .addExtras(extras)
+ .setContentIntent(PendingIntent.getActivity(mContext, 0, intent, 0, null))
+ .build();
+ }
+
private final class Metrics extends Callback {
private static final String COUNTER_PREFIX = "dnd_mode_";
private static final long MINIMUM_LOG_PERIOD_MS = 60 * 1000;
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index b79caca..9bba9ed 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -63,9 +63,8 @@
public static final int DEXOPT_STORAGE_DE = 1 << 8;
/** Indicates that dexopt is invoked from the background service. */
public static final int DEXOPT_IDLE_BACKGROUND_JOB = 1 << 9;
- /* Indicates that dexopt should not restrict access to private APIs.
- * Must be kept in sync with com.android.internal.os.ZygoteInit. */
- public static final int DEXOPT_DISABLE_HIDDEN_API_CHECKS = 1 << 10;
+ /** Indicates that dexopt should restrict access to private APIs. */
+ public static final int DEXOPT_ENABLE_HIDDEN_API_CHECKS = 1 << 10;
// NOTE: keep in sync with installd
public static final int FLAG_CLEAR_CACHE_ONLY = 1 << 8;
@@ -290,14 +289,14 @@
int dexoptNeeded, @Nullable String outputPath, int dexFlags,
String compilerFilter, @Nullable String volumeUuid, @Nullable String sharedLibraries,
@Nullable String seInfo, boolean downgrade, int targetSdkVersion,
- @Nullable String profileName, @Nullable String dexMetadataPath)
- throws InstallerException {
+ @Nullable String profileName, @Nullable String dexMetadataPath,
+ @Nullable String compilationReason) throws InstallerException {
assertValidInstructionSet(instructionSet);
if (!checkBeforeRemote()) return;
try {
mInstalld.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded, outputPath,
dexFlags, compilerFilter, volumeUuid, sharedLibraries, seInfo, downgrade,
- targetSdkVersion, profileName, dexMetadataPath);
+ targetSdkVersion, profileName, dexMetadataPath, compilationReason);
} catch (Exception e) {
throw InstallerException.from(e);
}
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index fc73142..9420a6c 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -262,11 +262,12 @@
int dexFlags, String compilerFilter, @Nullable String volumeUuid,
@Nullable String sharedLibraries, @Nullable String seInfo, boolean downgrade,
int targetSdkVersion, @Nullable String profileName,
- @Nullable String dexMetadataPath) throws InstallerException {
+ @Nullable String dexMetadataPath, @Nullable String dexoptCompilationReason)
+ throws InstallerException {
final StringBuilder builder = new StringBuilder();
- // The version. Right now it's 6.
- builder.append("6 ");
+ // The version. Right now it's 7.
+ builder.append("7 ");
builder.append("dexopt");
@@ -285,6 +286,7 @@
encodeParameter(builder, targetSdkVersion);
encodeParameter(builder, profileName);
encodeParameter(builder, dexMetadataPath);
+ encodeParameter(builder, dexoptCompilationReason);
commands.add(builder.toString());
}
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 2c68e67..77bf67d 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -34,7 +34,6 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.pm.Installer.InstallerException;
-import com.android.server.pm.dex.DexManager;
import com.android.server.pm.dex.DexoptOptions;
import com.android.server.pm.dex.DexoptUtils;
import com.android.server.pm.dex.PackageDexUsage;
@@ -57,13 +56,14 @@
import static com.android.server.pm.Installer.DEXOPT_STORAGE_CE;
import static com.android.server.pm.Installer.DEXOPT_STORAGE_DE;
import static com.android.server.pm.Installer.DEXOPT_IDLE_BACKGROUND_JOB;
-import static com.android.server.pm.Installer.DEXOPT_DISABLE_HIDDEN_API_CHECKS;
+import static com.android.server.pm.Installer.DEXOPT_ENABLE_HIDDEN_API_CHECKS;
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
import static com.android.server.pm.PackageManagerService.WATCHDOG_TIMEOUT;
-import static dalvik.system.DexFile.getNonProfileGuidedCompilerFilter;
+import static com.android.server.pm.PackageManagerServiceCompilerMapping.getReasonName;
+
import static dalvik.system.DexFile.getSafeModeCompilerFilter;
import static dalvik.system.DexFile.isProfileGuidedCompilerFilter;
@@ -231,7 +231,8 @@
for (String dexCodeIsa : dexCodeInstructionSets) {
int newResult = dexOptPath(pkg, path, dexCodeIsa, compilerFilter,
profileUpdated, classLoaderContexts[i], dexoptFlags, sharedGid,
- packageStats, options.isDowngrade(), profileName, dexMetadataPath);
+ packageStats, options.isDowngrade(), profileName, dexMetadataPath,
+ options.getCompilationReason());
// The end result is:
// - FAILED if any path failed,
// - PERFORMED if at least one path needed compilation,
@@ -256,7 +257,7 @@
private int dexOptPath(PackageParser.Package pkg, String path, String isa,
String compilerFilter, boolean profileUpdated, String classLoaderContext,
int dexoptFlags, int uid, CompilerStats.PackageStats packageStats, boolean downgrade,
- String profileName, String dexMetadataPath) {
+ String profileName, String dexMetadataPath, int compilationReason) {
int dexoptNeeded = getDexoptNeeded(path, isa, compilerFilter, classLoaderContext,
profileUpdated, downgrade);
if (Math.abs(dexoptNeeded) == DexFile.NO_DEXOPT_NEEDED) {
@@ -283,7 +284,7 @@
mInstaller.dexopt(path, uid, pkg.packageName, isa, dexoptNeeded, oatDir, dexoptFlags,
compilerFilter, pkg.volumeUuid, classLoaderContext, pkg.applicationInfo.seInfo,
false /* downgrade*/, pkg.applicationInfo.targetSdkVersion,
- profileName, dexMetadataPath);
+ profileName, dexMetadataPath, getReasonName(compilationReason));
if (packageStats != null) {
long endTime = System.currentTimeMillis();
@@ -394,7 +395,7 @@
// Note this trades correctness for performance since the resulting slow down is
// unacceptable in some cases until b/64530081 is fixed.
String classLoaderContext = SKIP_SHARED_LIBRARY_CHECK;
-
+ int reason = options.getCompilationReason();
try {
for (String isa : dexUseInfo.getLoaderIsas()) {
// Reuse the same dexopt path as for the primary apks. We don't need all the
@@ -405,7 +406,7 @@
/*oatDir*/ null, dexoptFlags,
compilerFilter, info.volumeUuid, classLoaderContext, info.seInfoUser,
options.isDowngrade(), info.targetSdkVersion, /*profileName*/ null,
- /*dexMetadataPath*/ null);
+ /*dexMetadataPath*/ null, getReasonName(reason));
}
return DEX_OPT_PERFORMED;
@@ -528,11 +529,9 @@
boolean isPublic = !info.isForwardLocked() &&
(!isProfileGuidedFilter || options.isDexoptInstallWithDexMetadata());
int profileFlag = isProfileGuidedFilter ? DEXOPT_PROFILE_GUIDED : 0;
- // System apps are invoked with a runtime flag which exempts them from
- // restrictions on hidden API usage. We dexopt with the same runtime flag
- // otherwise offending methods would have to be re-verified at runtime
- // and we want to avoid the performance overhead of that.
- int hiddenApiFlag = info.isAllowedToUseHiddenApi() ? DEXOPT_DISABLE_HIDDEN_API_CHECKS : 0;
+ // Some apps are executed with restrictions on hidden API usage. If this app is one
+ // of them, pass a flag to dexopt to enable the same restrictions during compilation.
+ int hiddenApiFlag = info.isAllowedToUseHiddenApi() ? 0 : DEXOPT_ENABLE_HIDDEN_API_CHECKS;
int dexFlags =
(isPublic ? DEXOPT_PUBLIC : 0)
| (debuggable ? DEXOPT_DEBUGGABLE : 0)
@@ -655,8 +654,8 @@
if ((flags & DEXOPT_IDLE_BACKGROUND_JOB) == DEXOPT_IDLE_BACKGROUND_JOB) {
flagsList.add("idle_background_job");
}
- if ((flags & DEXOPT_DISABLE_HIDDEN_API_CHECKS) == DEXOPT_DISABLE_HIDDEN_API_CHECKS) {
- flagsList.add("disable_hidden_api_checks");
+ if ((flags & DEXOPT_ENABLE_HIDDEN_API_CHECKS) == DEXOPT_ENABLE_HIDDEN_API_CHECKS) {
+ flagsList.add("enable_hidden_api_checks");
}
return String.join(",", flagsList);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 3cd24f9..884606d2 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -598,6 +598,7 @@
}
// Compilation reasons.
+ public static final int REASON_UNKNOWN = -1;
public static final int REASON_FIRST_BOOT = 0;
public static final int REASON_BOOT = 1;
public static final int REASON_INSTALL = 2;
@@ -2720,11 +2721,12 @@
* application can be scanned.
*/
if (mSettings.isDisabledSystemPackageLPr(ps.name)) {
- logCriticalInfo(Log.WARN, "Expecting better updated system app for "
- + ps.name + "; removing system app. Last known codePath="
- + ps.codePathString + ", installStatus=" + ps.installStatus
- + ", versionCode=" + ps.versionCode + "; scanned versionCode="
- + scannedPkg.getLongVersionCode());
+ logCriticalInfo(Log.WARN,
+ "Expecting better updated system app for " + ps.name
+ + "; removing system app. Last known"
+ + " codePath=" + ps.codePathString
+ + ", versionCode=" + ps.versionCode
+ + "; scanned versionCode=" + scannedPkg.getLongVersionCode());
removePackageLI(scannedPkg, true);
mExpectingBetter.put(ps.name, ps.codePath);
}
@@ -2753,18 +2755,6 @@
}
}
- //look for any incomplete package installations
- ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr();
- for (int i = 0; i < deletePkgsList.size(); i++) {
- // Actual deletion of code and data will be handled by later
- // reconciliation step
- final String packageName = deletePkgsList.get(i).name;
- logCriticalInfo(Log.WARN, "Cleaning up incompletely installed app: " + packageName);
- synchronized (mPackages) {
- mSettings.removePackageLPw(packageName);
- }
- }
-
//delete tmp files
deleteTempPackageFiles();
@@ -8847,7 +8837,7 @@
final long startTime = System.nanoTime();
final int[] stats = performDexOptUpgrade(pkgs, mIsPreNUpgrade /* showDialog */,
- getCompilerFilterForReason(causeFirstBoot ? REASON_FIRST_BOOT : REASON_BOOT),
+ causeFirstBoot ? REASON_FIRST_BOOT : REASON_BOOT,
false /* bootComplete */);
final int elapsedTimeSeconds =
@@ -8874,7 +8864,7 @@
* and {@code numberOfPackagesFailed}.
*/
private int[] performDexOptUpgrade(List<PackageParser.Package> pkgs, boolean showDialog,
- final String compilerFilter, boolean bootComplete) {
+ final int compilationReason, boolean bootComplete) {
int numberOfPackagesVisited = 0;
int numberOfPackagesOptimized = 0;
@@ -8974,13 +8964,11 @@
}
}
- String pkgCompilerFilter = compilerFilter;
+ int pkgCompilationReason = compilationReason;
if (useProfileForDexopt) {
// Use background dexopt mode to try and use the profile. Note that this does not
// guarantee usage of the profile.
- pkgCompilerFilter =
- PackageManagerServiceCompilerMapping.getCompilerFilterForReason(
- PackageManagerService.REASON_BACKGROUND_DEXOPT);
+ pkgCompilationReason = PackageManagerService.REASON_BACKGROUND_DEXOPT;
}
// checkProfiles is false to avoid merging profiles during boot which
@@ -8991,7 +8979,7 @@
int dexoptFlags = bootComplete ? DexoptOptions.DEXOPT_BOOT_COMPLETE : 0;
int primaryDexOptStaus = performDexOptTraced(new DexoptOptions(
pkg.packageName,
- pkgCompilerFilter,
+ pkgCompilationReason,
dexoptFlags));
switch (primaryDexOptStaus) {
@@ -9092,8 +9080,8 @@
int flags = (checkProfiles ? DexoptOptions.DEXOPT_CHECK_FOR_PROFILES_UPDATES : 0) |
(force ? DexoptOptions.DEXOPT_FORCE : 0) |
(bootComplete ? DexoptOptions.DEXOPT_BOOT_COMPLETE : 0);
- return performDexOpt(new DexoptOptions(packageName, targetCompilerFilter,
- splitName, flags));
+ return performDexOpt(new DexoptOptions(packageName, REASON_UNKNOWN,
+ targetCompilerFilter, splitName, flags));
}
/**
@@ -9202,7 +9190,8 @@
final String[] instructionSets = getAppDexInstructionSets(p.applicationInfo);
if (!deps.isEmpty()) {
DexoptOptions libraryOptions = new DexoptOptions(options.getPackageName(),
- options.getCompilerFilter(), options.getSplitName(),
+ options.getCompilationReason(), options.getCompilerFilter(),
+ options.getSplitName(),
options.getFlags() | DexoptOptions.DEXOPT_AS_SHARED_LIBRARY);
for (PackageParser.Package depPackage : deps) {
// TODO: Analyze and investigate if we (should) profile libraries.
@@ -16574,17 +16563,7 @@
PackageInstalledInfo res, UserHandle user, int installReason) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "updateSettings");
- String pkgName = pkg.packageName;
- synchronized (mPackages) {
- //write settings. the installStatus will be incomplete at this stage.
- //note that the new package setting would have already been
- //added to mPackages. It hasn't been persisted yet.
- mSettings.setInstallStatus(pkgName, PackageSettingBase.PKG_INSTALL_INCOMPLETE);
- // TODO: Remove this write? It's also written at the end of this method
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "writeSettings");
- mSettings.writeLPr();
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
+ final String pkgName = pkg.packageName;
if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + pkg.codePath);
synchronized (mPackages) {
@@ -16665,7 +16644,6 @@
res.name = pkgName;
res.uid = pkg.applicationInfo.uid;
res.pkg = pkg;
- mSettings.setInstallStatus(pkgName, PackageSettingBase.PKG_INSTALL_COMPLETE);
mSettings.setInstallerPackageName(pkgName, installerPackageName);
res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
//to update install status
@@ -18751,7 +18729,7 @@
return true;
}
- private final class ClearStorageConnection implements ServiceConnection {
+ private static final class ClearStorageConnection implements ServiceConnection {
IMediaContainerService mContainerService;
@Override
@@ -20666,10 +20644,6 @@
@Override
public String getInstallerPackageName(String packageName) {
final int callingUid = Binder.getCallingUid();
- if (getInstantAppPackageName(callingUid) != null) {
- return null;
- }
- // reader
synchronized (mPackages) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
if (filterAppAccessLPr(ps, callingUid, UserHandle.getUserId(callingUid))) {
@@ -21462,35 +21436,37 @@
// the given package is involved with.
if (dumpState.onTitlePrinted()) pw.println();
- final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
- ipw.println();
- ipw.println("Frozen packages:");
- ipw.increaseIndent();
- if (mFrozenPackages.size() == 0) {
- ipw.println("(none)");
- } else {
- for (int i = 0; i < mFrozenPackages.size(); i++) {
- ipw.println(mFrozenPackages.valueAt(i));
+ try (final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120)) {
+ ipw.println();
+ ipw.println("Frozen packages:");
+ ipw.increaseIndent();
+ if (mFrozenPackages.size() == 0) {
+ ipw.println("(none)");
+ } else {
+ for (int i = 0; i < mFrozenPackages.size(); i++) {
+ ipw.println(mFrozenPackages.valueAt(i));
+ }
}
+ ipw.decreaseIndent();
}
- ipw.decreaseIndent();
}
if (!checkin && dumpState.isDumping(DumpState.DUMP_VOLUMES) && packageName == null) {
if (dumpState.onTitlePrinted()) pw.println();
- final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
- ipw.println();
- ipw.println("Loaded volumes:");
- ipw.increaseIndent();
- if (mLoadedVolumes.size() == 0) {
- ipw.println("(none)");
- } else {
- for (int i = 0; i < mLoadedVolumes.size(); i++) {
- ipw.println(mLoadedVolumes.valueAt(i));
+ try (final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120)) {
+ ipw.println();
+ ipw.println("Loaded volumes:");
+ ipw.increaseIndent();
+ if (mLoadedVolumes.size() == 0) {
+ ipw.println("(none)");
+ } else {
+ for (int i = 0; i < mLoadedVolumes.size(); i++) {
+ ipw.println(mLoadedVolumes.valueAt(i));
+ }
}
+ ipw.decreaseIndent();
}
- ipw.decreaseIndent();
}
if (!checkin && dumpState.isDumping(DumpState.DUMP_SERVICE_PERMISSIONS)
@@ -21619,61 +21595,63 @@
}
private void dumpDexoptStateLPr(PrintWriter pw, String packageName) {
- final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
- ipw.println();
- ipw.println("Dexopt state:");
- ipw.increaseIndent();
- Collection<PackageParser.Package> packages = null;
- if (packageName != null) {
- PackageParser.Package targetPackage = mPackages.get(packageName);
- if (targetPackage != null) {
- packages = Collections.singletonList(targetPackage);
- } else {
- ipw.println("Unable to find package: " + packageName);
- return;
- }
- } else {
- packages = mPackages.values();
- }
-
- for (PackageParser.Package pkg : packages) {
- ipw.println("[" + pkg.packageName + "]");
+ try (final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ")) {
+ ipw.println();
+ ipw.println("Dexopt state:");
ipw.increaseIndent();
- mPackageDexOptimizer.dumpDexoptState(ipw, pkg,
- mDexManager.getPackageUseInfoOrDefault(pkg.packageName));
- ipw.decreaseIndent();
+ Collection<PackageParser.Package> packages = null;
+ if (packageName != null) {
+ PackageParser.Package targetPackage = mPackages.get(packageName);
+ if (targetPackage != null) {
+ packages = Collections.singletonList(targetPackage);
+ } else {
+ ipw.println("Unable to find package: " + packageName);
+ return;
+ }
+ } else {
+ packages = mPackages.values();
+ }
+
+ for (PackageParser.Package pkg : packages) {
+ ipw.println("[" + pkg.packageName + "]");
+ ipw.increaseIndent();
+ mPackageDexOptimizer.dumpDexoptState(ipw, pkg,
+ mDexManager.getPackageUseInfoOrDefault(pkg.packageName));
+ ipw.decreaseIndent();
+ }
}
}
private void dumpCompilerStatsLPr(PrintWriter pw, String packageName) {
- final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
- ipw.println();
- ipw.println("Compiler stats:");
- ipw.increaseIndent();
- Collection<PackageParser.Package> packages = null;
- if (packageName != null) {
- PackageParser.Package targetPackage = mPackages.get(packageName);
- if (targetPackage != null) {
- packages = Collections.singletonList(targetPackage);
- } else {
- ipw.println("Unable to find package: " + packageName);
- return;
- }
- } else {
- packages = mPackages.values();
- }
-
- for (PackageParser.Package pkg : packages) {
- ipw.println("[" + pkg.packageName + "]");
+ try (final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ")) {
+ ipw.println();
+ ipw.println("Compiler stats:");
ipw.increaseIndent();
-
- CompilerStats.PackageStats stats = getCompilerPackageStats(pkg.packageName);
- if (stats == null) {
- ipw.println("(No recorded stats)");
+ Collection<PackageParser.Package> packages = null;
+ if (packageName != null) {
+ PackageParser.Package targetPackage = mPackages.get(packageName);
+ if (targetPackage != null) {
+ packages = Collections.singletonList(targetPackage);
+ } else {
+ ipw.println("Unable to find package: " + packageName);
+ return;
+ }
} else {
- stats.dump(ipw);
+ packages = mPackages.values();
}
- ipw.decreaseIndent();
+
+ for (PackageParser.Package pkg : packages) {
+ ipw.println("[" + pkg.packageName + "]");
+ ipw.increaseIndent();
+
+ CompilerStats.PackageStats stats = getCompilerPackageStats(pkg.packageName);
+ if (stats == null) {
+ ipw.println("(No recorded stats)");
+ } else {
+ stats.dump(ipw);
+ }
+ ipw.decreaseIndent();
+ }
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
index 19b0d9b..fce8285 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
@@ -123,4 +123,14 @@
return value;
}
+
+ public static String getReasonName(int reason) {
+ if (reason == PackageManagerService.REASON_UNKNOWN) {
+ return "unknown";
+ }
+ if (reason < 0 || reason >= REASON_STRINGS.length) {
+ throw new IllegalArgumentException("reason " + reason + " invalid");
+ }
+ return REASON_STRINGS[reason];
+ }
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 758c9d5..d2ef67b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -34,6 +34,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.FeatureInfo;
import android.content.pm.IPackageDataObserver;
+import android.content.pm.IPackageInstaller;
import android.content.pm.IPackageManager;
import android.content.pm.InstrumentationInfo;
import android.content.pm.PackageInfo;
@@ -89,12 +90,7 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Map;
-import java.util.WeakHashMap;
+import java.util.*;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
@@ -235,6 +231,8 @@
return runSetHarmfulAppWarning();
case "get-harmful-app-warning":
return runGetHarmfulAppWarning();
+ case "uninstall-system-updates":
+ return uninstallSystemUpdates();
default: {
String nextArg = getNextArg();
if (nextArg == null) {
@@ -257,6 +255,47 @@
return -1;
}
+ private int uninstallSystemUpdates() {
+ final PrintWriter pw = getOutPrintWriter();
+ List<String> failedUninstalls = new LinkedList<>();
+ try {
+ final ParceledListSlice<ApplicationInfo> packages =
+ mInterface.getInstalledApplications(
+ PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
+ final IPackageInstaller installer = mInterface.getPackageInstaller();
+ List<ApplicationInfo> list = packages.getList();
+ for (ApplicationInfo info : list) {
+ if (info.isUpdatedSystemApp()) {
+ pw.println("Uninstalling updates to " + info.packageName + "...");
+ final LocalIntentReceiver receiver = new LocalIntentReceiver();
+ installer.uninstall(new VersionedPackage(info.packageName,
+ info.versionCode), null /*callerPackageName*/, 0 /* flags */,
+ receiver.getIntentSender(), 0);
+
+ final Intent result = receiver.getResult();
+ final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
+ PackageInstaller.STATUS_FAILURE);
+ if (status != PackageInstaller.STATUS_SUCCESS) {
+ failedUninstalls.add(info.packageName);
+ }
+ }
+ }
+ } catch (RemoteException e) {
+ pw.println("Failure ["
+ + e.getClass().getName() + " - "
+ + e.getMessage() + "]");
+ return 0;
+ }
+ if (!failedUninstalls.isEmpty()) {
+ pw.println("Failure [Couldn't uninstall packages: "
+ + TextUtils.join(", ", failedUninstalls)
+ + "]");
+ return 0;
+ }
+ pw.println("Success");
+ return 1;
+ }
+
private void setParamsSize(InstallParams params, String inPath) {
if (params.sessionParams.sizeBytes == -1 && !STDIN_PATH.equals(inPath)) {
final ParcelFileDescriptor fd = openFileForSystem(inPath, "r");
@@ -2705,6 +2744,10 @@
pw.println(" get-harmful-app-warning [--user <USER_ID>] <PACKAGE>");
pw.println(" Return the harmful app warning message for the given app, if present");
pw.println();
+ pw.println(" uninstall-system-updates");
+ pw.println(" Remove updates to all system applications and fall back to their /system " +
+ "version.");
+ pw.println();
Intent.printIntentArgsHelp(pw , "");
}
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index f14a684..a0ed126 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -46,19 +46,6 @@
private static final int[] EMPTY_INT_ARRAY = new int[0];
- /**
- * Indicates the state of installation. Used by PackageManager to figure out
- * incomplete installations. Say a package is being installed (the state is
- * set to PKG_INSTALL_INCOMPLETE) and remains so till the package
- * installation is successful or unsuccessful in which case the
- * PackageManager will no longer maintain state information associated with
- * the package. If some exception(like device freeze or battery being pulled
- * out) occurs during installation of a package, the PackageManager needs
- * this information to clean up the previously failed installation.
- */
- static final int PKG_INSTALL_COMPLETE = 1;
- static final int PKG_INSTALL_INCOMPLETE = 0;
-
public final String name;
final String realName;
@@ -122,8 +109,6 @@
// started until explicitly launched by the user.
private final SparseArray<PackageUserState> userState = new SparseArray<PackageUserState>();
- int installStatus = PKG_INSTALL_COMPLETE;
-
/**
* Non-persisted value. During an "upgrade without restart", we need the set
* of all previous code paths so we can surgically add the new APKs to the
@@ -209,14 +194,6 @@
return volumeUuid;
}
- public void setInstallStatus(int newStatus) {
- installStatus = newStatus;
- }
-
- public int getInstallStatus() {
- return installStatus;
- }
-
public void setTimeStamp(long newStamp) {
timeStamp = newStamp;
}
@@ -260,7 +237,6 @@
cpuAbiOverrideString = orig.cpuAbiOverrideString;
firstInstallTime = orig.firstInstallTime;
installPermissionsFixed = orig.installPermissionsFixed;
- installStatus = orig.installStatus;
installerPackageName = orig.installerPackageName;
isOrphaned = orig.isOrphaned;
keySetData = orig.keySetData;
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index b6e1534..b5fe9ea 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -455,15 +455,6 @@
return mRenamedPackages.put(pkgName, origPkgName);
}
- void setInstallStatus(String pkgName, final int status) {
- PackageSetting p = mPackages.get(pkgName);
- if(p != null) {
- if(p.getInstallStatus() != status) {
- p.setInstallStatus(status);
- }
- }
- }
-
void applyPendingPermissionGrantsLPw(String packageName, int userId) {
ArrayMap<String, ArraySet<RestoredPermissionGrant>> grantsByPackage =
mRestoredUserGrants.get(userId);
@@ -2839,9 +2830,6 @@
if (pkg.uidError) {
serializer.attribute(null, "uidError", "true");
}
- if (pkg.installStatus == PackageSettingBase.PKG_INSTALL_INCOMPLETE) {
- serializer.attribute(null, "installStatus", "false");
- }
if (pkg.installerPackageName != null) {
serializer.attribute(null, "installer", pkg.installerPackageName);
}
@@ -2912,20 +2900,6 @@
bp.writeLPr(serializer);
}
- ArrayList<PackageSetting> getListOfIncompleteInstallPackagesLPr() {
- final ArraySet<String> kList = new ArraySet<String>(mPackages.keySet());
- final Iterator<String> its = kList.iterator();
- final ArrayList<PackageSetting> ret = new ArrayList<PackageSetting>();
- while (its.hasNext()) {
- final String key = its.next();
- final PackageSetting ps = mPackages.get(key);
- if (ps.getInstallStatus() == PackageSettingBase.PKG_INSTALL_INCOMPLETE) {
- ret.add(ps);
- }
- }
- return ret;
- }
-
void addPackageToCleanLPw(PackageCleanItem pkg) {
if (!mPackagesToBeCleaned.contains(pkg)) {
mPackagesToBeCleaned.add(pkg);
@@ -3874,15 +3848,6 @@
mInstallerPackages.add(installerPackageName);
}
- final String installStatusStr = parser.getAttributeValue(null, "installStatus");
- if (installStatusStr != null) {
- if (installStatusStr.equalsIgnoreCase("false")) {
- packageSetting.installStatus = PackageSettingBase.PKG_INSTALL_INCOMPLETE;
- } else {
- packageSetting.installStatus = PackageSettingBase.PKG_INSTALL_COMPLETE;
- }
- }
-
int outerDepth = parser.getDepth();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -4668,7 +4633,7 @@
pw.print(prefix); pw.print(" signatures="); pw.println(ps.signatures);
pw.print(prefix); pw.print(" installPermissionsFixed=");
pw.print(ps.installPermissionsFixed);
- pw.print(" installStatus="); pw.println(ps.installStatus);
+ pw.println();
pw.print(prefix); pw.print(" pkgFlags="); printFlags(pw, ps.pkgFlags, FLAG_DUMP_SPEC);
pw.println();
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index a0577b1..0eeaf66 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1486,6 +1486,23 @@
return restrictions != null && restrictions.getBoolean(restrictionKey);
}
+ /** @return if any user has the given restriction. */
+ @Override
+ public boolean hasUserRestrictionOnAnyUser(String restrictionKey) {
+ if (!UserRestrictionsUtils.isValidRestriction(restrictionKey)) {
+ return false;
+ }
+ final List<UserInfo> users = getUsers(/* excludeDying= */ true);
+ for (int i = 0; i < users.size(); i++) {
+ final int userId = users.get(i).id;
+ Bundle restrictions = getEffectiveUserRestrictions(userId);
+ if (restrictions != null && restrictions.getBoolean(restrictionKey)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* @hide
*
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 23185d7..41570c4 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -33,6 +33,7 @@
import android.os.UserManager;
import android.os.UserManagerInternal;
import android.provider.Settings;
+import android.provider.Settings.Global;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.util.Log;
@@ -581,6 +582,15 @@
Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP, "0");
}
break;
+ case UserManager.DISALLOW_CONFIG_LOCATION:
+ // When DISALLOW_CONFIG_LOCATION is set on any user, we undo the global
+ // kill switch.
+ if (newValue) {
+ android.provider.Settings.Global.putString(
+ context.getContentResolver(),
+ Global.LOCATION_GLOBAL_KILL_SWITCH, "0");
+ }
+ break;
}
} finally {
Binder.restoreCallingIdentity(id);
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 0e2730c..3e63fb4 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -549,13 +549,12 @@
mPackageDexUsage.maybeWriteAsync();
}
- // Try to optimize the package according to the install reason.
- String compilerFilter = PackageManagerServiceCompilerMapping.getCompilerFilterForReason(
- PackageManagerService.REASON_INSTALL);
DexUseInfo dexUseInfo = mPackageDexUsage.getPackageUseInfo(searchResult.mOwningPackageName)
.getDexUseInfoMap().get(dexPath);
- DexoptOptions options = new DexoptOptions(info.packageName, compilerFilter, /*flags*/0);
+ // Try to optimize the package according to the install reason.
+ DexoptOptions options = new DexoptOptions(info.packageName,
+ PackageManagerService.REASON_INSTALL, /*flags*/0);
int result = mPackageDexOptimizer.dexOptSecondaryDexPath(info, dexPath, dexUseInfo,
options);
diff --git a/services/core/java/com/android/server/pm/dex/DexoptOptions.java b/services/core/java/com/android/server/pm/dex/DexoptOptions.java
index d4f95cb..a7a7686 100644
--- a/services/core/java/com/android/server/pm/dex/DexoptOptions.java
+++ b/services/core/java/com/android/server/pm/dex/DexoptOptions.java
@@ -77,15 +77,21 @@
// It only applies for primary apk and it's always null if mOnlySecondaryDex is true.
private final String mSplitName;
+ // The reason for invoking dexopt (see PackageManagerService.REASON_* constants).
+ // A -1 value denotes an unknown reason.
+ private final int mCompilationReason;
+
public DexoptOptions(String packageName, String compilerFilter, int flags) {
- this(packageName, compilerFilter, /*splitName*/ null, flags);
+ this(packageName, /*compilationReason*/ -1, compilerFilter, /*splitName*/ null, flags);
}
- public DexoptOptions(String packageName, int compilerReason, int flags) {
- this(packageName, getCompilerFilterForReason(compilerReason), flags);
+ public DexoptOptions(String packageName, int compilationReason, int flags) {
+ this(packageName, compilationReason, getCompilerFilterForReason(compilationReason),
+ /*splitName*/ null, flags);
}
- public DexoptOptions(String packageName, String compilerFilter, String splitName, int flags) {
+ public DexoptOptions(String packageName, int compilationReason, String compilerFilter,
+ String splitName, int flags) {
int validityMask =
DEXOPT_CHECK_FOR_PROFILES_UPDATES |
DEXOPT_FORCE |
@@ -104,6 +110,7 @@
mCompilerFilter = compilerFilter;
mFlags = flags;
mSplitName = splitName;
+ mCompilationReason = compilationReason;
}
public String getPackageName() {
@@ -157,4 +164,8 @@
public int getFlags() {
return mFlags;
}
+
+ public int getCompilationReason() {
+ return mCompilationReason;
+ }
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 0502848..d9bcc5c 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -1326,30 +1326,38 @@
// When interactive, we're already awake.
// Wait for a long press or for the button to be released to decide what to do.
if (hasLongPressOnPowerBehavior()) {
- Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
- msg.setAsynchronous(true);
- mHandler.sendMessageDelayed(msg,
- ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
+ if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
+ powerLongPress();
+ } else {
+ Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
+ msg.setAsynchronous(true);
+ mHandler.sendMessageDelayed(msg,
+ ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
- if (hasVeryLongPressOnPowerBehavior()) {
- Message longMsg = mHandler.obtainMessage(MSG_POWER_VERY_LONG_PRESS);
- longMsg.setAsynchronous(true);
- mHandler.sendMessageDelayed(longMsg, mVeryLongPressTimeout);
+ if (hasVeryLongPressOnPowerBehavior()) {
+ Message longMsg = mHandler.obtainMessage(MSG_POWER_VERY_LONG_PRESS);
+ longMsg.setAsynchronous(true);
+ mHandler.sendMessageDelayed(longMsg, mVeryLongPressTimeout);
+ }
}
}
} else {
wakeUpFromPowerKey(event.getDownTime());
if (mSupportLongPressPowerWhenNonInteractive && hasLongPressOnPowerBehavior()) {
- Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
- msg.setAsynchronous(true);
- mHandler.sendMessageDelayed(msg,
- ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
+ if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
+ powerLongPress();
+ } else {
+ Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
+ msg.setAsynchronous(true);
+ mHandler.sendMessageDelayed(msg,
+ ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
- if (hasVeryLongPressOnPowerBehavior()) {
- Message longMsg = mHandler.obtainMessage(MSG_POWER_VERY_LONG_PRESS);
- longMsg.setAsynchronous(true);
- mHandler.sendMessageDelayed(longMsg, mVeryLongPressTimeout);
+ if (hasVeryLongPressOnPowerBehavior()) {
+ Message longMsg = mHandler.obtainMessage(MSG_POWER_VERY_LONG_PRESS);
+ longMsg.setAsynchronous(true);
+ mHandler.sendMessageDelayed(longMsg, mVeryLongPressTimeout);
+ }
}
mBeganFromNonInteractive = true;
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index bd4aa1c..0a6b38f 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -451,7 +451,7 @@
// First send the high-level shut down broadcast.
mActionDone = false;
Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
- intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND | Intent.FLAG_RECEIVER_REGISTERED_ONLY);
mContext.sendOrderedBroadcastAsUser(intent,
UserHandle.ALL, null, br, mHandler, 0, null, null);
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java b/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java
index 37df94f..5d76329 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java
@@ -15,6 +15,7 @@
*/
package com.android.server.power.batterysaver;
+import android.metrics.LogMaker;
import android.os.BatteryManagerInternal;
import android.os.SystemClock;
import android.util.ArrayMap;
@@ -23,6 +24,8 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
import com.android.server.power.BatterySaverPolicy;
@@ -43,6 +46,9 @@
private static final boolean DEBUG = BatterySaverPolicy.DEBUG;
+ @VisibleForTesting
+ static final boolean SEND_TRON_EVENTS = true;
+
private final Object mLock = new Object();
/** Whether battery saver is on or off. */
@@ -132,15 +138,6 @@
}
}
- @VisibleForTesting
- static final String COUNTER_POWER_PERCENT_PREFIX = "battery_saver_stats_percent_";
-
- @VisibleForTesting
- static final String COUNTER_POWER_MILLIAMPS_PREFIX = "battery_saver_stats_milliamps_";
-
- @VisibleForTesting
- static final String COUNTER_TIME_SECONDS_PREFIX = "battery_saver_stats_seconds_";
-
private static BatterySavingStats sInstance;
private BatteryManagerInternal mBatteryManagerInternal;
@@ -427,10 +424,9 @@
if (stateChanging) {
if (mLastState >= 0) {
final long deltaTime = now - mStartTime;
- final int deltaBattery = mStartBatteryLevel - batteryLevel;
- final int deltaPercent = mStartPercent - batteryPercent;
- report(mLastState, deltaTime, deltaBattery, deltaPercent);
+ report(mLastState, deltaTime, mStartBatteryLevel, mStartPercent,
+ batteryLevel, batteryPercent);
}
mStartTime = now;
mStartBatteryLevel = batteryLevel;
@@ -439,23 +435,28 @@
mLastState = newState;
}
- String getCounterSuffix(int state) {
- final boolean batterySaver =
+ void report(int state, long deltaTimeMs,
+ int startBatteryLevelUa, int startBatteryLevelPercent,
+ int endBatteryLevelUa, int endBatteryLevelPercent) {
+ if (!SEND_TRON_EVENTS) {
+ return;
+ }
+ final boolean batterySaverOn =
BatterySaverState.fromIndex(state) != BatterySaverState.OFF;
final boolean interactive =
InteractiveState.fromIndex(state) != InteractiveState.NON_INTERACTIVE;
- if (batterySaver) {
- return interactive ? "11" : "10";
- } else {
- return interactive ? "01" : "00";
- }
- }
- void report(int state, long deltaTimeMs, int deltaBatteryUa, int deltaPercent) {
- final String suffix = getCounterSuffix(state);
- mMetricsLogger.count(COUNTER_POWER_MILLIAMPS_PREFIX + suffix, deltaBatteryUa / 1000);
- mMetricsLogger.count(COUNTER_POWER_PERCENT_PREFIX + suffix, deltaPercent);
- mMetricsLogger.count(COUNTER_TIME_SECONDS_PREFIX + suffix, (int) (deltaTimeMs / 1000));
+ final LogMaker logMaker = new LogMaker(MetricsProto.MetricsEvent.BATTERY_SAVER)
+ .setSubtype(batterySaverOn ? 1 : 0)
+ .addTaggedData(MetricsEvent.FIELD_INTERACTIVE, interactive ? 1 : 0)
+ .addTaggedData(MetricsEvent.FIELD_DURATION_MILLIS, deltaTimeMs)
+ .addTaggedData(MetricsEvent.FIELD_START_BATTERY_UA, startBatteryLevelUa)
+ .addTaggedData(MetricsEvent.FIELD_START_BATTERY_PERCENT,
+ startBatteryLevelPercent)
+ .addTaggedData(MetricsEvent.FIELD_END_BATTERY_UA, endBatteryLevelUa)
+ .addTaggedData(MetricsEvent.FIELD_END_BATTERY_PERCENT, endBatteryLevelPercent);
+
+ mMetricsLogger.write(logMaker);
}
}
}
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index ef6067a..fa7e535 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -172,7 +172,6 @@
public void sendSubscriberBroadcast(IBinder intentSenderBinder, long configUid, long configKey,
long subscriptionId, long subscriptionRuleId,
StatsDimensionsValue dimensionsValue) {
- if (DEBUG) Slog.d(TAG, "Statsd requested to sendSubscriberBroadcast.");
enforceCallingPermission();
IntentSender intentSender = new IntentSender(intentSenderBinder);
Intent intent = new Intent()
@@ -181,16 +180,16 @@
.putExtra(StatsManager.EXTRA_STATS_SUBSCRIPTION_ID, subscriptionId)
.putExtra(StatsManager.EXTRA_STATS_SUBSCRIPTION_RULE_ID, subscriptionRuleId)
.putExtra(StatsManager.EXTRA_STATS_DIMENSIONS_VALUE, dimensionsValue);
+ if (DEBUG) {
+ Slog.d(TAG, String.format("Statsd sendSubscriberBroadcast with params {%d %d %d %d %s}",
+ configUid, configKey, subscriptionId,
+ subscriptionRuleId, dimensionsValue));
+ }
try {
intentSender.sendIntent(mContext, CODE_SUBSCRIBER_BROADCAST, intent, null, null);
} catch (IntentSender.SendIntentException e) {
Slog.w(TAG, "Unable to send using IntentSender from uid " + configUid
+ "; presumably it had been cancelled.");
- if (DEBUG) {
- Slog.d(TAG, String.format("SubscriberBroadcast params {%d %d %d %d %s}",
- configUid, configKey, subscriptionId,
- subscriptionRuleId, dimensionsValue));
- }
}
}
@@ -290,7 +289,8 @@
public final static class AnomalyAlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
- Slog.i(TAG, "StatsCompanionService believes an anomaly has occurred.");
+ Slog.i(TAG, "StatsCompanionService believes an anomaly has occurred at time "
+ + System.currentTimeMillis() + "ms.");
synchronized (sStatsdLock) {
if (sStatsd == null) {
Slog.w(TAG, "Could not access statsd to inform it of anomaly alarm firing");
@@ -360,10 +360,11 @@
if (DEBUG) Slog.d(TAG, "Setting anomaly alarm for " + timestampMs);
final long callingToken = Binder.clearCallingIdentity();
try {
- // using RTC, not RTC_WAKEUP, so if device is asleep, will only fire when it awakens.
+ // using ELAPSED_REALTIME, not ELAPSED_REALTIME_WAKEUP, so if device is asleep, will
+ // only fire when it awakens.
// This alarm is inexact, leaving its exactness completely up to the OS optimizations.
// AlarmManager will automatically cancel any previous mAnomalyAlarmIntent alarm.
- mAlarmManager.set(AlarmManager.RTC, timestampMs, mAnomalyAlarmIntent);
+ mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME, timestampMs, mAnomalyAlarmIntent);
} finally {
Binder.restoreCallingIdentity(callingToken);
}
@@ -388,10 +389,12 @@
Slog.d(TAG, "Setting pulling alarm for " + timestampMs + " every " + intervalMs + "ms");
final long callingToken = Binder.clearCallingIdentity();
try {
- // using RTC, not RTC_WAKEUP, so if device is asleep, will only fire when it awakens.
+ // using ELAPSED_REALTIME, not ELAPSED_REALTIME_WAKEUP, so if device is asleep, will
+ // only fire when it awakens.
// This alarm is inexact, leaving its exactness completely up to the OS optimizations.
// TODO: totally inexact means that stats per bucket could be quite off. Is this okay?
- mAlarmManager.setRepeating(AlarmManager.RTC, timestampMs, intervalMs, mPullingAlarmIntent);
+ mAlarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME, timestampMs, intervalMs,
+ mPullingAlarmIntent);
} finally {
Binder.restoreCallingIdentity(callingToken);
}
@@ -783,7 +786,9 @@
enforceCallingPermission();
if (DEBUG) Slog.d(TAG, "learned that statsdReady");
sayHiToStatsd(); // tell statsd that we're ready too and link to it
- mContext.sendBroadcastAsUser(new Intent(StatsManager.ACTION_STATSD_STARTED),
+ mContext.sendBroadcastAsUser(
+ new Intent(StatsManager.ACTION_STATSD_STARTED)
+ .addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND),
UserHandle.SYSTEM,
android.Manifest.permission.DUMP);
}
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 2bdaa1a..0d36145 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -78,9 +78,12 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.res.Configuration;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.GraphicBuffer;
import android.graphics.Path;
+import android.graphics.Picture;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Binder;
@@ -96,11 +99,8 @@
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import android.view.AppTransitionAnimationSpec;
-import android.view.DisplayListCanvas;
import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.RemoteAnimationAdapter;
-import android.view.RenderNode;
-import android.view.ThreadedRenderer;
import android.view.WindowManager.TransitionFlags;
import android.view.WindowManager.TransitionType;
import android.view.animation.AlphaAnimation;
@@ -973,11 +973,8 @@
final int width = frame.width();
final int height = frame.height();
- final RenderNode node = RenderNode.create("CrossProfileAppsThumbnail", null);
- node.setLeftTopRightBottom(0, 0, width, height);
- node.setClipToBounds(false);
-
- final DisplayListCanvas canvas = node.start(width, height);
+ final Picture picture = new Picture();
+ final Canvas canvas = picture.beginRecording(width, height);
canvas.drawColor(Color.argb(0.6f, 0, 0, 0));
final int thumbnailSize = mService.mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.cross_profile_apps_thumbnail_size);
@@ -988,10 +985,9 @@
(width + thumbnailSize) / 2,
(height + thumbnailSize) / 2);
drawable.draw(canvas);
- node.end(canvas);
+ picture.endRecording();
- return ThreadedRenderer.createHardwareBitmap(node, width, height)
- .createGraphicBufferHandle();
+ return Bitmap.createBitmap(picture).createGraphicBufferHandle();
}
Animation createCrossProfileAppsThumbnailAnimationLocked(Rect appRect) {
diff --git a/services/core/java/com/android/server/wm/AppWindowThumbnail.java b/services/core/java/com/android/server/wm/AppWindowThumbnail.java
index db95634..3cd3e8b 100644
--- a/services/core/java/com/android/server/wm/AppWindowThumbnail.java
+++ b/services/core/java/com/android/server/wm/AppWindowThumbnail.java
@@ -53,8 +53,7 @@
AppWindowThumbnail(Transaction t, AppWindowToken appToken, GraphicBuffer thumbnailHeader) {
mAppToken = appToken;
- mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished,
- appToken.mService.mAnimator::addAfterPrepareSurfacesRunnable, appToken.mService);
+ mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished, appToken.mService);
mWidth = thumbnailHeader.getWidth();
mHeight = thumbnailHeader.getHeight();
@@ -145,11 +144,6 @@
}
@Override
- public void destroyAfterPendingTransaction(SurfaceControl surface) {
- mAppToken.destroyAfterPendingTransaction(surface);
- }
-
- @Override
public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {
t.setLayer(leash, Integer.MAX_VALUE);
}
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index ce3f512..8155656 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -1766,6 +1766,9 @@
layer += Z_BOOST_BASE;
}
leash.setLayer(layer);
+
+ final DisplayContent dc = getDisplayContent();
+ dc.assignStackOrdering(t);
}
/**
diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java
index 4394a99..a180a3a 100644
--- a/services/core/java/com/android/server/wm/Dimmer.java
+++ b/services/core/java/com/android/server/wm/Dimmer.java
@@ -55,11 +55,6 @@
}
@Override
- public void destroyAfterPendingTransaction(SurfaceControl surface) {
- mHost.destroyAfterPendingTransaction(surface);
- }
-
- @Override
public SurfaceControl.Builder makeAnimationLeash() {
return mHost.makeAnimationLeash();
}
@@ -119,7 +114,7 @@
if (!mDimming) {
mDimLayer.destroy();
}
- }, mHost.mService.mAnimator::addAfterPrepareSurfacesRunnable, mHost.mService);
+ }, mHost.mService);
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 41a6e2b..2d32c81 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -380,11 +380,6 @@
*/
private int mSurfaceSize;
- /**
- * A list of surfaces to be destroyed after {@link #mPendingTransaction} is applied.
- */
- private final ArrayList<SurfaceControl> mPendingDestroyingSurfaces = new ArrayList<>();
-
/** Temporary float array to retrieve 3x3 matrix values. */
private final float[] mTmpFloats = new float[9];
@@ -1935,10 +1930,6 @@
}
}
mService.mAnimator.removeDisplayLocked(mDisplayId);
-
- // The pending transaction won't be applied so we should
- // just clean up any surfaces pending destruction.
- onPendingTransactionApplied();
} finally {
mRemovingDisplay = false;
}
@@ -3533,39 +3524,47 @@
@Override
void assignChildLayers(SurfaceControl.Transaction t) {
+ assignStackOrdering(t);
+ for (int i = 0; i < mChildren.size(); i++) {
+ final TaskStack s = mChildren.get(i);
+ s.assignChildLayers(t);
+ }
+ }
+
+ void assignStackOrdering(SurfaceControl.Transaction t) {
final int HOME_STACK_STATE = 0;
final int NORMAL_STACK_STATE = 1;
final int ALWAYS_ON_TOP_STATE = 2;
int layer = 0;
+ int layerForAnimationLayer = 0;
+
for (int state = 0; state <= ALWAYS_ON_TOP_STATE; state++) {
for (int i = 0; i < mChildren.size(); i++) {
final TaskStack s = mChildren.get(i);
- if (state == HOME_STACK_STATE && s.isActivityTypeHome()) {
- s.assignLayer(t, layer++);
- } else if (state == NORMAL_STACK_STATE && !s.isActivityTypeHome()
- && !s.isAlwaysOnTop()) {
- s.assignLayer(t, layer++);
- if (s.inSplitScreenWindowingMode() && mSplitScreenDividerAnchor != null) {
- t.setLayer(mSplitScreenDividerAnchor, layer++);
- }
- } else if (state == ALWAYS_ON_TOP_STATE && s.isAlwaysOnTop()) {
- s.assignLayer(t, layer++);
+ if (state == HOME_STACK_STATE && !s.isActivityTypeHome()) {
+ continue;
+ } else if (state == NORMAL_STACK_STATE && (s.isActivityTypeHome()
+ || s.isAlwaysOnTop())) {
+ continue;
+ } else if (state == ALWAYS_ON_TOP_STATE && !s.isAlwaysOnTop()) {
+ continue;
+ }
+ s.assignLayer(t, layer++);
+ if (s.inSplitScreenWindowingMode() && mSplitScreenDividerAnchor != null) {
+ t.setLayer(mSplitScreenDividerAnchor, layer++);
+ }
+ if (s.isSelfOrChildAnimating()) {
+ // Ensure the animation layer ends up above the
+ // highest animating stack and no higher.
+ layerForAnimationLayer = layer++;
}
}
- // The appropriate place for App-Transitions to occur is right
- // above all other animations but still below things in the Picture-and-Picture
- // windowing mode.
- if (state == NORMAL_STACK_STATE && mAppAnimationLayer != null) {
- t.setLayer(mAppAnimationLayer, layer++);
- }
}
- for (int i = 0; i < mChildren.size(); i++) {
- final TaskStack s = mChildren.get(i);
- s.assignChildLayers(t);
+ if (mAppAnimationLayer != null) {
+ t.setLayer(mAppAnimationLayer, layerForAnimationLayer);
}
-
}
@Override
@@ -3847,22 +3846,6 @@
}
@Override
- public void destroyAfterPendingTransaction(SurfaceControl surface) {
- mPendingDestroyingSurfaces.add(surface);
- }
-
- /**
- * Destroys any surfaces that have been put into the pending list with
- * {@link #destroyAfterPendingTransaction}.
- */
- void onPendingTransactionApplied() {
- for (int i = mPendingDestroyingSurfaces.size() - 1; i >= 0; i--) {
- mPendingDestroyingSurfaces.get(i).destroy();
- }
- mPendingDestroyingSurfaces.clear();
- }
-
- @Override
void prepareSurfaces() {
final ScreenRotationAnimation screenRotationAnimation =
mService.mAnimator.getScreenRotationAnimationLocked(mDisplayId);
@@ -3876,6 +3859,11 @@
mPendingTransaction.setAlpha(mWindowingLayer,
screenRotationAnimation.getEnterTransformation().getAlpha());
}
+
super.prepareSurfaces();
}
+
+ void assignStackOrdering(SurfaceControl.Transaction t) {
+ mTaskStackContainers.assignStackOrdering(t);
+ }
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index e869f58..e4edeb87 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -24,15 +24,15 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import android.app.ActivityManager;
import android.app.ActivityManager.TaskSnapshot;
import android.app.WindowConfiguration;
-import android.graphics.GraphicBuffer;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Binder;
+import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
import android.view.IRecentsAnimationController;
@@ -41,6 +41,7 @@
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
+import com.google.android.collect.Sets;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -59,6 +60,7 @@
private final IRecentsAnimationRunner mRunner;
private final RecentsAnimationCallbacks mCallbacks;
private final ArrayList<TaskAnimationAdapter> mPendingAnimations = new ArrayList<>();
+ private final int mDisplayId;
// The recents component app token that is shown behind the visibile tasks
private AppWindowToken mHomeAppToken;
@@ -98,17 +100,13 @@
final TaskAnimationAdapter adapter = mPendingAnimations.get(i);
final Task task = adapter.mTask;
if (task.mTaskId == taskId) {
- // TODO: Save this screenshot as the task snapshot?
- final Rect taskFrame = new Rect();
- task.getBounds(taskFrame);
- final GraphicBuffer buffer = SurfaceControl.captureLayers(
- task.getSurfaceControl().getHandle(), taskFrame, 1f);
- final AppWindowToken topChild = task.getTopChild();
- final WindowState mainWindow = topChild.findMainWindow();
- return new TaskSnapshot(buffer, topChild.getConfiguration().orientation,
- mainWindow.mContentInsets,
- ActivityManager.isLowRamDeviceStatic() /* reduced */,
- 1.0f /* scale */);
+ final TaskSnapshotController snapshotController =
+ mService.mTaskSnapshotController;
+ final ArraySet<Task> tasks = Sets.newArraySet(task);
+ snapshotController.snapshotTasks(tasks);
+ snapshotController.addSkipClosingAppSnapshotTasks(tasks);
+ return snapshotController.getSnapshot(taskId, 0 /* userId */,
+ false /* restoreFromDisk */, false /* reducedResolution */);
}
}
return null;
@@ -159,8 +157,6 @@
};
/**
- * Initializes a new RecentsAnimationController.
- *
* @param remoteAnimationRunner The remote runner which should be notified when the animation is
* ready to start or has been canceled
* @param callbacks Callbacks to be made when the animation finishes
@@ -171,16 +167,19 @@
mService = service;
mRunner = remoteAnimationRunner;
mCallbacks = callbacks;
+ mDisplayId = displayId;
+ }
- final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
- final ArrayList<Task> visibleTasks = dc.getVisibleTasks();
- if (visibleTasks.isEmpty()) {
- cancelAnimation();
- return;
- }
-
+ /**
+ * Initializes the recents animation controller. This is a separate call from the constructor
+ * because it may call cancelAnimation() which needs to properly clean up the controller
+ * in the window manager.
+ */
+ public void initialize() {
// Make leashes for each of the visible tasks and add it to the recents animation to be
// started
+ final DisplayContent dc = mService.mRoot.getDisplayContent(mDisplayId);
+ final ArrayList<Task> visibleTasks = dc.getVisibleTasks();
final int taskCount = visibleTasks.size();
for (int i = 0; i < taskCount; i++) {
final Task task = visibleTasks.get(i);
@@ -193,6 +192,12 @@
addAnimation(task);
}
+ // Skip the animation if there is nothing to animate
+ if (mPendingAnimations.isEmpty()) {
+ cancelAnimation();
+ return;
+ }
+
// Adjust the wallpaper visibility for the showing home activity
final AppWindowToken recentsComponentAppToken =
dc.getHomeStack().getTopChild().getTopFullscreenAppToken();
@@ -214,7 +219,7 @@
private void addAnimation(Task task) {
if (DEBUG) Log.d(TAG, "addAnimation(" + task.getName() + ")");
final SurfaceAnimator anim = new SurfaceAnimator(task, null /* animationFinishedCallback */,
- mService.mAnimator::addAfterPrepareSurfacesRunnable, mService);
+ mService);
final TaskAnimationAdapter taskAdapter = new TaskAnimationAdapter(task);
anim.startAnimation(task.getPendingTransaction(), taskAdapter, false /* hidden */);
task.commitPendingTransaction();
@@ -222,8 +227,10 @@
}
void startAnimation() {
- if (DEBUG) Log.d(TAG, "startAnimation(): mPendingStart=" + mPendingStart);
- if (!mPendingStart) {
+ if (DEBUG) Log.d(TAG, "startAnimation(): mPendingStart=" + mPendingStart
+ + " mCanceled=" + mCanceled);
+ if (!mPendingStart || mCanceled) {
+ // Skip starting if we've already started or canceled the animation
return;
}
try {
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index c353c1d..ae0f412 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -96,13 +96,17 @@
// Scale the timeout with the animator scale the controlling app is using.
mHandler.postDelayed(mTimeoutRunnable,
(long) (TIMEOUT_MS * mService.getCurrentAnimatorScale()));
- try {
- mRemoteAnimationAdapter.getRunner().onAnimationStart(createAnimations(),
- mFinishedCallback);
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to start remote animation", e);
- onAnimationFinished();
- }
+
+ final RemoteAnimationTarget[] animations = createAnimations();
+ mService.mAnimator.addAfterPrepareSurfacesRunnable(() -> {
+ try {
+ mRemoteAnimationAdapter.getRunner().onAnimationStart(animations,
+ mFinishedCallback);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to start remote animation", e);
+ onAnimationFinished();
+ }
+ });
}
private RemoteAnimationTarget[] createAnimations() {
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index f5760e5..2fe55b9 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -588,6 +588,8 @@
"<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
}
+ mService.mAnimator.executeAfterPrepareSurfacesRunnables();
+
final WindowSurfacePlacer surfacePlacer = mService.mWindowPlacerLocked;
// If we are ready to perform an app transition, check through all of the app tokens to be
@@ -798,7 +800,6 @@
mService.enableScreenIfNeededLocked();
mService.scheduleAnimationLocked();
- mService.mWindowPlacerLocked.destroyPendingSurfaces();
if (DEBUG_WINDOW_TRACE) Slog.e(TAG,
"performSurfacePlacementInner exit: animating=" + mService.mAnimator.isAnimating());
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index 83baee1..37be149 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -33,7 +33,6 @@
import com.android.internal.annotations.VisibleForTesting;
import java.io.PrintWriter;
-import java.util.function.Consumer;
/**
* A class that can run animations on objects that have a set of child surfaces. We do this by
@@ -60,21 +59,17 @@
/**
* @param animatable The object to animate.
* @param animationFinishedCallback Callback to invoke when an animation has finished running.
- * @param addAfterPrepareSurfaces Consumer that takes a runnable and executes it after preparing
- * surfaces in WM. Can be implemented differently during testing.
*/
SurfaceAnimator(Animatable animatable, @Nullable Runnable animationFinishedCallback,
- Consumer<Runnable> addAfterPrepareSurfaces, WindowManagerService service) {
+ WindowManagerService service) {
mAnimatable = animatable;
mService = service;
mAnimationFinishedCallback = animationFinishedCallback;
- mInnerAnimationFinishedCallback = getFinishedCallback(animationFinishedCallback,
- addAfterPrepareSurfaces);
+ mInnerAnimationFinishedCallback = getFinishedCallback(animationFinishedCallback);
}
private OnAnimationFinishedCallback getFinishedCallback(
- @Nullable Runnable animationFinishedCallback,
- Consumer<Runnable> addAfterPrepareSurfaces) {
+ @Nullable Runnable animationFinishedCallback) {
return anim -> {
synchronized (mService.mWindowMap) {
final SurfaceAnimator target = mService.mAnimationTransferMap.remove(anim);
@@ -83,30 +78,13 @@
return;
}
- // TODO: This should use pendingTransaction eventually, but right now things
- // happening on the animation finished callback are happening on the global
- // transaction.
- // For now we need to run this after it's guaranteed that the transaction that
- // reparents the surface onto the leash is executed already. Otherwise this may be
- // executed first, leading to surface loss, as the reparent operations wouldn't
- // be in order.
- addAfterPrepareSurfaces.accept(() -> {
- if (anim != mAnimation) {
- // Callback was from another animation - ignore.
- return;
- }
- final Transaction t = new Transaction();
- SurfaceControl.openTransaction();
- try {
- reset(t, true /* destroyLeash */);
- if (animationFinishedCallback != null) {
- animationFinishedCallback.run();
- }
- } finally {
- SurfaceControl.mergeToGlobalTransaction(t);
- SurfaceControl.closeTransaction();
- }
- });
+ if (anim != mAnimation) {
+ return;
+ }
+ reset(mAnimatable.getPendingTransaction(), true /* destroyLeash */);
+ if (animationFinishedCallback != null) {
+ animationFinishedCallback.run();
+ }
}
};
}
@@ -290,7 +268,7 @@
}
mService.mAnimationTransferMap.remove(mAnimation);
if (mLeash != null && destroyLeash) {
- mAnimatable.destroyAfterPendingTransaction(mLeash);
+ t.destroy(mLeash);
}
mLeash = null;
mAnimation = null;
@@ -379,13 +357,6 @@
void onAnimationLeashDestroyed(Transaction t);
/**
- * Destroy a given surface after executing {@link #getPendingTransaction}.
- *
- * @see WindowContainer#destroyAfterPendingTransaction
- */
- void destroyAfterPendingTransaction(SurfaceControl surface);
-
- /**
* @return A new surface to be used for the animation leash, inserted at the correct
* position in the hierarchy.
*/
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index a7a2b53..3d7b32c 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -92,6 +92,7 @@
private final TaskSnapshotPersister mPersister = new TaskSnapshotPersister(
Environment::getDataSystemCeDirectory);
private final TaskSnapshotLoader mLoader = new TaskSnapshotLoader(mPersister);
+ private final ArraySet<Task> mSkipClosingAppSnapshotTasks = new ArraySet<>();
private final ArraySet<Task> mTmpTasks = new ArraySet<>();
private final Handler mHandler = new Handler();
@@ -149,10 +150,20 @@
// either closing or hidden.
getClosingTasks(closingApps, mTmpTasks);
snapshotTasks(mTmpTasks);
-
+ mSkipClosingAppSnapshotTasks.clear();
}
- private void snapshotTasks(ArraySet<Task> tasks) {
+ /**
+ * Adds the given {@param tasks} to the list of tasks which should not have their snapshots
+ * taken upon the next processing of the set of closing apps. The caller is responsible for
+ * calling {@link #snapshotTasks} to ensure that the task has an up-to-date snapshot.
+ */
+ @VisibleForTesting
+ void addSkipClosingAppSnapshotTasks(ArraySet<Task> tasks) {
+ mSkipClosingAppSnapshotTasks.addAll(tasks);
+ }
+
+ void snapshotTasks(ArraySet<Task> tasks) {
for (int i = tasks.size() - 1; i >= 0; i--) {
final Task task = tasks.valueAt(i);
final int mode = getSnapshotMode(task);
@@ -295,7 +306,7 @@
// If the task of the app is not visible anymore, it means no other app in that task
// is opening. Thus, the task is closing.
- if (task != null && !task.isVisible()) {
+ if (task != null && !task.isVisible() && !mSkipClosingAppSnapshotTasks.contains(task)) {
outClosingTasks.add(task);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 49a30d5..ab10197 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -92,6 +92,7 @@
* executed and the corresponding transaction is closed and applied.
*/
private final ArrayList<Runnable> mAfterPrepareSurfacesRunnables = new ArrayList<>();
+ private boolean mInExecuteAfterPrepareSurfacesRunnables;
WindowAnimator(final WindowManagerService service) {
mService = service;
@@ -225,13 +226,6 @@
if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION animate");
}
- final int numDisplays = mDisplayContentsAnimators.size();
- for (int i = 0; i < numDisplays; i++) {
- final int displayId = mDisplayContentsAnimators.keyAt(i);
- final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
- dc.onPendingTransactionApplied();
- }
-
boolean hasPendingLayoutChanges = mService.mRoot.hasPendingLayoutChanges(this);
boolean doRequest = false;
if (mBulkUpdateParams != 0) {
@@ -265,7 +259,6 @@
}
mService.destroyPreservedSurfaceLocked();
- mService.mWindowPlacerLocked.destroyPendingSurfaces();
executeAfterPrepareSurfacesRunnables();
@@ -434,11 +427,24 @@
* the corresponding transaction is closed and applied.
*/
void addAfterPrepareSurfacesRunnable(Runnable r) {
+ // If runnables are already being handled in executeAfterPrepareSurfacesRunnable, then just
+ // immediately execute the runnable passed in.
+ if (mInExecuteAfterPrepareSurfacesRunnables) {
+ r.run();
+ return;
+ }
+
mAfterPrepareSurfacesRunnables.add(r);
scheduleAnimation();
}
- private void executeAfterPrepareSurfacesRunnables() {
+ void executeAfterPrepareSurfacesRunnables() {
+
+ // Don't even think about to start recursing!
+ if (mInExecuteAfterPrepareSurfacesRunnables) {
+ return;
+ }
+ mInExecuteAfterPrepareSurfacesRunnables = true;
// Traverse in order they were added.
final int size = mAfterPrepareSurfacesRunnables.size();
@@ -446,5 +452,6 @@
mAfterPrepareSurfacesRunnables.get(i).run();
}
mAfterPrepareSurfacesRunnables.clear();
+ mInExecuteAfterPrepareSurfacesRunnables = false;
}
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 6bd7f22..93e9137 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -109,8 +109,7 @@
WindowContainer(WindowManagerService service) {
mService = service;
mPendingTransaction = service.mTransactionFactory.make();
- mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished,
- service.mAnimator::addAfterPrepareSurfacesRunnable, service);
+ mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished, service);
}
@Override
@@ -286,8 +285,9 @@
}
if (mSurfaceControl != null) {
- destroyAfterPendingTransaction(mSurfaceControl);
+ getPendingTransaction().destroy(mSurfaceControl);
mSurfaceControl = null;
+ scheduleAnimation();
}
if (mParent != null) {
@@ -1075,19 +1075,6 @@
return mSurfaceControl;
}
- /**
- * Destroy a given surface after executing mPendingTransaction. This is
- * largely a workaround for destroy not being part of transactions
- * rather than an intentional design, so please take care when
- * expanding use.
- */
- @Override
- public void destroyAfterPendingTransaction(SurfaceControl surface) {
- if (mParent != null) {
- mParent.destroyAfterPendingTransaction(surface);
- }
- }
-
@Override
public Transaction getPendingTransaction() {
return mPendingTransaction;
@@ -1142,7 +1129,7 @@
scheduleAnimation();
}
- private void reassignLayer(Transaction t) {
+ void reassignLayer(Transaction t) {
final WindowContainer parent = getParent();
if (parent != null) {
parent.assignChildLayers(t);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index c2ed2ae..966f622 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2680,6 +2680,7 @@
cancelRecentsAnimation();
mRecentsAnimationController = new RecentsAnimationController(this,
recentsAnimationRunner, callbacks, displayId);
+ mRecentsAnimationController.initialize();
}
}
@@ -2687,6 +2688,19 @@
return mRecentsAnimationController;
}
+ /**
+ * @return Whether the next recents animation can continue to start. Called from
+ * {@link RecentsAnimation#startRecentsActivity}.
+ */
+ public boolean canStartRecentsAnimation() {
+ synchronized (mWindowMap) {
+ if (mAppTransition.isTransitionSet()) {
+ return false;
+ }
+ return true;
+ }
+ }
+
public void cancelRecentsAnimation() {
synchronized (mWindowMap) {
if (mRecentsAnimationController != null) {
@@ -2991,7 +3005,9 @@
@Override
public void dismissKeyguard(IKeyguardDismissCallback callback, CharSequence message) {
- checkCallingPermission(permission.CONTROL_KEYGUARD, "dismissKeyguard");
+ if (!checkCallingPermission(permission.CONTROL_KEYGUARD, "dismissKeyguard")) {
+ throw new SecurityException("Requires CONTROL_KEYGUARD permission");
+ }
synchronized(mWindowMap) {
mPolicy.dismissKeyguardLw(callback, message);
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 21b4361..c1a1452 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -4067,7 +4067,9 @@
final boolean hasSurface = mWinAnimator.hasSurface();
if (hasSurface) {
- mWinAnimator.hide("onExitAnimationDone");
+ // Use pendingTransaction here so hide is done the same transaction as the other
+ // animations when exiting
+ mWinAnimator.hide(getPendingTransaction(), "onExitAnimationDone");
}
// If we have an app token, we ask it to destroy the surface for us, so that it can take
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 9621ee5..a699ba0 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -164,6 +164,8 @@
private boolean mAnimationStartDelayed;
+ private final SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction();
+
/** The pixel format of the underlying SurfaceControl */
int mSurfaceFormat;
@@ -280,16 +282,21 @@
}
}
- void hide(String reason) {
+ void hide(SurfaceControl.Transaction transaction, String reason) {
if (!mLastHidden) {
//dump();
mLastHidden = true;
if (mSurfaceController != null) {
- mSurfaceController.hideInTransaction(reason);
+ mSurfaceController.hide(transaction, reason);
}
}
}
+ void hide(String reason) {
+ hide(mTmpTransaction, reason);
+ SurfaceControl.mergeToGlobalTransaction(mTmpTransaction);
+ }
+
boolean finishDrawingLocked() {
final boolean startingWindow =
mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index 554a600..d88e59c 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -86,6 +86,8 @@
private final int mWindowType;
private final Session mWindowSession;
+ private final SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction();
+
public WindowSurfaceController(SurfaceSession s, String name, int w, int h, int format,
int flags, WindowStateAnimator animator, int windowType, int ownerUid) {
mAnimator = animator;
@@ -148,21 +150,23 @@
}
}
- void hideInTransaction(String reason) {
+ void hide(SurfaceControl.Transaction transaction, String reason) {
if (SHOW_TRANSACTIONS) logSurface("HIDE ( " + reason + " )", null);
mHiddenForOtherReasons = true;
mAnimator.destroyPreservedSurfaceLocked();
- updateVisibility();
+ if (mSurfaceShown) {
+ hideSurface(transaction);
+ }
}
- private void hideSurface() {
+ private void hideSurface(SurfaceControl.Transaction transaction) {
if (mSurfaceControl == null) {
return;
}
setShown(false);
try {
- mSurfaceControl.hide();
+ transaction.hide(mSurfaceControl);
} catch (RuntimeException e) {
Slog.w(TAG, "Exception hiding surface in " + this);
}
@@ -421,7 +425,8 @@
private boolean updateVisibility() {
if (mHiddenForCrop || mHiddenForOtherReasons) {
if (mSurfaceShown) {
- hideSurface();
+ hideSurface(mTmpTransaction);
+ SurfaceControl.mergeToGlobalTransaction(mTmpTransaction);
}
return false;
} else {
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 7364e87..272f3a5 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -102,7 +102,6 @@
}
private final LayerAndToken mTmpLayerAndToken = new LayerAndToken();
- private final ArrayList<SurfaceControl> mPendingDestroyingSurfaces = new ArrayList<>();
private final SparseIntArray mTempTransitionReasons = new SparseIntArray();
private final Runnable mPerformSurfacePlacement;
@@ -697,25 +696,6 @@
}
}
- /**
- * Puts the {@param surface} into a pending list to be destroyed after the current transaction
- * has been committed.
- */
- void destroyAfterTransaction(SurfaceControl surface) {
- mPendingDestroyingSurfaces.add(surface);
- }
-
- /**
- * Destroys any surfaces that have been put into the pending list with
- * {@link #destroyAfterTransaction}.
- */
- void destroyPendingSurfaces() {
- for (int i = mPendingDestroyingSurfaces.size() - 1; i >= 0; i--) {
- mPendingDestroyingSurfaces.get(i).destroy();
- }
- mPendingDestroyingSurfaces.clear();
- }
-
public void dump(PrintWriter pw, String prefix) {
pw.println(prefix + "mTraversalScheduled=" + mTraversalScheduled);
pw.println(prefix + "mHoldScreenWindow=" + mService.mRoot.mHoldScreenWindow);
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 72f95fb..0b03281 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -41,6 +41,7 @@
"com_android_server_tv_TvUinputBridge.cpp",
"com_android_server_tv_TvInputHal.cpp",
"com_android_server_vr_VrManagerService.cpp",
+ "com_android_server_UsbAlsaJackDetector.cpp",
"com_android_server_UsbDeviceManager.cpp",
"com_android_server_UsbDescriptorParser.cpp",
"com_android_server_UsbMidiDevice.cpp",
@@ -97,6 +98,7 @@
"libgui",
"libusbhost",
"libsuspend",
+ "libtinyalsa",
"libEGL",
"libGLESv2",
"libnetutils",
diff --git a/services/core/jni/com_android_server_UsbAlsaJackDetector.cpp b/services/core/jni/com_android_server_UsbAlsaJackDetector.cpp
new file mode 100644
index 0000000..e9d4482
--- /dev/null
+++ b/services/core/jni/com_android_server_UsbAlsaJackDetector.cpp
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "UsbAlsaJackDetectorJNI"
+#include "utils/Log.h"
+
+#include "jni.h"
+#include <nativehelper/JNIHelp.h>
+#include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/Log.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <asm/byteorder.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <tinyalsa/asoundlib.h>
+
+#define DRIVER_NAME "/dev/usb_accessory"
+
+#define USB_IN_JACK_NAME "USB in Jack"
+#define USB_OUT_JACK_NAME "USB out Jack"
+
+namespace android
+{
+
+static jboolean is_jack_connected(jint card, const char* control) {
+ struct mixer* card_mixer = mixer_open(card);
+ if (card_mixer == NULL) {
+ return true;
+ }
+ struct mixer_ctl* ctl = mixer_get_ctl_by_name(card_mixer, control);
+ if (!ctl) {
+ return true;
+ }
+ mixer_ctl_update(ctl);
+ int val = mixer_ctl_get_value(ctl, 0);
+ ALOGI("JACK %s - value %d\n", control, val);
+ mixer_close(card_mixer);
+
+ return val != 0;
+}
+
+static jboolean android_server_UsbAlsaJackDetector_hasJackDetect(JNIEnv* /* env */,
+ jobject /* thiz */,
+ jint card)
+{
+ struct mixer* card_mixer = mixer_open(card);
+ if (card_mixer == NULL) {
+ return false;
+ }
+
+ jboolean has_jack = false;
+ if ((mixer_get_ctl_by_name(card_mixer, USB_IN_JACK_NAME) != NULL) ||
+ (mixer_get_ctl_by_name(card_mixer, USB_OUT_JACK_NAME) != NULL)) {
+ has_jack = true;
+ }
+ mixer_close(card_mixer);
+ return has_jack;
+}
+
+
+static jboolean android_server_UsbAlsaJackDetector_inputJackConnected(JNIEnv* /* env */,
+ jobject /* thiz */,
+ jint card)
+{
+ return is_jack_connected(card, USB_IN_JACK_NAME);
+}
+
+
+static jboolean android_server_UsbAlsaJackDetector_outputJackConnected(JNIEnv* /* env */,
+ jobject /* thiz */,
+ jint card)
+{
+ return is_jack_connected(card, USB_OUT_JACK_NAME);
+}
+
+static void android_server_UsbAlsaJackDetector_jackDetect(JNIEnv* env,
+ jobject thiz,
+ jint card) {
+ jclass jdclass = env->GetObjectClass(thiz);
+ jmethodID method_jackDetectCallback = env->GetMethodID(jdclass, "jackDetectCallback", "()Z");
+ if (method_jackDetectCallback == NULL) {
+ ALOGE("Can't find jackDetectCallback");
+ return;
+ }
+
+ struct mixer* m = mixer_open(card);
+ if (!m) {
+ ALOGE("Jack detect unable to open mixer\n");
+ return;
+ }
+ mixer_subscribe_events(m, 1);
+ do {
+
+ // Wait for a mixer event. Retry if interrupted, exit on error.
+ int retval;
+ do {
+ retval = mixer_wait_event(m, -1);
+ } while (retval == -EINTR);
+ if (retval < 0) {
+ break;
+ }
+ mixer_consume_event(m);
+ } while (env->CallBooleanMethod(thiz, method_jackDetectCallback));
+
+ mixer_close(m);
+ return;
+}
+
+static const JNINativeMethod method_table[] = {
+ { "nativeHasJackDetect", "(I)Z", (void*)android_server_UsbAlsaJackDetector_hasJackDetect },
+ { "nativeInputJackConnected", "(I)Z",
+ (void*)android_server_UsbAlsaJackDetector_inputJackConnected },
+ { "nativeOutputJackConnected", "(I)Z",
+ (void*)android_server_UsbAlsaJackDetector_outputJackConnected },
+ { "nativeJackDetect", "(I)Z", (void*)android_server_UsbAlsaJackDetector_jackDetect },
+};
+
+int register_android_server_UsbAlsaJackDetector(JNIEnv *env)
+{
+ jclass clazz = env->FindClass("com/android/server/usb/UsbAlsaJackDetector");
+ if (clazz == NULL) {
+ ALOGE("Can't find com/android/server/usb/UsbAlsaJackDetector");
+ return -1;
+ }
+
+ if (!jniRegisterNativeMethods(env, "com/android/server/usb/UsbAlsaJackDetector",
+ method_table, NELEM(method_table))) {
+ ALOGE("Can't register UsbAlsaJackDetector native methods");
+ return -1;
+ }
+
+ return 0;
+}
+
+}
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index bf2a637..0ebef37 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -34,6 +34,7 @@
int register_android_server_storage_AppFuse(JNIEnv* env);
int register_android_server_SerialService(JNIEnv* env);
int register_android_server_SystemServer(JNIEnv* env);
+int register_android_server_UsbAlsaJackDetector(JNIEnv* env);
int register_android_server_UsbDeviceManager(JNIEnv* env);
int register_android_server_UsbMidiDevice(JNIEnv* env);
int register_android_server_UsbHostManager(JNIEnv* env);
@@ -82,6 +83,7 @@
register_android_server_AlarmManagerService(env);
register_android_server_UsbDeviceManager(env);
register_android_server_UsbMidiDevice(env);
+ register_android_server_UsbAlsaJackDetector(env);
register_android_server_UsbHostManager(env);
register_android_server_vr_VrManagerService(env);
register_android_server_VibratorService(env);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 75bb5e4..61c8b79 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -196,7 +196,7 @@
private static final String THERMAL_OBSERVER_CLASS =
"com.google.android.clockwork.ThermalObserver";
private static final String WEAR_CONNECTIVITY_SERVICE_CLASS =
- "com.google.android.clockwork.connectivity.WearConnectivityService";
+ "com.android.clockwork.connectivity.WearConnectivityService";
private static final String WEAR_SIDEKICK_SERVICE_CLASS =
"com.google.android.clockwork.sidekick.SidekickService";
private static final String WEAR_DISPLAY_SERVICE_CLASS =
diff --git a/services/robotests/src/com/android/server/backup/TransportManagerTest.java b/services/robotests/src/com/android/server/backup/TransportManagerTest.java
index 44ac803..503adb2 100644
--- a/services/robotests/src/com/android/server/backup/TransportManagerTest.java
+++ b/services/robotests/src/com/android/server/backup/TransportManagerTest.java
@@ -19,14 +19,12 @@
import static com.android.server.backup.testing.TransportData.genericTransport;
import static com.android.server.backup.testing.TransportTestUtils.mockTransport;
import static com.android.server.backup.testing.TransportTestUtils.setUpTransportsForTransportManager;
+
import static com.google.common.truth.Truth.assertThat;
-import static java.util.Arrays.asList;
-import static java.util.Collections.emptyList;
-import static java.util.Collections.singletonList;
-import static java.util.stream.Collectors.toList;
-import static java.util.stream.Collectors.toSet;
-import static java.util.stream.Stream.concat;
+
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
@@ -35,6 +33,13 @@
import static org.robolectric.shadow.api.Shadow.extract;
import static org.testng.Assert.expectThrows;
+import static java.util.Arrays.asList;
+import static java.util.Collections.emptyList;
+import static java.util.Collections.singletonList;
+import static java.util.stream.Collectors.toList;
+import static java.util.stream.Collectors.toSet;
+import static java.util.stream.Stream.concat;
+
import android.annotation.Nullable;
import android.app.backup.BackupManager;
import android.content.ComponentName;
@@ -43,6 +48,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.platform.test.annotations.Presubmit;
+
import com.android.server.backup.testing.ShadowContextImplForBackup;
import com.android.server.backup.testing.TransportData;
import com.android.server.backup.testing.TransportTestUtils.TransportMock;
@@ -54,11 +60,7 @@
import com.android.server.testing.SystemLoaderPackages;
import com.android.server.testing.shadows.FrameworkShadowContextImpl;
import com.android.server.testing.shadows.FrameworkShadowPackageManager;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-import java.util.Set;
-import java.util.stream.Stream;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -69,6 +71,12 @@
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowPackageManager;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Stream;
+
@RunWith(FrameworkRobolectricTestRunner.class)
@Config(
manifest = Config.NONE,
@@ -81,6 +89,12 @@
private static final String PACKAGE_A = "some.package.a";
private static final String PACKAGE_B = "some.package.b";
+ /**
+ * GMSCore depends on this constant so we define it here on top of the definition in
+ * {@link TransportManager} to verify this extra is passed
+ */
+ private static final String EXTRA_TRANSPORT_REGISTRATION = "transport_registration";
+
@Mock private OnTransportRegisteredListener mListener;
@Mock private TransportClientManager mTransportClientManager;
private TransportData mTransportA1;
@@ -195,6 +209,22 @@
}
@Test
+ public void testRegisterTransports_passesRegistrationExtraToGetTransportClient()
+ throws Exception {
+ setUpPackage(PACKAGE_A, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
+ setUpTransports(mTransportA1);
+ TransportManager transportManager = createTransportManager(mTransportA1);
+
+ transportManager.registerTransports();
+
+ verify(mTransportClientManager)
+ .getTransportClient(
+ eq(mTransportA1.getTransportComponent()),
+ argThat(bundle -> bundle.getBoolean(EXTRA_TRANSPORT_REGISTRATION)),
+ anyString());
+ }
+
+ @Test
public void testOnPackageAdded_registerTransports() throws Exception {
setUpPackage(PACKAGE_A, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
setUpTransports(mTransportA1);
@@ -580,6 +610,9 @@
when(mTransportClientManager.getTransportClient(
eq(transport.getTransportComponent()), any()))
.thenReturn(transportMock.transportClient);
+ when(mTransportClientManager.getTransportClient(
+ eq(transport.getTransportComponent()), any(), any()))
+ .thenReturn(transportMock.transportClient);
transportMocks.add(transportMock);
}
return transportMocks;
diff --git a/services/robotests/src/com/android/server/backup/transport/TransportClientManagerTest.java b/services/robotests/src/com/android/server/backup/transport/TransportClientManagerTest.java
new file mode 100644
index 0000000..5e3c974
--- /dev/null
+++ b/services/robotests/src/com/android/server/backup/transport/TransportClientManagerTest.java
@@ -0,0 +1,122 @@
+/*
+ * 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.backup.transport;
+
+import static com.android.server.backup.TransportManager.SERVICE_ACTION_TRANSPORT_HOST;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.argThat;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.platform.test.annotations.Presubmit;
+import com.android.server.testing.FrameworkRobolectricTestRunner;
+import com.android.server.testing.SystemLoaderPackages;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatcher;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+@RunWith(FrameworkRobolectricTestRunner.class)
+@Config(manifest = Config.NONE, sdk = 26)
+@SystemLoaderPackages({"com.android.server.backup"})
+@Presubmit
+public class TransportClientManagerTest {
+
+ private static final String PACKAGE_NAME = "random.package.name";
+ private static final String CLASS_NAME = "random.package.name.transport.Transport";
+
+ @Mock private Context mContext;
+ @Mock private TransportConnectionListener mTransportConnectionListener;
+ private TransportClientManager mTransportClientManager;
+ private ComponentName mTransportComponent;
+ private Intent mBindIntent;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mTransportClientManager = new TransportClientManager(mContext);
+ mTransportComponent = new ComponentName(PACKAGE_NAME, CLASS_NAME);
+ mBindIntent = new Intent(SERVICE_ACTION_TRANSPORT_HOST).setComponent(mTransportComponent);
+
+ when(mContext.bindServiceAsUser(
+ any(Intent.class),
+ any(ServiceConnection.class),
+ anyInt(),
+ any(UserHandle.class)))
+ .thenReturn(true);
+ }
+
+ @Test
+ public void testGetTransportClient_withExtras_createsTransportClientWithCorrectIntent() {
+ Bundle extras = new Bundle();
+ extras.putBoolean("random_extra", true);
+ mBindIntent.putExtras(extras);
+
+ TransportClient transportClient =
+ mTransportClientManager.getTransportClient(mTransportComponent, extras, "caller");
+
+ transportClient.connectAsync(mTransportConnectionListener, "caller");
+ verify(mContext)
+ .bindServiceAsUser(
+ argThat(matchesIntentAndExtras(mBindIntent)),
+ any(ServiceConnection.class),
+ anyInt(),
+ any(UserHandle.class));
+ }
+
+ private ArgumentMatcher<Intent> matchesIntentAndExtras(Intent expectedIntent) {
+ return (Intent actualIntent) -> {
+ if (!expectedIntent.filterEquals(actualIntent)) {
+ return false;
+ }
+
+ Bundle expectedExtras = expectedIntent.getExtras();
+ Bundle actualExtras = actualIntent.getExtras();
+
+ if (expectedExtras == null && actualExtras == null) {
+ return true;
+ }
+
+ if (expectedExtras == null || actualExtras == null) {
+ return false;
+ }
+
+ if (expectedExtras.size() != actualExtras.size()) {
+ return false;
+ }
+
+ for (String key : expectedExtras.keySet()) {
+ if (!expectedExtras.get(key).equals(actualExtras.get(key))) {
+ return false;
+ }
+ }
+
+ return true;
+ };
+ }
+}
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 97d6c43..5d8aca1 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -60,7 +60,6 @@
<uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" />
<uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<!-- Uses API introduced in O (26) -->
<uses-sdk android:minSdkVersion="1"
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java
index 07262e1..23fe0ff 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java
@@ -34,7 +34,6 @@
import android.annotation.NonNull;
import android.content.Context;
-import android.os.Handler;
import android.os.Message;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
@@ -49,9 +48,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.util.concurrent.CompletableFuture;
import java.util.function.IntConsumer;
-import java.util.function.Supplier;
/**
@@ -283,6 +280,19 @@
verify(mMgh.getNext(), times(2)).onMotionEvent(any(), any(), anyInt());
}
+ @Test
+ public void testTripleTapAndHold_zoomsImmediately() {
+ assertZoomsImmediatelyOnSwipeFrom(STATE_2TAPS);
+ assertZoomsImmediatelyOnSwipeFrom(STATE_SHORTCUT_TRIGGERED);
+ }
+
+ private void assertZoomsImmediatelyOnSwipeFrom(int state) {
+ goFromStateIdleTo(state);
+ swipeAndHold();
+ assertIn(STATE_DRAGGING_TMP);
+ returnToNormalFrom(STATE_DRAGGING_TMP);
+ }
+
private void assertTransition(int fromState, Runnable transitionAction, int toState) {
goFromStateIdleTo(fromState);
transitionAction.run();
@@ -339,11 +349,13 @@
check(tapCount() == 2, state);
} break;
case STATE_DRAGGING: {
+ check(isZoomed(), state);
check(mMgh.mCurrentState == mMgh.mViewportDraggingState,
state);
check(mMgh.mViewportDraggingState.mZoomedInBeforeDrag, state);
} break;
case STATE_DRAGGING_TMP: {
+ check(isZoomed(), state);
check(mMgh.mCurrentState == mMgh.mViewportDraggingState,
state);
check(!mMgh.mViewportDraggingState.mZoomedInBeforeDrag, state);
@@ -353,11 +365,13 @@
check(!isZoomed(), state);
} break;
case STATE_PANNING: {
+ check(isZoomed(), state);
check(mMgh.mCurrentState == mMgh.mPanningScalingState,
state);
check(!mMgh.mPanningScalingState.mScaling, state);
} break;
case STATE_SCALING_AND_PANNING: {
+ check(isZoomed(), state);
check(mMgh.mCurrentState == mMgh.mPanningScalingState,
state);
check(mMgh.mPanningScalingState.mScaling, state);
diff --git a/services/tests/servicestests/src/com/android/server/am/PendingRemoteAnimationRegistryTest.java b/services/tests/servicestests/src/com/android/server/am/PendingRemoteAnimationRegistryTest.java
new file mode 100644
index 0000000..2baf995
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/am/PendingRemoteAnimationRegistryTest.java
@@ -0,0 +1,103 @@
+/*
+ * 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.am;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import android.annotation.Nullable;
+import android.app.ActivityOptions;
+import android.os.Handler;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.FlakyTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.ArrayMap;
+import android.view.RemoteAnimationAdapter;
+
+import com.android.server.testutils.OffsettableClock;
+import com.android.server.testutils.TestHandler;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * atest PendingRemoteAnimationRegistryTest
+ */
+@SmallTest
+@Presubmit
+@FlakyTest
+@RunWith(AndroidJUnit4.class)
+public class PendingRemoteAnimationRegistryTest extends ActivityTestsBase {
+
+ @Mock RemoteAnimationAdapter mAdapter;
+ private PendingRemoteAnimationRegistry mRegistry;
+ private final OffsettableClock mClock = new OffsettableClock.Stopped();
+ private TestHandler mHandler;
+ private ActivityManagerService mService;
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ MockitoAnnotations.initMocks(this);
+ mService = createActivityManagerService();
+ mService.mHandlerThread.getThreadHandler().runWithScissors(() -> {
+ mHandler = new TestHandler(null, mClock);
+ }, 0);
+ mRegistry = new PendingRemoteAnimationRegistry(mService, mHandler);
+ }
+
+ @Test
+ public void testOverrideActivityOptions() {
+ mRegistry.addPendingAnimation("com.android.test", mAdapter);
+ ActivityOptions opts = ActivityOptions.makeBasic();
+ opts = mRegistry.overrideOptionsIfNeeded("com.android.test", opts);
+ assertEquals(mAdapter, opts.getRemoteAnimationAdapter());
+ }
+
+ @Test
+ public void testOverrideActivityOptions_null() {
+ mRegistry.addPendingAnimation("com.android.test", mAdapter);
+ final ActivityOptions opts = mRegistry.overrideOptionsIfNeeded("com.android.test", null);
+ assertNotNull(opts);
+ assertEquals(mAdapter, opts.getRemoteAnimationAdapter());
+ }
+
+ @Test
+ public void testTimeout() {
+ mRegistry.addPendingAnimation("com.android.test", mAdapter);
+ mClock.fastForward(5000);
+ mHandler.timeAdvance();
+ assertNull(mRegistry.overrideOptionsIfNeeded("com.android.test", null));
+ }
+
+ @Test
+ public void testTimeout_overridenEntry() {
+ mRegistry.addPendingAnimation("com.android.test", mAdapter);
+ mClock.fastForward(2500);
+ mHandler.timeAdvance();
+ mRegistry.addPendingAnimation("com.android.test", mAdapter);
+ mClock.fastForward(1000);
+ mHandler.timeAdvance();
+ final ActivityOptions opts = mRegistry.overrideOptionsIfNeeded("com.android.test", null);
+ assertEquals(mAdapter, opts.getRemoteAnimationAdapter());
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/SystemUpdatePolicyTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/SystemUpdatePolicyTest.java
index 98c428d..091d9bd 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/SystemUpdatePolicyTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/SystemUpdatePolicyTest.java
@@ -45,6 +45,7 @@
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.TimeUnit;
/**
* Unit tests for {@link android.app.admin.SystemUpdatePolicy}.
@@ -253,6 +254,147 @@
}
+ @Test
+ public void testInstallationOptionWithoutFreeze() {
+ // Also duplicated at com.google.android.gts.deviceowner.SystemUpdatePolicyTest
+ final long millis_2018_01_01 = TimeUnit.SECONDS.toMillis(1514764800);
+
+ SystemUpdatePolicy p = SystemUpdatePolicy.createAutomaticInstallPolicy();
+ assertInstallationOption(SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, Long.MAX_VALUE,
+ millis_2018_01_01, p);
+
+ p = SystemUpdatePolicy.createPostponeInstallPolicy();
+ assertInstallationOption(SystemUpdatePolicy.TYPE_POSTPONE, Long.MAX_VALUE,
+ millis_2018_01_01, p);
+
+ p = SystemUpdatePolicy.createWindowedInstallPolicy(120, 180); // 2:00 - 3:00
+ // 00:00 is two hours before the next window
+ assertInstallationOption(SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.HOURS.toMillis(2),
+ millis_2018_01_01, p);
+ // 02:00 is within the current maintenance window, and one hour until the window ends
+ assertInstallationOption(
+ SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.HOURS.toMillis(1),
+ millis_2018_01_01 + TimeUnit.HOURS.toMillis(2), p);
+ // 04:00 is 22 hours from the window next day
+ assertInstallationOption(SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.HOURS.toMillis(22),
+ millis_2018_01_01 + TimeUnit.HOURS.toMillis(4), p);
+
+ p = SystemUpdatePolicy.createWindowedInstallPolicy(22 * 60, 2 * 60); // 22:00 - 2:00
+ // 21:00 is one hour from the next window
+ assertInstallationOption(SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.HOURS.toMillis(1),
+ millis_2018_01_01 + TimeUnit.HOURS.toMillis(21), p);
+ // 00:00 is two hours from the end of current window
+ assertInstallationOption(
+ SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.HOURS.toMillis(2),
+ millis_2018_01_01, p);
+ // 03:00 is 22 hours from the window today
+ assertInstallationOption(SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.HOURS.toMillis(19),
+ millis_2018_01_01 + TimeUnit.HOURS.toMillis(3), p);
+ }
+
+ @Test
+ public void testInstallationOptionWithFreeze() throws Exception {
+ final long millis_2016_02_29 = TimeUnit.SECONDS.toMillis(1456704000);
+ final long millis_2017_01_31 = TimeUnit.SECONDS.toMillis(1485820800);
+ final long millis_2017_02_28 = TimeUnit.SECONDS.toMillis(1488240000);
+ final long millis_2018_01_01 = TimeUnit.SECONDS.toMillis(1514764800);
+ final long millis_2018_08_01 = TimeUnit.SECONDS.toMillis(1533081600);
+
+ SystemUpdatePolicy p = SystemUpdatePolicy.createAutomaticInstallPolicy();
+ setFreezePeriods(p, "01-01", "01-31");
+ // Inside a freeze period
+ assertInstallationOption(
+ SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(31),
+ millis_2018_01_01, p);
+ // Device is outside freeze between 2/28 to 12/31 inclusive
+ assertInstallationOption(
+ SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.DAYS.toMillis(307),
+ millis_2017_02_28, p);
+
+ // Freeze period contains leap day Feb 29
+ p = SystemUpdatePolicy.createPostponeInstallPolicy();
+ setFreezePeriods(p, "02-01", "03-15");
+ // Freezed until 3/31, note 2016 is a leap year
+ assertInstallationOption(SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(16),
+ millis_2016_02_29, p);
+ // Freezed until 3/31, note 2017 is not a leap year
+ assertInstallationOption(SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(16),
+ millis_2017_02_28, p);
+ // Next freeze is 2018/2/1
+ assertInstallationOption(SystemUpdatePolicy.TYPE_POSTPONE, TimeUnit.DAYS.toMillis(31),
+ millis_2018_01_01, p);
+
+ // Freeze period start on or right after leap day
+ p = SystemUpdatePolicy.createAutomaticInstallPolicy();
+ setFreezePeriods(p, "03-01", "03-31");
+ assertInstallationOption(
+ SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.DAYS.toMillis(1),
+ millis_2016_02_29, p);
+ assertInstallationOption(
+ SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.DAYS.toMillis(1),
+ millis_2017_02_28, p);
+ setFreezePeriods(p, "02-28", "03-15");
+ assertInstallationOption(
+ SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(16),
+ millis_2016_02_29, p);
+ assertInstallationOption(
+ SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(16),
+ millis_2017_02_28, p);
+
+ // Freeze period end on or right after leap day
+ p = SystemUpdatePolicy.createAutomaticInstallPolicy();
+ setFreezePeriods(p, "02-01", "02-28");
+ assertInstallationOption(
+ SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(1),
+ millis_2016_02_29, p);
+ assertInstallationOption(
+ SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(1),
+ millis_2017_02_28, p);
+ p = SystemUpdatePolicy.createAutomaticInstallPolicy();
+ setFreezePeriods(p, "02-01", "03-01");
+ assertInstallationOption(
+ SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(2),
+ millis_2016_02_29, p);
+ assertInstallationOption(
+ SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.DAYS.toMillis(2),
+ millis_2017_02_28, p);
+
+ // Freeze period with maintenance window
+ p = SystemUpdatePolicy.createWindowedInstallPolicy(23 * 60, 1 * 60); // 23:00 - 1:00
+ setFreezePeriods(p, "02-01", "02-28");
+ // 00:00 is within the current window, outside freeze period
+ assertInstallationOption(
+ SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.HOURS.toMillis(1),
+ millis_2018_01_01, p);
+ // Last day of feeze period, which ends in 22 hours
+ assertInstallationOption(
+ SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.HOURS.toMillis(22),
+ millis_2017_02_28 + TimeUnit.HOURS.toMillis(2), p);
+ // Last day before the next freeze, and within window
+ assertInstallationOption(
+ SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.HOURS.toMillis(1),
+ millis_2017_01_31, p);
+ // Last day before the next freeze, and there is still a partial maintenance window before
+ // the freeze.
+ assertInstallationOption(
+ SystemUpdatePolicy.TYPE_PAUSE, TimeUnit.HOURS.toMillis(19),
+ millis_2017_01_31 + TimeUnit.HOURS.toMillis(4), p);
+
+ // Two freeze periods
+ p = SystemUpdatePolicy.createAutomaticInstallPolicy();
+ setFreezePeriods(p, "05-01", "06-01", "12-01", "01-31");
+ // automatic policy for August, September, November and December
+ assertInstallationOption(
+ SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.DAYS.toMillis(122),
+ millis_2018_08_01, p);
+ }
+
+ private void assertInstallationOption(int expectedType, long expectedTime, long now,
+ SystemUpdatePolicy p) {
+ assertEquals(expectedType, p.getInstallationOptionAt(now).getType());
+ assertEquals(expectedTime, p.getInstallationOptionAt(now).getEffectiveTime());
+ }
+
private void testFreezePeriodsSucceeds(String...dates) throws Exception {
SystemUpdatePolicy p = SystemUpdatePolicy.createPostponeInstallPolicy();
setFreezePeriods(p, dates);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/OWNERS b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/OWNERS
new file mode 100644
index 0000000..bb487fb
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/OWNERS
@@ -0,0 +1,4 @@
+aseemk@google.com
+bozhu@google.com
+dementyev@google.com
+robertberry@google.com
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
index a523b86..8bd0df4 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
@@ -503,6 +503,30 @@
}
@Test
+ public void recoverKeys_doesNotThrowIfNoApplicationKeysToBeDecrypted() throws Exception {
+ mRecoverableKeyStoreManager.startRecoverySession(
+ TEST_SESSION_ID,
+ TEST_PUBLIC_KEY,
+ TEST_VAULT_PARAMS,
+ TEST_VAULT_CHALLENGE,
+ ImmutableList.of(new KeyChainProtectionParams(
+ TYPE_LOCKSCREEN,
+ UI_FORMAT_PASSWORD,
+ KeyDerivationParams.createSha256Params(TEST_SALT),
+ TEST_SECRET)));
+ byte[] keyClaimant = mRecoverySessionStorage.get(Binder.getCallingUid(), TEST_SESSION_ID)
+ .getKeyClaimant();
+ SecretKey recoveryKey = randomRecoveryKey();
+ byte[] encryptedClaimResponse = encryptClaimResponse(
+ keyClaimant, TEST_SECRET, TEST_VAULT_PARAMS, recoveryKey);
+
+ mRecoverableKeyStoreManager.recoverKeys(
+ TEST_SESSION_ID,
+ /*encryptedRecoveryKey=*/ encryptedClaimResponse,
+ /*applicationKeys=*/ ImmutableList.of());
+ }
+
+ @Test
public void recoverKeys_returnsDecryptedKeys() throws Exception {
mRecoverableKeyStoreManager.startRecoverySession(
TEST_SESSION_ID,
diff --git a/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java b/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java
index 6e1808b..28b54ef 100644
--- a/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java
@@ -323,6 +323,7 @@
private void turnBatteryOn() throws Exception {
executeCommand("cmd battery unplug");
+ executeCommand("cmd battery set status " + BatteryManager.BATTERY_STATUS_NOT_CHARGING);
assertBatteryOn();
}
@@ -336,6 +337,7 @@
private void turnBatteryOff() throws Exception {
executeCommand("cmd battery set ac " + BatteryManager.BATTERY_PLUGGED_AC);
+ executeCommand("cmd battery set status " + BatteryManager.BATTERY_STATUS_CHARGING);
}
private static void batteryReset() throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index 98483a8..53d97e7 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -612,7 +612,6 @@
assertThat(origPkgSetting.installerPackageName, is(testPkgSetting.installerPackageName));
assertThat(origPkgSetting.installPermissionsFixed,
is(testPkgSetting.installPermissionsFixed));
- assertThat(origPkgSetting.installStatus, is(testPkgSetting.installStatus));
assertThat(origPkgSetting.isOrphaned, is(testPkgSetting.isOrphaned));
assertSame(origPkgSetting.keySetData, testPkgSetting.keySetData);
assertThat(origPkgSetting.keySetData, is(testPkgSetting.keySetData));
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java
index f559986a..93064bc 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java
@@ -118,7 +118,7 @@
public void testCreateDexoptOptionsSplit() {
int flags = DexoptOptions.DEXOPT_FORCE | DexoptOptions.DEXOPT_BOOT_COMPLETE;
- DexoptOptions opt = new DexoptOptions(mPackageName, mCompilerFilter, mSplitName, flags);
+ DexoptOptions opt = new DexoptOptions(mPackageName, -1, mCompilerFilter, mSplitName, flags);
assertEquals(mPackageName, opt.getPackageName());
assertEquals(mCompilerFilter, opt.getCompilerFilter());
assertEquals(mSplitName, opt.getSplitName());
diff --git a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySavingStatsTest.java b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySavingStatsTest.java
index f7516b2..f7112d4 100644
--- a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySavingStatsTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySavingStatsTest.java
@@ -15,25 +15,30 @@
*/
package com.android.server.power.batterysaver;
+import static com.android.server.power.batterysaver.BatterySavingStats.SEND_TRON_EVENTS;
+
import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import android.metrics.LogMaker;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.server.power.batterysaver.BatterySavingStats.BatterySaverState;
import com.android.server.power.batterysaver.BatterySavingStats.DozeState;
import com.android.server.power.batterysaver.BatterySavingStats.InteractiveState;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
@@ -222,8 +227,28 @@
target.toDebugString());
}
- private void assertMetricsLog(String counter, int value) {
- verify(mMetricsLogger, times(1)).count(eq(counter), eq(value));
+ private void assertLog(boolean batterySaver, boolean interactive, long deltaTimeMs,
+ int deltaBatteryLevelUa, int deltaBatteryLevelPercent) {
+ if (SEND_TRON_EVENTS) {
+ ArgumentCaptor<LogMaker> ac = ArgumentCaptor.forClass(LogMaker.class);
+ verify(mMetricsLogger, times(1)).write(ac.capture());
+
+ LogMaker lm = ac.getValue();
+ assertEquals(MetricsEvent.BATTERY_SAVER, lm.getCategory());
+ assertEquals(batterySaver ? 1 : 0,
+ lm.getTaggedData(MetricsEvent.RESERVED_FOR_LOGBUILDER_SUBTYPE));
+ assertEquals(interactive ? 1 : 0, lm.getTaggedData(MetricsEvent.FIELD_INTERACTIVE));
+ assertEquals(deltaTimeMs, lm.getTaggedData(MetricsEvent.FIELD_DURATION_MILLIS));
+
+ assertEquals(deltaBatteryLevelUa,
+ (int) lm.getTaggedData(MetricsEvent.FIELD_START_BATTERY_UA)
+ - (int) lm.getTaggedData(MetricsEvent.FIELD_END_BATTERY_UA));
+ assertEquals(deltaBatteryLevelPercent,
+ (int) lm.getTaggedData(MetricsEvent.FIELD_START_BATTERY_PERCENT)
+ - (int) lm.getTaggedData(MetricsEvent.FIELD_END_BATTERY_PERCENT));
+ } else {
+ verify(mMetricsLogger, times(0)).write(any(LogMaker.class));
+ }
}
@Test
@@ -249,9 +274,7 @@
InteractiveState.NON_INTERACTIVE,
DozeState.NOT_DOZING);
- assertMetricsLog(BatterySavingStats.COUNTER_POWER_MILLIAMPS_PREFIX + "01", 2);
- assertMetricsLog(BatterySavingStats.COUNTER_POWER_PERCENT_PREFIX + "01", 200);
- assertMetricsLog(BatterySavingStats.COUNTER_TIME_SECONDS_PREFIX + "01", 60);
+ assertLog(false, true, 60_000, 2000, 200);
target.advanceClock(1);
target.drainBattery(2000);
@@ -282,9 +305,7 @@
InteractiveState.INTERACTIVE,
DozeState.NOT_DOZING);
- assertMetricsLog(BatterySavingStats.COUNTER_POWER_MILLIAMPS_PREFIX + "00", 2 * 3);
- assertMetricsLog(BatterySavingStats.COUNTER_POWER_PERCENT_PREFIX + "00", 200 * 3);
- assertMetricsLog(BatterySavingStats.COUNTER_TIME_SECONDS_PREFIX + "00", 60 * 3);
+ assertLog(false, false, 60_000 * 3, 2000 * 3, 200 * 3);
target.advanceClock(10);
target.drainBattery(10000);
@@ -292,9 +313,7 @@
reset(mMetricsLogger);
target.startCharging();
- assertMetricsLog(BatterySavingStats.COUNTER_POWER_MILLIAMPS_PREFIX + "11", 10);
- assertMetricsLog(BatterySavingStats.COUNTER_POWER_PERCENT_PREFIX + "11", 1000);
- assertMetricsLog(BatterySavingStats.COUNTER_TIME_SECONDS_PREFIX + "11", 60 * 10);
+ assertLog(true, true, 60_000 * 10, 10000, 1000);
target.advanceClock(1);
target.drainBattery(2000);
@@ -312,8 +331,6 @@
target.startCharging();
- assertMetricsLog(BatterySavingStats.COUNTER_POWER_MILLIAMPS_PREFIX + "10", 2);
- assertMetricsLog(BatterySavingStats.COUNTER_POWER_PERCENT_PREFIX + "10", 200);
- assertMetricsLog(BatterySavingStats.COUNTER_TIME_SECONDS_PREFIX + "10", 60);
+ assertLog(true, false, 60_000, 2000, 200);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/testutils/TestHandler.java b/services/tests/servicestests/src/com/android/server/testutils/TestHandler.java
index 029d9f1..1222b59 100644
--- a/services/tests/servicestests/src/com/android/server/testutils/TestHandler.java
+++ b/services/tests/servicestests/src/com/android/server/testutils/TestHandler.java
@@ -16,10 +16,11 @@
package com.android.server.testutils;
-import static android.util.ExceptionUtils.getRootCause;
+import static android.util.ExceptionUtils.appendCause;
import static android.util.ExceptionUtils.propagate;
import android.os.Handler;
+import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
import android.util.ArrayMap;
@@ -60,7 +61,7 @@
}
public TestHandler(Callback callback, LongSupplier clock) {
- super(callback);
+ super(Looper.getMainLooper(), callback);
mClock = clock;
}
@@ -132,7 +133,7 @@
} catch (Throwable t) {
// Append stack trace of this message being posted as a cause for a helpful
// test error message
- throw propagate(getRootCause(t).initCause(msg.postPoint));
+ throw propagate(appendCause(t, msg.postPoint));
} finally {
msg.message.recycle();
}
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 78b6077..cbbdca6 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -308,6 +308,7 @@
private void reportEvent(AppStandbyController controller, int eventType,
long elapsedTime) {
// Back to ACTIVE on event
+ mInjector.mElapsedRealtime = elapsedTime;
UsageEvents.Event ev = new UsageEvents.Event();
ev.mPackage = PACKAGE_1;
ev.mEventType = eventType;
@@ -487,6 +488,89 @@
}
@Test
+ public void testCascadingTimeouts() throws Exception {
+ setChargingState(mController, false);
+
+ reportEvent(mController, USER_INTERACTION, 0);
+ assertBucket(STANDBY_BUCKET_ACTIVE);
+
+ reportEvent(mController, NOTIFICATION_SEEN, 1000);
+ assertBucket(STANDBY_BUCKET_ACTIVE);
+
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET,
+ REASON_PREDICTED, 1000);
+ assertBucket(STANDBY_BUCKET_ACTIVE);
+
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
+ REASON_PREDICTED, 2000 + mController.mStrongUsageTimeoutMillis);
+ assertBucket(STANDBY_BUCKET_WORKING_SET);
+
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
+ REASON_PREDICTED, 2000 + mController.mNotificationSeenTimeoutMillis);
+ assertBucket(STANDBY_BUCKET_FREQUENT);
+ }
+
+ @Test
+ public void testOverlappingTimeouts() throws Exception {
+ setChargingState(mController, false);
+
+ reportEvent(mController, USER_INTERACTION, 0);
+ assertBucket(STANDBY_BUCKET_ACTIVE);
+
+ reportEvent(mController, NOTIFICATION_SEEN, 1000);
+ assertBucket(STANDBY_BUCKET_ACTIVE);
+
+ // Overlapping USER_INTERACTION before previous one times out
+ reportEvent(mController, USER_INTERACTION, mController.mStrongUsageTimeoutMillis - 1000);
+ assertBucket(STANDBY_BUCKET_ACTIVE);
+
+ // Still in ACTIVE after first USER_INTERACTION times out
+ mInjector.mElapsedRealtime = mController.mStrongUsageTimeoutMillis + 1000;
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
+ REASON_PREDICTED, mInjector.mElapsedRealtime);
+ assertBucket(STANDBY_BUCKET_ACTIVE);
+
+ // Both timed out, so NOTIFICATION_SEEN timeout should be effective
+ mInjector.mElapsedRealtime = mController.mStrongUsageTimeoutMillis * 2 + 2000;
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
+ REASON_PREDICTED, mInjector.mElapsedRealtime);
+ assertBucket(STANDBY_BUCKET_WORKING_SET);
+
+ mInjector.mElapsedRealtime = mController.mNotificationSeenTimeoutMillis + 2000;
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
+ REASON_PREDICTED, mInjector.mElapsedRealtime);
+ assertBucket(STANDBY_BUCKET_RARE);
+ }
+
+ @Test
+ public void testPredictionNotOverridden() throws Exception {
+ setChargingState(mController, false);
+
+ reportEvent(mController, USER_INTERACTION, 0);
+ assertBucket(STANDBY_BUCKET_ACTIVE);
+
+ mInjector.mElapsedRealtime = WORKING_SET_THRESHOLD - 1000;
+ reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime);
+ assertBucket(STANDBY_BUCKET_ACTIVE);
+
+ // Falls back to WORKING_SET
+ mInjector.mElapsedRealtime += 5000;
+ mController.checkIdleStates(USER_ID);
+ assertBucket(STANDBY_BUCKET_WORKING_SET);
+
+ // Predict to ACTIVE
+ mInjector.mElapsedRealtime += 1000;
+ mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
+ REASON_PREDICTED, mInjector.mElapsedRealtime);
+ assertBucket(STANDBY_BUCKET_ACTIVE);
+
+ // CheckIdleStates should not change the prediction
+ mInjector.mElapsedRealtime += 1000;
+ mController.checkIdleStates(USER_ID);
+ assertBucket(STANDBY_BUCKET_ACTIVE);
+ }
+
+ @Test
public void testAddActiveDeviceAdmin() {
assertActiveAdmins(USER_ID, (String[]) null);
assertActiveAdmins(USER_ID2, (String[]) null);
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
index b55c79b..79a9610 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
@@ -131,7 +131,6 @@
assertNoStartingWindow(controller.getAppWindowToken(mDisplayContent));
controller.getAppWindowToken(mDisplayContent).getParent().getParent().removeImmediately();
- mDisplayContent.onPendingTransactionApplied();
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
index 64c3037..a120eba 100644
--- a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
@@ -23,11 +23,11 @@
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.FlakyTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.view.SurfaceControl;
@@ -39,7 +39,6 @@
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -47,7 +46,6 @@
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
-import java.util.concurrent.CountDownLatch;
/**
* Test class for {@link SurfaceAnimatorTest}.
@@ -87,7 +85,7 @@
callbackCaptor.getValue().onAnimationFinished(mSpec);
assertNotAnimating(mAnimatable);
assertTrue(mAnimatable.mFinishedCallbackCalled);
- assertTrue(mAnimatable.mPendingDestroySurfaces.contains(mAnimatable.mLeash));
+ verify(mTransaction).destroy(eq(mAnimatable.mLeash));
// TODO: Verify reparenting once we use mPendingTransaction to reparent it back
}
@@ -97,7 +95,7 @@
final SurfaceControl firstLeash = mAnimatable.mLeash;
mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec2, true /* hidden */);
- assertTrue(mAnimatable.mPendingDestroySurfaces.contains(firstLeash));
+ verify(mTransaction).destroy(eq(firstLeash));
assertFalse(mAnimatable.mFinishedCallbackCalled);
final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass(
@@ -124,7 +122,7 @@
assertNotAnimating(mAnimatable);
verify(mSpec).onAnimationCancelled(any());
assertTrue(mAnimatable.mFinishedCallbackCalled);
- assertTrue(mAnimatable.mPendingDestroySurfaces.contains(mAnimatable.mLeash));
+ verify(mTransaction).destroy(eq(mAnimatable.mLeash));
}
@Test
@@ -145,7 +143,7 @@
verifyZeroInteractions(mSpec);
assertNotAnimating(mAnimatable);
assertTrue(mAnimatable.mFinishedCallbackCalled);
- assertTrue(mAnimatable.mPendingDestroySurfaces.contains(mAnimatable.mLeash));
+ verify(mTransaction).destroy(eq(mAnimatable.mLeash));
}
@Test
@@ -161,11 +159,11 @@
assertNotAnimating(mAnimatable);
assertAnimating(mAnimatable2);
assertEquals(leash, mAnimatable2.mSurfaceAnimator.mLeash);
- assertFalse(mAnimatable.mPendingDestroySurfaces.contains(leash));
+ verify(mTransaction, never()).destroy(eq(leash));
callbackCaptor.getValue().onAnimationFinished(mSpec);
assertNotAnimating(mAnimatable2);
assertTrue(mAnimatable2.mFinishedCallbackCalled);
- assertTrue(mAnimatable2.mPendingDestroySurfaces.contains(leash));
+ verify(mTransaction).destroy(eq(leash));
}
private void assertAnimating(MyAnimatable animatable) {
@@ -182,7 +180,6 @@
final SurfaceControl mParent;
final SurfaceControl mSurface;
- final ArrayList<SurfaceControl> mPendingDestroySurfaces = new ArrayList<>();
final SurfaceAnimator mSurfaceAnimator;
SurfaceControl mLeash;
boolean mFinishedCallbackCalled;
@@ -198,7 +195,7 @@
.build();
mFinishedCallbackCalled = false;
mLeash = null;
- mSurfaceAnimator = new SurfaceAnimator(this, mFinishedCallback, Runnable::run, sWm);
+ mSurfaceAnimator = new SurfaceAnimator(this, mFinishedCallback, sWm);
}
@Override
@@ -219,11 +216,6 @@
}
@Override
- public void destroyAfterPendingTransaction(SurfaceControl surface) {
- mPendingDestroySurfaces.add(surface);
- }
-
- @Override
public Builder makeAnimationLeash() {
return new SurfaceControl.Builder(mSession) {
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java
index 920796e..5650050 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java
@@ -29,6 +29,7 @@
import android.support.test.runner.AndroidJUnit4;
import android.util.ArraySet;
+import com.google.android.collect.Sets;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -74,6 +75,21 @@
}
@Test
+ public void testGetClosingApps_skipClosingAppsSnapshotTasks() throws Exception {
+ final WindowState closingWindow = createWindow(null, FIRST_APPLICATION_WINDOW,
+ "closingWindow");
+ closingWindow.mAppToken.setVisibility(null, false /* visible */, TRANSIT_UNSET,
+ true /* performLayout */, false /* isVoiceInteraction */);
+ final ArraySet<AppWindowToken> closingApps = new ArraySet<>();
+ closingApps.add(closingWindow.mAppToken);
+ final ArraySet<Task> closingTasks = new ArraySet<>();
+ sWm.mTaskSnapshotController.addSkipClosingAppSnapshotTasks(
+ Sets.newArraySet(closingWindow.mAppToken.getTask()));
+ sWm.mTaskSnapshotController.getClosingTasks(closingApps, closingTasks);
+ assertEquals(0, closingTasks.size());
+ }
+
+ @Test
public void testGetSnapshotMode() throws Exception {
final WindowState disabledWindow = createWindow(null,
FIRST_APPLICATION_WINDOW, mDisplayContent, "disabledWindow");
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
index a5fa903..a566327 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
@@ -15,10 +15,13 @@
*/
package com.android.server.notification;
+import static android.app.NotificationChannel.USER_LOCKED_IMPORTANCE;
import static android.service.notification.NotificationListenerService.Ranking
.USER_SENTIMENT_NEGATIVE;
import static android.service.notification.NotificationListenerService.Ranking
.USER_SENTIMENT_NEUTRAL;
+import static android.service.notification.NotificationListenerService.Ranking
+ .USER_SENTIMENT_POSITIVE;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
@@ -315,7 +318,7 @@
@Test
public void testImportance_locked_preUpgrade() throws Exception {
defaultChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
- defaultChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
+ defaultChannel.lockFields(USER_LOCKED_IMPORTANCE);
StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
false /* lights */, false /* defaultLights */, null /* group */);
@@ -327,7 +330,7 @@
@Test
public void testImportance_locked_unspecified_preUpgrade() throws Exception {
defaultChannel.setImportance(NotificationManager.IMPORTANCE_UNSPECIFIED);
- defaultChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
+ defaultChannel.lockFields(USER_LOCKED_IMPORTANCE);
StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
false /* lights */, false /* defaultLights */, null /* group */);
@@ -549,4 +552,23 @@
assertEquals(USER_SENTIMENT_NEGATIVE, record.getUserSentiment());
}
+
+ @Test
+ public void testUserSentiment_userLocked() throws Exception {
+ channel.lockFields(USER_LOCKED_IMPORTANCE);
+ StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
+ true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+ false /* lights */, false /* defaultLights */, groupId /* group */);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+
+ assertEquals(USER_SENTIMENT_POSITIVE, record.getUserSentiment());
+
+ Bundle signals = new Bundle();
+ signals.putInt(Adjustment.KEY_USER_SENTIMENT, USER_SENTIMENT_NEGATIVE);
+ record.addAdjustment(new Adjustment(pkg, record.getKey(), signals, null, sbn.getUserId()));
+
+ record.applyAdjustments();
+
+ assertEquals(USER_SENTIMENT_POSITIVE, record.getUserSentiment());
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java
index abfc54d..9ebce71 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java
@@ -914,16 +914,18 @@
final NotificationChannel update1 = getChannel();
update1.setSound(new Uri.Builder().scheme("test").build(),
new AudioAttributes.Builder().build());
- update1.lockFields(NotificationChannel.USER_LOCKED_PRIORITY); // should be ignored
+ update1.lockFields(NotificationChannel.USER_LOCKED_PRIORITY);
mHelper.updateNotificationChannel(PKG, UID, update1, true);
- assertEquals(NotificationChannel.USER_LOCKED_SOUND,
+ assertEquals(NotificationChannel.USER_LOCKED_PRIORITY
+ | NotificationChannel.USER_LOCKED_SOUND,
mHelper.getNotificationChannel(PKG, UID, update1.getId(), false)
.getUserLockedFields());
NotificationChannel update2 = getChannel();
update2.enableVibration(true);
mHelper.updateNotificationChannel(PKG, UID, update2, true);
- assertEquals(NotificationChannel.USER_LOCKED_SOUND
+ assertEquals(NotificationChannel.USER_LOCKED_PRIORITY
+ | NotificationChannel.USER_LOCKED_SOUND
| NotificationChannel.USER_LOCKED_VIBRATION,
mHelper.getNotificationChannel(PKG, UID, update2.getId(), false)
.getUserLockedFields());
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index c532a8a..6144c51 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -17,21 +17,32 @@
package com.android.server.notification;
import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertEquals;
import static junit.framework.TestCase.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import android.app.NotificationManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.Resources;
import android.media.AudioAttributes;
import android.provider.Settings;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.server.UiServiceTestCase;
import org.junit.Before;
@@ -46,15 +57,24 @@
public class ZenModeHelperTest extends UiServiceTestCase {
@Mock ConditionProviders mConditionProviders;
+ @Mock NotificationManager mNotificationManager;
+ @Mock private Resources mResources;
private TestableLooper mTestableLooper;
private ZenModeHelper mZenModeHelperSpy;
+ private Context mContext;
+ private ContentResolver mContentResolver;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mTestableLooper = TestableLooper.get(this);
- mZenModeHelperSpy = spy(new ZenModeHelper(getContext(), mTestableLooper.getLooper(),
+ mContext = spy(getContext());
+ mContentResolver = mContext.getContentResolver();
+ when(mContext.getResources()).thenReturn(mResources);
+ when(mContext.getSystemService(NotificationManager.class)).thenReturn(mNotificationManager);
+
+ mZenModeHelperSpy = spy(new ZenModeHelper(mContext, mTestableLooper.getLooper(),
mConditionProviders));
}
@@ -194,4 +214,31 @@
verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(shouldMute, usage);
}
}
+
+ @Test
+ public void testZenUpgradeNotification() {
+ // shows zen upgrade notification if stored settings says to shows, boot is completed
+ // and we're setting zen mode on
+ Settings.Global.putInt(mContentResolver, Settings.Global.SHOW_ZEN_UPGRADE_NOTIFICATION, 1);
+ mZenModeHelperSpy.mIsBootComplete = true;
+ mZenModeHelperSpy.setZenModeSetting(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+
+ verify(mZenModeHelperSpy, times(1)).createZenUpgradeNotification();
+ verify(mNotificationManager, times(1)).notify(eq(ZenModeHelper.TAG),
+ eq(SystemMessage.NOTE_ZEN_UPGRADE), any());
+ assertEquals(0, Settings.Global.getInt(mContentResolver,
+ Settings.Global.SHOW_ZEN_UPGRADE_NOTIFICATION, -1));
+ }
+
+ @Test
+ public void testNoZenUpgradeNotification() {
+ // doesn't show upgrade notification if stored settings says don't show
+ Settings.Global.putInt(mContentResolver, Settings.Global.SHOW_ZEN_UPGRADE_NOTIFICATION, 0);
+ mZenModeHelperSpy.mIsBootComplete = true;
+ mZenModeHelperSpy.setZenModeSetting(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+
+ verify(mZenModeHelperSpy, never()).createZenUpgradeNotification();
+ verify(mNotificationManager, never()).notify(eq(ZenModeHelper.TAG),
+ eq(SystemMessage.NOTE_ZEN_UPGRADE), any());
+ }
}
diff --git a/services/usage/java/com/android/server/usage/AppIdleHistory.java b/services/usage/java/com/android/server/usage/AppIdleHistory.java
index b654a66..f26c2ae 100644
--- a/services/usage/java/com/android/server/usage/AppIdleHistory.java
+++ b/services/usage/java/com/android/server/usage/AppIdleHistory.java
@@ -23,6 +23,7 @@
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_NEVER;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
+import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET;
import android.app.usage.UsageStatsManager;
import android.os.SystemClock;
@@ -87,7 +88,9 @@
// The last time a job was run for this app
private static final String ATTR_LAST_RUN_JOB_TIME = "lastJobRunTime";
// The time when the forced active state can be overridden.
- private static final String ATTR_BUCKET_TIMEOUT_TIME = "bucketTimeoutTime";
+ private static final String ATTR_BUCKET_ACTIVE_TIMEOUT_TIME = "activeTimeoutTime";
+ // The time when the forced working_set state can be overridden.
+ private static final String ATTR_BUCKET_WORKING_SET_TIMEOUT_TIME = "workingSetTimeoutTime";
// device on time = mElapsedDuration + (timeNow - mElapsedSnapshot)
private long mElapsedSnapshot; // Elapsed time snapshot when last write of mDeviceOnDuration
@@ -117,11 +120,15 @@
int lastInformedBucket;
// The last time a job was run for this app, using elapsed timebase
long lastJobRunTime;
- // When should the bucket state timeout, in elapsed timebase, if greater than
+ // When should the bucket active state timeout, in elapsed timebase, if greater than
// lastUsedElapsedTime.
// This is used to keep the app in a high bucket regardless of other timeouts and
// predictions.
- long bucketTimeoutTime;
+ long bucketActiveTimeoutTime;
+ // If there's a forced working_set state, this is when it times out. This can be sitting
+ // under any active state timeout, so that it becomes applicable after the active state
+ // timeout expires.
+ long bucketWorkingSetTimeoutTime;
}
AppIdleHistory(File storageDir, long elapsedRealtime) {
@@ -208,11 +215,28 @@
* @param packageName name of the app being updated, for logging purposes
* @param newBucket the bucket to set the app to
* @param elapsedRealtime mark as used time if non-zero
- * @param timeout set the timeout of the specified bucket, if non-zero
+ * @param timeout set the timeout of the specified bucket, if non-zero. Can only be used
+ * with bucket values of ACTIVE and WORKING_SET.
* @return
*/
public AppUsageHistory reportUsage(AppUsageHistory appUsageHistory, String packageName,
int newBucket, long elapsedRealtime, long timeout) {
+ // Set the timeout if applicable
+ if (timeout > elapsedRealtime) {
+ // Convert to elapsed timebase
+ final long timeoutTime = mElapsedDuration + (timeout - mElapsedSnapshot);
+ if (newBucket == STANDBY_BUCKET_ACTIVE) {
+ appUsageHistory.bucketActiveTimeoutTime = Math.max(timeoutTime,
+ appUsageHistory.bucketActiveTimeoutTime);
+ } else if (newBucket == STANDBY_BUCKET_WORKING_SET) {
+ appUsageHistory.bucketWorkingSetTimeoutTime = Math.max(timeoutTime,
+ appUsageHistory.bucketWorkingSetTimeoutTime);
+ } else {
+ throw new IllegalArgumentException("Cannot set a timeout on bucket=" +
+ newBucket);
+ }
+ }
+
if (elapsedRealtime != 0) {
appUsageHistory.lastUsedElapsedTime = mElapsedDuration
+ (elapsedRealtime - mElapsedSnapshot);
@@ -226,12 +250,6 @@
.currentBucket
+ ", reason=" + appUsageHistory.bucketingReason);
}
- if (timeout > elapsedRealtime) {
- // Convert to elapsed timebase
- appUsageHistory.bucketTimeoutTime =
- Math.max(appUsageHistory.bucketTimeoutTime,
- mElapsedDuration + (timeout - mElapsedSnapshot));
- }
}
appUsageHistory.bucketingReason = REASON_USAGE;
@@ -247,7 +265,8 @@
* @param userId
* @param newBucket the bucket to set the app to
* @param elapsedRealtime mark as used time if non-zero
- * @param timeout set the timeout of the specified bucket, if non-zero
+ * @param timeout set the timeout of the specified bucket, if non-zero. Can only be used
+ * with bucket values of ACTIVE and WORKING_SET.
* @return
*/
public AppUsageHistory reportUsage(String packageName, int userId, int newBucket,
@@ -504,8 +523,10 @@
parser.getAttributeValue(null, ATTR_BUCKETING_REASON);
appUsageHistory.lastJobRunTime = getLongValue(parser,
ATTR_LAST_RUN_JOB_TIME, Long.MIN_VALUE);
- appUsageHistory.bucketTimeoutTime = getLongValue(parser,
- ATTR_BUCKET_TIMEOUT_TIME, 0L);
+ appUsageHistory.bucketActiveTimeoutTime = getLongValue(parser,
+ ATTR_BUCKET_ACTIVE_TIMEOUT_TIME, 0L);
+ appUsageHistory.bucketWorkingSetTimeoutTime = getLongValue(parser,
+ ATTR_BUCKET_WORKING_SET_TIMEOUT_TIME, 0L);
if (appUsageHistory.bucketingReason == null) {
appUsageHistory.bucketingReason = REASON_DEFAULT;
}
@@ -557,9 +578,13 @@
xml.attribute(null, ATTR_CURRENT_BUCKET,
Integer.toString(history.currentBucket));
xml.attribute(null, ATTR_BUCKETING_REASON, history.bucketingReason);
- if (history.bucketTimeoutTime > 0) {
- xml.attribute(null, ATTR_BUCKET_TIMEOUT_TIME, Long.toString(history
- .bucketTimeoutTime));
+ if (history.bucketActiveTimeoutTime > 0) {
+ xml.attribute(null, ATTR_BUCKET_ACTIVE_TIMEOUT_TIME, Long.toString(history
+ .bucketActiveTimeoutTime));
+ }
+ if (history.bucketWorkingSetTimeoutTime > 0) {
+ xml.attribute(null, ATTR_BUCKET_WORKING_SET_TIMEOUT_TIME, Long.toString(history
+ .bucketWorkingSetTimeoutTime));
}
if (history.lastJobRunTime != Long.MIN_VALUE) {
xml.attribute(null, ATTR_LAST_RUN_JOB_TIME, Long.toString(history
@@ -593,14 +618,19 @@
continue;
}
idpw.print("package=" + packageName);
+ idpw.print(" userId=" + userId);
idpw.print(" lastUsedElapsed=");
TimeUtils.formatDuration(totalElapsedTime - appUsageHistory.lastUsedElapsedTime, idpw);
idpw.print(" lastUsedScreenOn=");
TimeUtils.formatDuration(screenOnTime - appUsageHistory.lastUsedScreenTime, idpw);
idpw.print(" lastPredictedTime=");
TimeUtils.formatDuration(totalElapsedTime - appUsageHistory.lastPredictedTime, idpw);
- idpw.print(" bucketTimeoutTime=");
- TimeUtils.formatDuration(totalElapsedTime - appUsageHistory.bucketTimeoutTime, idpw);
+ idpw.print(" bucketActiveTimeoutTime=");
+ TimeUtils.formatDuration(totalElapsedTime - appUsageHistory.bucketActiveTimeoutTime,
+ idpw);
+ idpw.print(" bucketWorkingSetTimeoutTime=");
+ TimeUtils.formatDuration(totalElapsedTime - appUsageHistory.bucketWorkingSetTimeoutTime,
+ idpw);
idpw.print(" lastJobRunTime=");
TimeUtils.formatDuration(totalElapsedTime - appUsageHistory.lastJobRunTime, idpw);
idpw.print(" idle=" + (isIdle(packageName, userId, elapsedRealtime) ? "y" : "n"));
diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java
index 32db752..c31809e 100644
--- a/services/usage/java/com/android/server/usage/AppStandbyController.java
+++ b/services/usage/java/com/android/server/usage/AppStandbyController.java
@@ -30,6 +30,7 @@
import static com.android.server.SystemService.PHASE_BOOT_COMPLETED;
import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY;
+import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.AppGlobals;
import android.app.usage.UsageStatsManager.StandbyBuckets;
@@ -171,6 +172,8 @@
static final int MSG_REPORT_CONTENT_PROVIDER_USAGE = 8;
static final int MSG_PAROLE_STATE_CHANGED = 9;
static final int MSG_ONE_TIME_CHECK_IDLE_STATES = 10;
+ /** Check the state of one app: arg1 = userId, arg2 = uid, obj = (String) packageName */
+ static final int MSG_CHECK_PACKAGE_IDLE_STATE = 11;
long mCheckIdleIntervalMillis;
long mAppIdleParoleIntervalMillis;
@@ -322,7 +325,7 @@
// Get sync adapters for the authority
String[] packages = ContentResolver.getSyncAdapterPackagesForAuthorityAsUser(
authority, userId);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long elapsedRealtime = mInjector.elapsedRealtime();
for (String packageName: packages) {
// Only force the sync adapters to active if the provider is not in the same package and
// the sync adapter is a system package.
@@ -460,53 +463,8 @@
for (int p = 0; p < packageCount; p++) {
final PackageInfo pi = packages.get(p);
final String packageName = pi.packageName;
- final boolean isSpecial = isAppSpecial(packageName,
- UserHandle.getAppId(pi.applicationInfo.uid),
- userId);
- if (DEBUG) {
- Slog.d(TAG, " Checking idle state for " + packageName + " special=" +
- isSpecial);
- }
- if (isSpecial) {
- synchronized (mAppIdleLock) {
- mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime,
- STANDBY_BUCKET_EXEMPTED, REASON_DEFAULT);
- }
- maybeInformListeners(packageName, userId, elapsedRealtime,
- STANDBY_BUCKET_EXEMPTED, false);
- } else {
- synchronized (mAppIdleLock) {
- AppIdleHistory.AppUsageHistory app =
- mAppIdleHistory.getAppUsageHistory(packageName,
- userId, elapsedRealtime);
- // If the bucket was forced by the developer or the app is within the
- // temporary active period, leave it alone.
- if (REASON_FORCED.equals(app.bucketingReason)
- || !hasBucketTimeoutPassed(app, elapsedRealtime)) {
- continue;
- }
- boolean predictionLate = false;
- // If the bucket was moved up due to usage, let the timeouts apply.
- if (REASON_DEFAULT.equals(app.bucketingReason)
- || REASON_USAGE.equals(app.bucketingReason)
- || REASON_TIMEOUT.equals(app.bucketingReason)
- || (predictionLate = predictionTimedOut(app, elapsedRealtime))) {
- int oldBucket = app.currentBucket;
- int newBucket = getBucketForLocked(packageName, userId,
- elapsedRealtime);
- if (DEBUG) {
- Slog.d(TAG, " Old bucket=" + oldBucket
- + ", newBucket=" + newBucket);
- }
- if (oldBucket < newBucket || predictionLate) {
- mAppIdleHistory.setAppStandbyBucket(packageName, userId,
- elapsedRealtime, newBucket, REASON_TIMEOUT);
- maybeInformListeners(packageName, userId, elapsedRealtime,
- newBucket, false);
- }
- }
- }
- }
+ checkAndUpdateStandbyState(packageName, userId, pi.applicationInfo.uid,
+ elapsedRealtime);
}
}
if (DEBUG) {
@@ -516,6 +474,90 @@
return true;
}
+ /** Check if we need to update the standby state of a specific app. */
+ private void checkAndUpdateStandbyState(String packageName, @UserIdInt int userId,
+ int uid, long elapsedRealtime) {
+ if (uid <= 0) {
+ try {
+ uid = mPackageManager.getPackageUidAsUser(packageName, userId);
+ } catch (PackageManager.NameNotFoundException e) {
+ // Not a valid package for this user, nothing to do
+ // TODO: Remove any history of removed packages
+ return;
+ }
+ }
+ final boolean isSpecial = isAppSpecial(packageName,
+ UserHandle.getAppId(uid),
+ userId);
+ if (DEBUG) {
+ Slog.d(TAG, " Checking idle state for " + packageName + " special=" +
+ isSpecial);
+ }
+ if (isSpecial) {
+ synchronized (mAppIdleLock) {
+ mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime,
+ STANDBY_BUCKET_EXEMPTED, REASON_DEFAULT);
+ }
+ maybeInformListeners(packageName, userId, elapsedRealtime,
+ STANDBY_BUCKET_EXEMPTED, false);
+ } else {
+ synchronized (mAppIdleLock) {
+ final AppIdleHistory.AppUsageHistory app =
+ mAppIdleHistory.getAppUsageHistory(packageName,
+ userId, elapsedRealtime);
+ String reason = app.bucketingReason;
+
+ // If the bucket was forced by the user/developer, leave it alone.
+ // A usage event will be the only way to bring it out of this forced state
+ if (REASON_FORCED.equals(app.bucketingReason)) {
+ return;
+ }
+ final int oldBucket = app.currentBucket;
+ int newBucket = Math.max(oldBucket, STANDBY_BUCKET_ACTIVE); // Undo EXEMPTED
+ boolean predictionLate = false;
+ // Compute age-based bucket
+ if (REASON_DEFAULT.equals(app.bucketingReason)
+ || REASON_USAGE.equals(app.bucketingReason)
+ || REASON_TIMEOUT.equals(app.bucketingReason)
+ || (predictionLate = predictionTimedOut(app, elapsedRealtime))) {
+ newBucket = getBucketForLocked(packageName, userId,
+ elapsedRealtime);
+ if (DEBUG) {
+ Slog.d(TAG, "Evaluated AOSP newBucket = " + newBucket);
+ }
+ reason = REASON_TIMEOUT;
+ }
+ // Check if the app is within one of the timeouts for forced bucket elevation
+ final long elapsedTimeAdjusted = mAppIdleHistory.getElapsedTime(elapsedRealtime);
+ if (newBucket >= STANDBY_BUCKET_ACTIVE
+ && app.bucketActiveTimeoutTime > elapsedTimeAdjusted) {
+ newBucket = STANDBY_BUCKET_ACTIVE;
+ reason = REASON_USAGE;
+ if (DEBUG) {
+ Slog.d(TAG, " Keeping at ACTIVE due to min timeout");
+ }
+ } else if (newBucket >= STANDBY_BUCKET_WORKING_SET
+ && app.bucketWorkingSetTimeoutTime > elapsedTimeAdjusted) {
+ newBucket = STANDBY_BUCKET_WORKING_SET;
+ reason = REASON_USAGE;
+ if (DEBUG) {
+ Slog.d(TAG, " Keeping at WORKING_SET due to min timeout");
+ }
+ }
+ if (DEBUG) {
+ Slog.d(TAG, " Old bucket=" + oldBucket
+ + ", newBucket=" + newBucket);
+ }
+ if (oldBucket < newBucket || predictionLate) {
+ mAppIdleHistory.setAppStandbyBucket(packageName, userId,
+ elapsedRealtime, newBucket, reason);
+ maybeInformListeners(packageName, userId, elapsedRealtime,
+ newBucket, false);
+ }
+ }
+ }
+ }
+
private boolean predictionTimedOut(AppIdleHistory.AppUsageHistory app, long elapsedRealtime) {
return app.bucketingReason != null
&& app.bucketingReason.startsWith(REASON_PREDICTED)
@@ -526,7 +568,9 @@
private boolean hasBucketTimeoutPassed(AppIdleHistory.AppUsageHistory app,
long elapsedRealtime) {
- return app.bucketTimeoutTime < mAppIdleHistory.getElapsedTime(elapsedRealtime);
+ final long elapsedTimeAdjusted = mAppIdleHistory.getElapsedTime(elapsedRealtime);
+ return app.bucketActiveTimeoutTime < elapsedTimeAdjusted
+ && app.bucketWorkingSetTimeoutTime < elapsedTimeAdjusted;
}
private void maybeInformListeners(String packageName, int userId,
@@ -631,16 +675,22 @@
event.mPackage, userId, elapsedRealtime);
final int prevBucket = appHistory.currentBucket;
final String prevBucketReason = appHistory.bucketingReason;
+ final long nextCheckTime;
if (event.mEventType == UsageEvents.Event.NOTIFICATION_SEEN) {
+ // Mild usage elevates to WORKING_SET but doesn't change usage time.
mAppIdleHistory.reportUsage(appHistory, event.mPackage,
STANDBY_BUCKET_WORKING_SET,
- elapsedRealtime, elapsedRealtime + mNotificationSeenTimeoutMillis);
+ 0, elapsedRealtime + mNotificationSeenTimeoutMillis);
+ nextCheckTime = mNotificationSeenTimeoutMillis;
} else {
- mAppIdleHistory.reportUsage(event.mPackage, userId,
+ mAppIdleHistory.reportUsage(appHistory, event.mPackage,
STANDBY_BUCKET_ACTIVE,
elapsedRealtime, elapsedRealtime + mStrongUsageTimeoutMillis);
+ nextCheckTime = mStrongUsageTimeoutMillis;
}
-
+ mHandler.sendMessageDelayed(mHandler.obtainMessage
+ (MSG_CHECK_PACKAGE_IDLE_STATE, userId, -1, event.mPackage),
+ nextCheckTime);
final boolean userStartedInteracting =
appHistory.currentBucket == STANDBY_BUCKET_ACTIVE &&
prevBucket != appHistory.currentBucket &&
@@ -932,9 +982,24 @@
// If the bucket is required to stay in a higher state for a specified duration, don't
// override unless the duration has passed
- if (predicted && app.currentBucket < newBucket
- && !hasBucketTimeoutPassed(app, elapsedRealtime)) {
- return;
+ if (predicted) {
+ // Check if the app is within one of the timeouts for forced bucket elevation
+ final long elapsedTimeAdjusted = mAppIdleHistory.getElapsedTime(elapsedRealtime);
+ if (newBucket > STANDBY_BUCKET_ACTIVE
+ && app.bucketActiveTimeoutTime > elapsedTimeAdjusted) {
+ newBucket = STANDBY_BUCKET_ACTIVE;
+ reason = REASON_USAGE;
+ if (DEBUG) {
+ Slog.d(TAG, " Keeping at ACTIVE due to min timeout");
+ }
+ } else if (newBucket > STANDBY_BUCKET_WORKING_SET
+ && app.bucketWorkingSetTimeoutTime > elapsedTimeAdjusted) {
+ newBucket = STANDBY_BUCKET_WORKING_SET;
+ reason = REASON_USAGE;
+ if (DEBUG) {
+ Slog.d(TAG, " Keeping at WORKING_SET due to min timeout");
+ }
+ }
}
mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime, newBucket,
@@ -1347,6 +1412,10 @@
+ ", Charging state:" + mCharging);
informParoleStateChanged();
break;
+ case MSG_CHECK_PACKAGE_IDLE_STATE:
+ checkAndUpdateStandbyState((String) msg.obj, msg.arg1, msg.arg2,
+ mInjector.elapsedRealtime());
+ break;
default:
super.handleMessage(msg);
break;
diff --git a/services/usb/OWNERS b/services/usb/OWNERS
new file mode 100644
index 0000000..7897a0c
--- /dev/null
+++ b/services/usb/OWNERS
@@ -0,0 +1,4 @@
+badhri@google.com
+elaurent@google.com
+moltmann@google.com
+zhangjerry@google.com
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaDevice.java b/services/usb/java/com/android/server/usb/UsbAlsaDevice.java
index 7480e56..9d4db00 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaDevice.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaDevice.java
@@ -17,9 +17,14 @@
package com.android.server.usb;
import android.annotation.NonNull;
+import android.media.AudioSystem;
+import android.media.IAudioService;
+import android.os.RemoteException;
import android.service.usb.UsbAlsaDeviceProto;
+import android.util.Slog;
import com.android.internal.util.dump.DualDumpOutputStream;
+import com.android.server.audio.AudioService;
/**
* Represents the ALSA specification, and attributes of an ALSA device.
@@ -30,25 +35,31 @@
private final int mCardNum;
private final int mDeviceNum;
- private final boolean mHasPlayback;
- private final boolean mHasCapture;
+ private final String mDeviceAddress;
+ private final boolean mHasOutput;
+ private final boolean mHasInput;
private final boolean mIsInputHeadset;
private final boolean mIsOutputHeadset;
- private final String mDeviceAddress;
+ private boolean mSelected = false;
+ private int mOutputState;
+ private int mInputState;
+ private UsbAlsaJackDetector mJackDetector;
+ private IAudioService mAudioService;
private String mDeviceName = "";
private String mDeviceDescription = "";
- public UsbAlsaDevice(int card, int device, String deviceAddress,
- boolean hasPlayback, boolean hasCapture,
+ public UsbAlsaDevice(IAudioService audioService, int card, int device, String deviceAddress,
+ boolean hasOutput, boolean hasInput,
boolean isInputHeadset, boolean isOutputHeadset) {
+ mAudioService = audioService;
mCardNum = card;
mDeviceNum = device;
mDeviceAddress = deviceAddress;
- mHasPlayback = hasPlayback;
- mHasCapture = hasCapture;
+ mHasOutput = hasOutput;
+ mHasInput = hasInput;
mIsInputHeadset = isInputHeadset;
mIsOutputHeadset = isOutputHeadset;
}
@@ -75,71 +86,187 @@
}
/**
- * @returns true if the device supports playback.
+ * @returns the ALSA card/device address string.
*/
- public boolean hasPlayback() {
- return mHasPlayback;
+ public String getAlsaCardDeviceString() {
+ if (mCardNum < 0 || mDeviceNum < 0) {
+ Slog.e(TAG, "Invalid alsa card or device alsaCard: " + mCardNum
+ + " alsaDevice: " + mDeviceNum);
+ return null;
+ }
+ return AudioService.makeAlsaAddressString(mCardNum, mDeviceNum);
}
/**
- * @returns true if the device supports capture (recording).
+ * @returns true if the device supports output.
*/
- public boolean hasCapture() {
- return mHasCapture;
+ public boolean hasOutput() {
+ return mHasOutput;
}
/**
- * @returns true if the device is a headset for purposes of capture.
+ * @returns true if the device supports input (recording).
+ */
+ public boolean hasInput() {
+ return mHasInput;
+ }
+
+ /**
+ * @returns true if the device is a headset for purposes of input.
*/
public boolean isInputHeadset() {
return mIsInputHeadset;
}
/**
- * @returns true if the device is a headset for purposes of playback.
+ * @returns true if the device is a headset for purposes of output.
*/
public boolean isOutputHeadset() {
return mIsOutputHeadset;
}
/**
+ * @returns true if input jack is detected or jack detection is not supported.
+ */
+ private synchronized boolean isInputJackConnected() {
+ if (mJackDetector == null) {
+ return true; // If jack detect isn't supported, say it's connected.
+ }
+ return mJackDetector.isInputJackConnected();
+ }
+
+ /**
+ * @returns true if input jack is detected or jack detection is not supported.
+ */
+ private synchronized boolean isOutputJackConnected() {
+ if (mJackDetector == null) {
+ return true; // if jack detect isn't supported, say it's connected.
+ }
+ return mJackDetector.isOutputJackConnected();
+ }
+
+ /** Begins a jack-detection thread. */
+ private synchronized void startJackDetect() {
+ // If no jack detect capabilities exist, mJackDetector will be null.
+ mJackDetector = UsbAlsaJackDetector.startJackDetect(this);
+ }
+
+ /** Stops a jack-detection thread. */
+ private synchronized void stopJackDetect() {
+ if (mJackDetector != null) {
+ mJackDetector.pleaseStop();
+ }
+ mJackDetector = null;
+ }
+
+ /** Start using this device as the selected USB Audio Device. */
+ public synchronized void start() {
+ mSelected = true;
+ mInputState = 0;
+ mOutputState = 0;
+ startJackDetect();
+ updateWiredDeviceConnectionState(true);
+ }
+
+ /** Stop using this device as the selected USB Audio Device. */
+ public synchronized void stop() {
+ stopJackDetect();
+ updateWiredDeviceConnectionState(false);
+ mSelected = false;
+ }
+
+ /** Updates AudioService with the connection state of the alsaDevice.
+ * Checks ALSA Jack state for inputs and outputs before reporting.
+ */
+ public synchronized void updateWiredDeviceConnectionState(boolean enable) {
+ if (!mSelected) {
+ Slog.e(TAG, "updateWiredDeviceConnectionState on unselected AlsaDevice!");
+ return;
+ }
+ String alsaCardDeviceString = getAlsaCardDeviceString();
+ if (alsaCardDeviceString == null) {
+ return;
+ }
+ try {
+ // Output Device
+ if (mHasOutput) {
+ int device = mIsOutputHeadset
+ ? AudioSystem.DEVICE_OUT_USB_HEADSET
+ : AudioSystem.DEVICE_OUT_USB_DEVICE;
+ if (DEBUG) {
+ Slog.d(TAG, "pre-call device:0x" + Integer.toHexString(device)
+ + " addr:" + alsaCardDeviceString
+ + " name:" + mDeviceName);
+ }
+ boolean connected = isOutputJackConnected();
+ Slog.i(TAG, "OUTPUT JACK connected: " + connected);
+ int outputState = (enable && connected) ? 1 : 0;
+ if (outputState != mOutputState) {
+ mOutputState = outputState;
+ mAudioService.setWiredDeviceConnectionState(device, outputState,
+ alsaCardDeviceString,
+ mDeviceName, TAG);
+ }
+ }
+
+ // Input Device
+ if (mHasInput) {
+ int device = mIsInputHeadset ? AudioSystem.DEVICE_IN_USB_HEADSET
+ : AudioSystem.DEVICE_IN_USB_DEVICE;
+ boolean connected = isInputJackConnected();
+ Slog.i(TAG, "INPUT JACK connected: " + connected);
+ int inputState = (enable && connected) ? 1 : 0;
+ if (inputState != mInputState) {
+ mInputState = inputState;
+ mAudioService.setWiredDeviceConnectionState(
+ device, inputState, alsaCardDeviceString,
+ mDeviceName, TAG);
+ }
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "RemoteException in setWiredDeviceConnectionState");
+ }
+ }
+
+
+ /**
* @Override
* @returns a string representation of the object.
*/
- public String toString() {
+ public synchronized String toString() {
return "UsbAlsaDevice: [card: " + mCardNum
+ ", device: " + mDeviceNum
+ ", name: " + mDeviceName
- + ", hasPlayback: " + mHasPlayback
- + ", hasCapture: " + mHasCapture + "]";
+ + ", hasOutput: " + mHasOutput
+ + ", hasInput: " + mHasInput + "]";
}
/**
* Write a description of the device to a dump stream.
*/
- public void dump(@NonNull DualDumpOutputStream dump, String idName, long id) {
+ public synchronized void dump(@NonNull DualDumpOutputStream dump, String idName, long id) {
long token = dump.start(idName, id);
dump.write("card", UsbAlsaDeviceProto.CARD, mCardNum);
dump.write("device", UsbAlsaDeviceProto.DEVICE, mDeviceNum);
dump.write("name", UsbAlsaDeviceProto.NAME, mDeviceName);
- dump.write("has_playback", UsbAlsaDeviceProto.HAS_PLAYBACK, mHasPlayback);
- dump.write("has_capture", UsbAlsaDeviceProto.HAS_CAPTURE, mHasCapture);
+ dump.write("has_output", UsbAlsaDeviceProto.HAS_PLAYBACK, mHasOutput);
+ dump.write("has_input", UsbAlsaDeviceProto.HAS_CAPTURE, mHasInput);
dump.write("address", UsbAlsaDeviceProto.ADDRESS, mDeviceAddress);
dump.end(token);
}
// called by logDevices
- String toShortString() {
+ synchronized String toShortString() {
return "[card:" + mCardNum + " device:" + mDeviceNum + " " + mDeviceName + "]";
}
- String getDeviceName() {
+ synchronized String getDeviceName() {
return mDeviceName;
}
- void setDeviceNameAndDescription(String deviceName, String deviceDescription) {
+ synchronized void setDeviceNameAndDescription(String deviceName, String deviceDescription) {
mDeviceName = deviceName;
mDeviceDescription = deviceDescription;
}
@@ -155,8 +282,8 @@
UsbAlsaDevice other = (UsbAlsaDevice) obj;
return (mCardNum == other.mCardNum
&& mDeviceNum == other.mDeviceNum
- && mHasPlayback == other.mHasPlayback
- && mHasCapture == other.mHasCapture
+ && mHasOutput == other.mHasOutput
+ && mHasInput == other.mHasInput
&& mIsInputHeadset == other.mIsInputHeadset
&& mIsOutputHeadset == other.mIsOutputHeadset);
}
@@ -170,8 +297,8 @@
int result = 1;
result = prime * result + mCardNum;
result = prime * result + mDeviceNum;
- result = prime * result + (mHasPlayback ? 0 : 1);
- result = prime * result + (mHasCapture ? 0 : 1);
+ result = prime * result + (mHasOutput ? 0 : 1);
+ result = prime * result + (mHasInput ? 0 : 1);
result = prime * result + (mIsInputHeadset ? 0 : 1);
result = prime * result + (mIsOutputHeadset ? 0 : 1);
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaJackDetector.java b/services/usb/java/com/android/server/usb/UsbAlsaJackDetector.java
new file mode 100644
index 0000000..c498847
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/UsbAlsaJackDetector.java
@@ -0,0 +1,97 @@
+/*
+ * 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.usb;
+
+/**
+ * Detects and reports ALSA jack state and events.
+ */
+public final class UsbAlsaJackDetector implements Runnable {
+ private static final String TAG = "UsbAlsaJackDetector";
+
+ private static native boolean nativeHasJackDetect(int card);
+ private native boolean nativeJackDetect(int card);
+ private native boolean nativeOutputJackConnected(int card);
+ private native boolean nativeInputJackConnected(int card);
+
+ private boolean mStopJackDetect = false;
+ private UsbAlsaDevice mAlsaDevice;
+
+ /* use startJackDetect to create a UsbAlsaJackDetector */
+ private UsbAlsaJackDetector(UsbAlsaDevice device) {
+ mAlsaDevice = device;
+ }
+
+ /** If jack detection is detected on the given Alsa Device,
+ * create and return a UsbAlsaJackDetector which will update wired device state
+ * each time a jack detection event is registered.
+ *
+ * @returns UsbAlsaJackDetector if jack detect is supported, or null.
+ */
+ public static UsbAlsaJackDetector startJackDetect(UsbAlsaDevice device) {
+ if (!nativeHasJackDetect(device.getCardNum())) {
+ return null;
+ }
+ UsbAlsaJackDetector jackDetector = new UsbAlsaJackDetector(device);
+
+ // This thread will exit once the USB device disappears.
+ // It can also be convinced to stop with pleaseStop().
+ new Thread(jackDetector, "USB jack detect thread").start();
+ return jackDetector;
+ }
+
+ public boolean isInputJackConnected() {
+ return nativeInputJackConnected(mAlsaDevice.getCardNum());
+ }
+
+ public boolean isOutputJackConnected() {
+ return nativeOutputJackConnected(mAlsaDevice.getCardNum());
+ }
+
+ /**
+ * Stop the jack detect thread from calling back into UsbAlsaDevice.
+ * This doesn't force the thread to stop (which is deprecated in java and dangerous due to
+ * locking issues), but will cause the thread to exit at the next safe opportunity.
+ */
+ public void pleaseStop() {
+ synchronized (this) {
+ mStopJackDetect = true;
+ }
+ }
+
+ /**
+ * Called by nativeJackDetect each time a jack detect event is reported.
+ * @return false when the jackDetect thread should stop. true otherwise.
+ */
+ public boolean jackDetectCallback() {
+ synchronized (this) {
+ if (mStopJackDetect) {
+ return false;
+ }
+ mAlsaDevice.updateWiredDeviceConnectionState(true);
+ }
+ return true;
+ }
+
+ /**
+ * This will call jackDetectCallback each time it detects a jack detect event.
+ * If jackDetectCallback returns false, this function will return.
+ */
+ public void run() {
+ nativeJackDetect(mAlsaDevice.getCardNum());
+ }
+}
+
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index 0c5f8f1..2f1c516 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -20,11 +20,9 @@
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.hardware.usb.UsbDevice;
-import android.media.AudioSystem;
import android.media.IAudioService;
import android.media.midi.MidiDeviceInfo;
import android.os.Bundle;
-import android.os.RemoteException;
import android.os.ServiceManager;
import android.provider.Settings;
import android.service.usb.UsbAlsaManagerProto;
@@ -32,7 +30,6 @@
import com.android.internal.alsa.AlsaCardsParser;
import com.android.internal.util.dump.DualDumpOutputStream;
-import com.android.server.audio.AudioService;
import com.android.server.usb.descriptors.UsbDescriptorParser;
import libcore.io.IoUtils;
@@ -58,6 +55,7 @@
// this is needed to map USB devices to ALSA Audio Devices, especially to remove an
// ALSA device when we are notified that its associated USB device has been removed.
private final ArrayList<UsbAlsaDevice> mAlsaDevices = new ArrayList<UsbAlsaDevice>();
+ private UsbAlsaDevice mSelectedDevice;
/**
* List of connected MIDI devices
@@ -78,17 +76,19 @@
ServiceManager.getService(Context.AUDIO_SERVICE));
}
- // Notifies AudioService when a device is added or removed
- // audioDevice - the AudioDevice that was added or removed
- // enabled - if true, we're connecting a device (it's arrived), else disconnecting
- private void notifyDeviceState(UsbAlsaDevice alsaDevice, boolean enabled) {
+ /**
+ * Select the AlsaDevice to be used for AudioService.
+ * AlsaDevice.start() notifies AudioService of it's connected state.
+ *
+ * @param alsaDevice The selected UsbAlsaDevice for system USB audio.
+ */
+ private synchronized void selectAlsaDevice(UsbAlsaDevice alsaDevice) {
if (DEBUG) {
- Slog.d(TAG, "notifyDeviceState " + enabled + " " + alsaDevice);
+ Slog.d(TAG, "selectAlsaDevice " + alsaDevice);
}
- if (mAudioService == null) {
- Slog.e(TAG, "no AudioService");
- return;
+ if (mSelectedDevice != null) {
+ deselectAlsaDevice();
}
// FIXME Does not yet handle the case where the setting is changed
@@ -102,40 +102,14 @@
return;
}
- int state = (enabled ? 1 : 0);
- int cardNum = alsaDevice.getCardNum();
- int deviceNum = alsaDevice.getDeviceNum();
- if (cardNum < 0 || deviceNum < 0) {
- Slog.e(TAG, "Invalid alsa card or device alsaCard: " + cardNum
- + " alsaDevice: " + deviceNum);
- return;
- }
+ mSelectedDevice = alsaDevice;
+ alsaDevice.start();
+ }
- String address = AudioService.makeAlsaAddressString(cardNum, deviceNum);
- try {
- // Playback Device
- if (alsaDevice.hasPlayback()) {
- int device = alsaDevice.isOutputHeadset()
- ? AudioSystem.DEVICE_OUT_USB_HEADSET
- : AudioSystem.DEVICE_OUT_USB_DEVICE;
- if (DEBUG) {
- Slog.i(TAG, "pre-call device:0x" + Integer.toHexString(device) +
- " addr:" + address + " name:" + alsaDevice.getDeviceName());
- }
- mAudioService.setWiredDeviceConnectionState(
- device, state, address, alsaDevice.getDeviceName(), TAG);
- }
-
- // Capture Device
- if (alsaDevice.hasCapture()) {
- int device = alsaDevice.isInputHeadset()
- ? AudioSystem.DEVICE_IN_USB_HEADSET
- : AudioSystem.DEVICE_IN_USB_DEVICE;
- mAudioService.setWiredDeviceConnectionState(
- device, state, address, alsaDevice.getDeviceName(), TAG);
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "RemoteException in setWiredDeviceConnectionState");
+ private synchronized void deselectAlsaDevice() {
+ if (mSelectedDevice != null) {
+ mSelectedDevice.stop();
+ mSelectedDevice = null;
}
}
@@ -168,7 +142,7 @@
Slog.d(TAG, " alsaDevice:" + alsaDevice);
}
if (alsaDevice != null) {
- notifyDeviceState(alsaDevice, true /*enabled*/);
+ selectAlsaDevice(alsaDevice);
}
return alsaDevice;
} else {
@@ -202,16 +176,21 @@
if (hasInput || hasOutput) {
boolean isInputHeadset = parser.isInputHeadset();
boolean isOutputHeadset = parser.isOutputHeadset();
- UsbAlsaDevice alsaDevice =
- new UsbAlsaDevice(cardRec.getCardNum(), 0 /*device*/, deviceAddress,
- hasOutput, hasInput, isInputHeadset, isOutputHeadset);
- alsaDevice.setDeviceNameAndDescription(
- cardRec.getCardName(), cardRec.getCardDescription());
- mAlsaDevices.add(0, alsaDevice);
- // Select it
+ if (mAudioService == null) {
+ Slog.e(TAG, "no AudioService");
+ return;
+ }
+
+ UsbAlsaDevice alsaDevice =
+ new UsbAlsaDevice(mAudioService, cardRec.getCardNum(), 0 /*device*/,
+ deviceAddress, hasOutput, hasInput,
+ isInputHeadset, isOutputHeadset);
if (alsaDevice != null) {
- notifyDeviceState(alsaDevice, true /*enabled*/);
+ alsaDevice.setDeviceNameAndDescription(
+ cardRec.getCardName(), cardRec.getCardDescription());
+ mAlsaDevices.add(0, alsaDevice);
+ selectAlsaDevice(alsaDevice);
}
}
@@ -256,7 +235,7 @@
}
}
- /* package */ void usbDeviceRemoved(String deviceAddress/*UsbDevice usbDevice*/) {
+ /* package */ synchronized void usbDeviceRemoved(String deviceAddress/*UsbDevice usbDevice*/) {
if (DEBUG) {
Slog.d(TAG, "deviceRemoved(" + deviceAddress + ")");
}
@@ -264,13 +243,9 @@
// Audio
UsbAlsaDevice alsaDevice = removeAlsaDeviceFromList(deviceAddress);
Slog.i(TAG, "USB Audio Device Removed: " + alsaDevice);
- if (alsaDevice != null) {
- if (alsaDevice.hasPlayback() || alsaDevice.hasCapture()) {
- notifyDeviceState(alsaDevice, false /*enabled*/);
-
- // if there any external devices left, select one of them
- selectDefaultDevice();
- }
+ if (alsaDevice != null && alsaDevice == mSelectedDevice) {
+ deselectAlsaDevice();
+ selectDefaultDevice(); // if there any external devices left, select one of them
}
// MIDI
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 6806947..a7fc470 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -1786,7 +1786,7 @@
mGadgetProxy = IUsbGadget.getService();
mGadgetProxy.linkToDeath(new UsbGadgetDeathRecipient(),
USB_GADGET_HAL_DEATH_COOKIE);
- if (!mCurrentFunctionsApplied) {
+ if (!mCurrentFunctionsApplied && !mCurrentUsbFunctionsRequested) {
setEnabledFunctions(mCurrentFunctions, false);
}
} catch (NoSuchElementException e) {
diff --git a/telecomm/OWNERS b/telecomm/OWNERS
new file mode 100644
index 0000000..a3bcfb2
--- /dev/null
+++ b/telecomm/OWNERS
@@ -0,0 +1,6 @@
+set noparent
+
+tgunn@google.com
+breadley@google.com
+hallliu@google.com
+rgreenwalt@google.com
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java
index 5fcff18..024bd30 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -29,7 +29,6 @@
import java.util.Collections;
import java.util.List;
import java.util.Locale;
-import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
@@ -82,7 +81,7 @@
private int mConnectionProperties;
private String mDisconnectMessage;
private long mConnectTimeMillis = CONNECT_TIME_NOT_SPECIFIED;
- private long mConnectElapsedTimeMillis = CONNECT_TIME_NOT_SPECIFIED;
+ private long mConnectionStartElapsedRealTime = CONNECT_TIME_NOT_SPECIFIED;
private StatusHints mStatusHints;
private Bundle mExtras;
private Set<String> mPreviousExtraKeys;
@@ -584,30 +583,36 @@
}
/**
- * Sets the connection start time of the {@code Conference}. Should be specified in wall-clock
- * time returned by {@link System#currentTimeMillis()}.
+ * Sets the connection start time of the {@code Conference}. This is used in the call log to
+ * indicate the date and time when the conference took place.
+ * <p>
+ * Should be specified in wall-clock time returned by {@link System#currentTimeMillis()}.
* <p>
* When setting the connection time, you should always set the connection elapsed time via
- * {@link #setConnectionElapsedTime(long)}.
+ * {@link #setConnectionStartElapsedRealTime(long)} to ensure the duration is reflected.
*
- * @param connectionTimeMillis The connection time, in milliseconds.
+ * @param connectionTimeMillis The connection time, in milliseconds, as returned by
+ * {@link System#currentTimeMillis()}.
*/
public final void setConnectionTime(long connectionTimeMillis) {
mConnectTimeMillis = connectionTimeMillis;
}
/**
- * Sets the elapsed time since system boot when the {@link Conference} was connected.
- * This is used to determine the duration of the {@link Conference}.
+ * Sets the start time of the {@link Conference} which is the basis for the determining the
+ * duration of the {@link Conference}.
* <p>
- * When setting the connection elapsed time, you should always set the connection time via
+ * You should use a value returned by {@link SystemClock#elapsedRealtime()} to ensure that time
+ * zone changes do not impact the conference duration.
+ * <p>
+ * When setting this, you should also set the connection time via
* {@link #setConnectionTime(long)}.
*
- * @param connectionElapsedTime The connection time, as measured by
+ * @param connectionStartElapsedRealTime The connection time, as measured by
* {@link SystemClock#elapsedRealtime()}.
*/
- public final void setConnectionElapsedTime(long connectionElapsedTime) {
- mConnectElapsedTimeMillis = connectionElapsedTime;
+ public final void setConnectionStartElapsedRealTime(long connectionStartElapsedRealTime) {
+ mConnectionStartElapsedRealTime = connectionStartElapsedRealTime;
}
/**
@@ -642,8 +647,8 @@
* @return The elapsed time at which the {@link Conference} was connected.
* @hide
*/
- public final long getConnectElapsedTime() {
- return mConnectElapsedTimeMillis;
+ public final long getConnectionStartElapsedRealTime() {
+ return mConnectionStartElapsedRealTime;
}
/**
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 24184e0..3229705 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -2299,7 +2299,7 @@
*
* @hide
*/
- public final void setConnectElapsedTimeMillis(long connectElapsedTimeMillis) {
+ public final void setConnectionStartElapsedRealTime(long connectElapsedTimeMillis) {
mConnectElapsedTimeMillis = connectElapsedTimeMillis;
}
@@ -2743,7 +2743,20 @@
/**
* Notifies this Connection, which is in {@link #STATE_RINGING}, of
* a request to accept.
- *
+ * <p>
+ * For managed {@link ConnectionService}s, this will be called when the user answers a call via
+ * the default dialer's {@link InCallService}.
+ * <p>
+ * Although a self-managed {@link ConnectionService} provides its own incoming call UI, the
+ * Telecom framework may request that the call is answered in the following circumstances:
+ * <ul>
+ * <li>The user chooses to answer an incoming call via a Bluetooth device.</li>
+ * <li>A car mode {@link InCallService} is in use which has declared
+ * {@link TelecomManager#METADATA_INCLUDE_SELF_MANAGED_CALLS} in its manifest. Such an
+ * {@link InCallService} will be able to see calls from self-managed
+ * {@link ConnectionService}s, and will be able to display an incoming call UI on their
+ * behalf.</li>
+ * </ul>
* @param videoState The video state in which to answer the connection.
*/
public void onAnswer(int videoState) {}
@@ -2751,6 +2764,20 @@
/**
* Notifies this Connection, which is in {@link #STATE_RINGING}, of
* a request to accept.
+ * <p>
+ * For managed {@link ConnectionService}s, this will be called when the user answers a call via
+ * the default dialer's {@link InCallService}.
+ * <p>
+ * Although a self-managed {@link ConnectionService} provides its own incoming call UI, the
+ * Telecom framework may request that the call is answered in the following circumstances:
+ * <ul>
+ * <li>The user chooses to answer an incoming call via a Bluetooth device.</li>
+ * <li>A car mode {@link InCallService} is in use which has declared
+ * {@link TelecomManager#METADATA_INCLUDE_SELF_MANAGED_CALLS} in its manifest. Such an
+ * {@link InCallService} will be able to see calls from self-managed
+ * {@link ConnectionService}s, and will be able to display an incoming call UI on their
+ * behalf.</li>
+ * </ul>
*/
public void onAnswer() {
onAnswer(VideoProfile.STATE_AUDIO_ONLY);
@@ -2765,6 +2792,20 @@
/**
* Notifies this Connection, which is in {@link #STATE_RINGING}, of
* a request to reject.
+ * <p>
+ * For managed {@link ConnectionService}s, this will be called when the user rejects a call via
+ * the default dialer's {@link InCallService}.
+ * <p>
+ * Although a self-managed {@link ConnectionService} provides its own incoming call UI, the
+ * Telecom framework may request that the call is rejected in the following circumstances:
+ * <ul>
+ * <li>The user chooses to reject an incoming call via a Bluetooth device.</li>
+ * <li>A car mode {@link InCallService} is in use which has declared
+ * {@link TelecomManager#METADATA_INCLUDE_SELF_MANAGED_CALLS} in its manifest. Such an
+ * {@link InCallService} will be able to see calls from self-managed
+ * {@link ConnectionService}s, and will be able to display an incoming call UI on their
+ * behalf.</li>
+ * </ul>
*/
public void onReject() {}
@@ -2847,9 +2888,10 @@
* should show its own incoming call user interface.
* <p>
* Where there are ongoing calls in other self-managed {@link ConnectionService}s, or in a
- * regular {@link ConnectionService}, the Telecom framework will display its own incoming call
- * user interface to allow the user to choose whether to answer the new incoming call and
- * disconnect other ongoing calls, or to reject the new incoming call.
+ * regular {@link ConnectionService}, and it is not possible to hold these other calls, the
+ * Telecom framework will display its own incoming call user interface to allow the user to
+ * choose whether to answer the new incoming call and disconnect other ongoing calls, or to
+ * reject the new incoming call.
* <p>
* You should trigger the display of the incoming call user interface for your application by
* showing a {@link Notification} with a full-screen {@link Intent} specified.
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 211699e..1547857 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -21,7 +21,6 @@
import android.content.ComponentName;
import android.content.Intent;
import android.net.Uri;
-import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -2007,7 +2006,7 @@
null : conference.getVideoProvider().getInterface(),
conference.getVideoState(),
conference.getConnectTimeMillis(),
- conference.getConnectElapsedTime(),
+ conference.getConnectionStartElapsedRealTime(),
conference.getStatusHints(),
conference.getExtras());
diff --git a/telephony/OWNERS b/telephony/OWNERS
new file mode 100644
index 0000000..6f67bc2
--- /dev/null
+++ b/telephony/OWNERS
@@ -0,0 +1,14 @@
+set noparent
+
+tgunn@google.com
+breadley@google.com
+hallliu@google.com
+rgreenwalt@google.com
+mpq@google.com
+amitmahajan@google.com
+fionaxu@google.com
+jackyu@google.com
+jminjie@google.com
+satk@google.com
+shuoq@google.com
+refuhoo@google.com
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index 38408fe..77413d9c 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -17,6 +17,7 @@
package android.telephony;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -34,6 +35,8 @@
import android.util.DisplayMetrics;
import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.List;
/**
* A Parcelable class for Subscription Information.
@@ -332,12 +335,7 @@
return this.mCountryIso;
}
- /**
- * @return whether the subscription is an embedded one.
- * @hide
- *
- * TODO(b/35851809): Make this public.
- */
+ /** @return whether the subscription is an embedded one. */
public boolean isEmbedded() {
return this.mIsEmbedded;
}
@@ -351,9 +349,9 @@
* @return whether the app is authorized to manage this subscription per its metadata.
* @throws UnsupportedOperationException if this subscription is not embedded.
* @hide
- *
- * TODO(b/35851809): Make this public.
+ * @deprecated - Do not use.
*/
+ @Deprecated
public boolean canManageSubscription(Context context) {
return canManageSubscription(context, context.getPackageName());
}
@@ -367,7 +365,9 @@
* @return whether the app is authorized to manage this subscription per its metadata.
* @throws UnsupportedOperationException if this subscription is not embedded.
* @hide
+ * @deprecated - Do not use.
*/
+ @Deprecated
public boolean canManageSubscription(Context context, String packageName) {
if (!isEmbedded()) {
throw new UnsupportedOperationException("Not an embedded subscription");
@@ -395,14 +395,14 @@
* @return the {@link UiccAccessRule}s dictating who is authorized to manage this subscription.
* @throws UnsupportedOperationException if this subscription is not embedded.
* @hide
- *
- * TODO(b/35851809): Make this a SystemApi.
*/
- public @Nullable UiccAccessRule[] getAccessRules() {
+ @SystemApi
+ public @Nullable List<UiccAccessRule> getAccessRules() {
if (!isEmbedded()) {
throw new UnsupportedOperationException("Not an embedded subscription");
}
- return mAccessRules;
+ if (mAccessRules == null) return null;
+ return Arrays.asList(mAccessRules);
}
/**
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index debf43d..11a1984 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -30,6 +30,7 @@
import android.app.BroadcastOptions;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -822,10 +823,13 @@
* if the list is non-empty the list is sorted by {@link SubscriptionInfo#getSimSlotIndex}
* then by {@link SubscriptionInfo#getSubscriptionId}.
* </ul>
- * @hide
*
- * TODO(b/35851809): Make this a SystemApi.
+ * <p>
+ * Permissions android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE is required
+ * for #getAvailableSubscriptionInfoList to be invoked.
+ * @hide
*/
+ @SystemApi
public List<SubscriptionInfo> getAvailableSubscriptionInfoList() {
List<SubscriptionInfo> result = null;
@@ -863,9 +867,6 @@
* if the list is non-empty the list is sorted by {@link SubscriptionInfo#getSimSlotIndex}
* then by {@link SubscriptionInfo#getSubscriptionId}.
* </ul>
- * @hide
- *
- * TODO(b/35851809): Make this public.
*/
public List<SubscriptionInfo> getAccessibleSubscriptionInfoList() {
List<SubscriptionInfo> result = null;
@@ -891,9 +892,8 @@
*
* <p>Requires the {@link android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission.
* @hide
- *
- * TODO(b/35851809): Make this a SystemApi.
*/
+ @SystemApi
public void requestEmbeddedSubscriptionInfoListRefresh() {
try {
ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
@@ -1892,4 +1892,51 @@
options.setTemporaryAppWhitelistDuration(TimeUnit.MINUTES.toMillis(1));
mContext.sendBroadcast(intent, null, options.toBundle());
}
+
+ /**
+ * Checks whether the app with the given context is authorized to manage the given subscription
+ * according to its metadata. Only supported for embedded subscriptions (if
+ * {@code SubscriptionInfo#isEmbedded} returns true).
+ *
+ * @param info The subscription to check.
+ * @return whether the app is authorized to manage this subscription per its metadata.
+ * @throws UnsupportedOperationException if this subscription is not embedded.
+ */
+ public boolean canManageSubscription(SubscriptionInfo info) {
+ return canManageSubscription(info, mContext.getPackageName());
+ }
+
+ /**
+ * Checks whether the given app is authorized to manage the given subscription according to its
+ * metadata. Only supported for embedded subscriptions (if {@code SubscriptionInfo#isEmbedded}
+ * returns true).
+ *
+ * @param info The subscription to check.
+ * @param packageName Package name of the app to check.
+ * @return whether the app is authorized to manage this subscription per its metadata.
+ * @throws UnsupportedOperationException if this subscription is not embedded.
+ * @hide
+ */
+ public boolean canManageSubscription(SubscriptionInfo info, String packageName) {
+ if (!info.isEmbedded()) {
+ throw new UnsupportedOperationException("Not an embedded subscription");
+ }
+ if (info.getAccessRules() == null) {
+ return false;
+ }
+ PackageManager packageManager = mContext.getPackageManager();
+ PackageInfo packageInfo;
+ try {
+ packageInfo = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new IllegalArgumentException("Unknown package: " + packageName, e);
+ }
+ for (UiccAccessRule rule : info.getAccessRules()) {
+ if (rule.getCarrierPrivilegeStatus(packageInfo)
+ == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
+ return true;
+ }
+ }
+ return false;
+ }
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 03d8b5c..fefc03d 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -53,6 +53,7 @@
import android.telephony.ims.aidl.IImsRcsFeature;
import android.telephony.ims.aidl.IImsRegistration;
import android.telephony.ims.feature.ImsFeature;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
import android.util.Log;
import com.android.ims.internal.IImsServiceFeatureCallback;
@@ -4801,7 +4802,7 @@
}
/**
- * Sets the telephony property with the value specified.
+ * Sets a per-phone telephony property with the value specified.
*
* @hide
*/
@@ -4851,6 +4852,20 @@
}
/**
+ * Sets a global telephony property with the value specified.
+ *
+ * @hide
+ */
+ public static void setTelephonyProperty(String property, String value) {
+ if (value == null) {
+ value = "";
+ }
+ Rlog.d(TAG, "setTelephonyProperty: success" + " property=" +
+ property + " value: " + value);
+ SystemProperties.set(property, value);
+ }
+
+ /**
* Convenience function for retrieving a value from the secure settings
* value list as an integer. Note that internally setting values are
* always stored as strings; this function converts the string to an
@@ -4939,7 +4954,7 @@
}
/**
- * Gets the telephony property.
+ * Gets a per-phone telephony property.
*
* @hide
*/
@@ -4955,6 +4970,19 @@
return propVal == null ? defaultVal : propVal;
}
+ /**
+ * Gets a global telephony property.
+ *
+ * See also getTelephonyProperty(phoneId, property, defaultVal). Most telephony properties are
+ * per-phone.
+ *
+ * @hide
+ */
+ public static String getTelephonyProperty(String property, String defaultVal) {
+ String propVal = SystemProperties.get(property);
+ return propVal == null ? defaultVal : propVal;
+ }
+
/** @hide */
public int getSimCount() {
// FIXME Need to get it from Telephony Dev Controller when that gets implemented!
@@ -6383,84 +6411,106 @@
return false;
}
- /**
- * Returns the IMS Registration Status
- * @hide
- */
- public boolean isImsRegistered() {
- try {
- ITelephony telephony = getITelephony();
- if (telephony == null)
- return false;
- return telephony.isImsRegistered();
- } catch (RemoteException ex) {
- return false;
- } catch (NullPointerException ex) {
- return false;
- }
- }
-
/**
- * Returns the IMS Registration Status for a particular Subscription ID
+ * Returns the IMS Registration Status for a particular Subscription ID.
*
* @param subId Subscription ID
* @return true if IMS status is registered, false if the IMS status is not registered or a
* RemoteException occurred.
- *
* @hide
*/
public boolean isImsRegistered(int subId) {
- try {
- return getITelephony().isImsRegisteredForSubscriber(subId);
- } catch (RemoteException ex) {
- return false;
- } catch (NullPointerException ex) {
- return false;
- }
- }
-
- /**
- * Returns the Status of Volte
- * @hide
- */
- public boolean isVolteAvailable() {
- try {
- return getITelephony().isVolteAvailable();
- } catch (RemoteException ex) {
- return false;
- } catch (NullPointerException ex) {
- return false;
- }
- }
-
- /**
- * Returns the Status of video telephony (VT)
- * @hide
- */
- public boolean isVideoTelephonyAvailable() {
try {
- return getITelephony().isVideoTelephonyAvailable();
- } catch (RemoteException ex) {
- return false;
- } catch (NullPointerException ex) {
+ return getITelephony().isImsRegistered(subId);
+ } catch (RemoteException | NullPointerException ex) {
return false;
}
}
/**
- * Returns the Status of Wi-Fi Calling
+ * Returns the IMS Registration Status for a particular Subscription ID, which is determined
+ * when the TelephonyManager is created using {@link #createForSubscriptionId(int)}. If an
+ * invalid subscription ID is used during creation, will the default subscription ID will be
+ * used.
+ *
+ * @return true if IMS status is registered, false if the IMS status is not registered or a
+ * RemoteException occurred.
+ * @see SubscriptionManager#getDefaultSubscriptionId()
+ * @hide
+ */
+ public boolean isImsRegistered() {
+ try {
+ return getITelephony().isImsRegistered(getSubId());
+ } catch (RemoteException | NullPointerException ex) {
+ return false;
+ }
+ }
+
+ /**
+ * The current status of Voice over LTE for the subscription associated with this instance when
+ * it was created using {@link #createForSubscriptionId(int)}. If an invalid subscription ID was
+ * used during creation, the default subscription ID will be used.
+ * @return true if Voice over LTE is available or false if it is unavailable or unknown.
+ * @see SubscriptionManager#getDefaultSubscriptionId()
+ * @hide
+ */
+ public boolean isVolteAvailable() {
+ try {
+ return getITelephony().isVolteAvailable(getSubId());
+ } catch (RemoteException | NullPointerException ex) {
+ return false;
+ }
+ }
+
+ /**
+ * The availability of Video Telephony (VT) for the subscription ID specified when this instance
+ * was created using {@link #createForSubscriptionId(int)}. If an invalid subscription ID was
+ * used during creation, the default subscription ID will be used. To query the
+ * underlying technology that VT is available on, use {@link #getImsRegTechnologyForMmTel}.
+ * @return true if VT is available, or false if it is unavailable or unknown.
+ * @hide
+ */
+ public boolean isVideoTelephonyAvailable() {
+ try {
+ return getITelephony().isVideoTelephonyAvailable(getSubId());
+ } catch (RemoteException | NullPointerException ex) {
+ return false;
+ }
+ }
+
+ /**
+ * Returns the Status of Wi-Fi calling (Voice over WiFi) for the subscription ID specified.
+ * @param subId the subscription ID.
+ * @return true if VoWiFi is available, or false if it is unavailable or unknown.
* @hide
*/
public boolean isWifiCallingAvailable() {
try {
- return getITelephony().isWifiCallingAvailable();
- } catch (RemoteException ex) {
- return false;
- } catch (NullPointerException ex) {
+ return getITelephony().isWifiCallingAvailable(getSubId());
+ } catch (RemoteException | NullPointerException ex) {
return false;
}
}
+ /**
+ * The technology that IMS is registered for for the MMTEL feature.
+ * @param subId subscription ID to get IMS registration technology for.
+ * @return The IMS registration technology that IMS is registered to for the MMTEL feature.
+ * Valid return results are:
+ * - {@link ImsRegistrationImplBase#REGISTRATION_TECH_LTE} for LTE registration,
+ * - {@link ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN} for IWLAN registration, or
+ * - {@link ImsRegistrationImplBase#REGISTRATION_TECH_NONE} if we are not registered or the
+ * result is unavailable.
+ * @hide
+ */
+ public @ImsRegistrationImplBase.ImsRegistrationTech int getImsRegTechnologyForMmTel() {
+ try {
+ return getITelephony().getImsRegTechnologyForMmTel(getSubId());
+ } catch (RemoteException ex) {
+ return ImsRegistrationImplBase.REGISTRATION_TECH_NONE;
+ }
+ }
+
/**
* Set TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC for the default phone.
*
diff --git a/telephony/java/android/telephony/UiccAccessRule.java b/telephony/java/android/telephony/UiccAccessRule.java
index 3937201..c3f8a19 100644
--- a/telephony/java/android/telephony/UiccAccessRule.java
+++ b/telephony/java/android/telephony/UiccAccessRule.java
@@ -16,6 +16,7 @@
package android.telephony;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.content.pm.PackageInfo;
import android.content.pm.Signature;
import android.os.Parcel;
@@ -39,9 +40,8 @@
* specification.
*
* @hide
- *
- * TODO(b/35851809): Make this a SystemApi.
*/
+@SystemApi
public final class UiccAccessRule implements Parcelable {
private static final String TAG = "UiccAccessRule";
diff --git a/telephony/java/android/telephony/euicc/DownloadableSubscription.java b/telephony/java/android/telephony/euicc/DownloadableSubscription.java
index 01041c8..88db22b 100644
--- a/telephony/java/android/telephony/euicc/DownloadableSubscription.java
+++ b/telephony/java/android/telephony/euicc/DownloadableSubscription.java
@@ -16,18 +16,17 @@
package android.telephony.euicc;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.telephony.UiccAccessRule;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
import com.android.internal.util.Preconditions;
-/**
- * Information about a subscription which is available for download.
- *
- * TODO(b/35851809): Make this public.
- * @hide
- */
+/** Information about a subscription which is available for download. */
public final class DownloadableSubscription implements Parcelable {
public static final Creator<DownloadableSubscription> CREATOR =
@@ -46,11 +45,12 @@
/**
* Activation code. May be null for subscriptions which are not based on activation codes, e.g.
* to download a default subscription assigned to this device.
+ * Should use getEncodedActivationCode() instead.
* @hide
- *
- * TODO(b/35851809): Make this a SystemApi.
+ * @deprecated - Do not use. This will be private. Use getEncodedActivationCode() instead.
*/
@Nullable
+ @Deprecated
public final String encodedActivationCode;
@Nullable private String confirmationCode;
@@ -58,8 +58,16 @@
// see getCarrierName and setCarrierName
@Nullable
private String carrierName;
+
// see getAccessRules and setAccessRules
- private UiccAccessRule[] accessRules;
+ @Nullable
+ private List<UiccAccessRule> accessRules;
+
+ /** Gets the activation code. */
+ @Nullable
+ public String getEncodedActivationCode() {
+ return encodedActivationCode;
+ }
/** @hide */
private DownloadableSubscription(String encodedActivationCode) {
@@ -70,7 +78,59 @@
encodedActivationCode = in.readString();
confirmationCode = in.readString();
carrierName = in.readString();
- accessRules = in.createTypedArray(UiccAccessRule.CREATOR);
+ accessRules = new ArrayList<UiccAccessRule>();
+ in.readTypedList(accessRules, UiccAccessRule.CREATOR);
+ }
+
+ private DownloadableSubscription(String encodedActivationCode, String confirmationCode,
+ String carrierName, List<UiccAccessRule> accessRules) {
+ this.encodedActivationCode = encodedActivationCode;
+ this.confirmationCode = confirmationCode;
+ this.carrierName = carrierName;
+ this.accessRules = accessRules;
+ }
+
+ /** @hide */
+ @SystemApi
+ public static final class Builder {
+ @Nullable private String encodedActivationCode;
+ @Nullable private String confirmationCode;
+ @Nullable private String carrierName;
+ List<UiccAccessRule> accessRules;
+
+ public Builder() {}
+
+ public Builder(DownloadableSubscription baseSubscription) {
+ encodedActivationCode = baseSubscription.getEncodedActivationCode();
+ confirmationCode = baseSubscription.getConfirmationCode();
+ carrierName = baseSubscription.getCarrierName();
+ accessRules = baseSubscription.getAccessRules();
+ }
+
+ public DownloadableSubscription build() {
+ return new DownloadableSubscription(encodedActivationCode, confirmationCode,
+ carrierName, accessRules);
+ }
+
+ public Builder setEncodedActivationCode(String value) {
+ encodedActivationCode = value;
+ return this;
+ }
+
+ public Builder setConfirmationCode(String value) {
+ confirmationCode = value;
+ return this;
+ }
+
+ public Builder setCarrierName(String value) {
+ carrierName = value;
+ return this;
+ }
+
+ public Builder setAccessRules(List<UiccAccessRule> value) {
+ accessRules = value;
+ return this;
+ }
}
/**
@@ -87,7 +147,10 @@
/**
* Sets the confirmation code.
+ * @hide
+ * @deprecated - Do not use.
*/
+ @Deprecated
public void setConfirmationCode(String confirmationCode) {
this.confirmationCode = confirmationCode;
}
@@ -103,9 +166,9 @@
/**
* Set the user-visible carrier name.
* @hide
- *
- * TODO(b/35851809): Make this a SystemApi.
+ * @deprecated - Do not use.
*/
+ @Deprecated
public void setCarrierName(String carrierName) {
this.carrierName = carrierName;
}
@@ -117,44 +180,51 @@
* those created with {@link #forActivationCode}). May be populated with
* {@link EuiccManager#getDownloadableSubscriptionMetadata}.
* @hide
- *
- * TODO(b/35851809): Make this a SystemApi.
*/
+ @SystemApi
@Nullable
public String getCarrierName() {
return carrierName;
}
/**
- * Returns the {@link UiccAccessRule}s dictating access to this subscription.
+ * Returns the {@link UiccAccessRule}s in list dictating access to this subscription.
*
* <p>Only present for downloadable subscriptions that were queried from a server (as opposed to
* those created with {@link #forActivationCode}). May be populated with
* {@link EuiccManager#getDownloadableSubscriptionMetadata}.
* @hide
- *
- * TODO(b/35851809): Make this a SystemApi.
*/
- public UiccAccessRule[] getAccessRules() {
+ @SystemApi
+ public List<UiccAccessRule> getAccessRules() {
return accessRules;
}
/**
* Set the {@link UiccAccessRule}s dictating access to this subscription.
* @hide
- *
- * TODO(b/35851809): Make this a SystemApi.
+ * @deprecated - Do not use.
*/
- public void setAccessRules(UiccAccessRule[] accessRules) {
+ @Deprecated
+ public void setAccessRules(List<UiccAccessRule> accessRules) {
this.accessRules = accessRules;
}
+ /**
+ * @hide
+ * @deprecated - Do not use.
+ */
+ @Deprecated
+ public void setAccessRules(UiccAccessRule[] accessRules) {
+ this.accessRules = Arrays.asList(accessRules);
+ }
+
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(encodedActivationCode);
dest.writeString(confirmationCode);
dest.writeString(carrierName);
- dest.writeTypedArray(accessRules, flags);
+ dest.writeTypedList(accessRules);
}
@Override
diff --git a/telephony/java/android/telephony/euicc/EuiccCardManager.java b/telephony/java/android/telephony/euicc/EuiccCardManager.java
index a1a6a5a..c3f4007 100644
--- a/telephony/java/android/telephony/euicc/EuiccCardManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccCardManager.java
@@ -17,6 +17,7 @@
import android.annotation.IntDef;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.content.Context;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -49,14 +50,14 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import android.annotation.CallbackExecutor;
+import java.util.concurrent.Executor;
/**
* EuiccCardManager is the application interface to an eSIM card.
- *
* @hide
- *
- * TODO(b/35851809): Make this a SystemApi.
*/
+@SystemApi
public class EuiccCardManager {
private static final String TAG = "EuiccCardManager";
@@ -68,6 +69,7 @@
CANCEL_REASON_TIMEOUT,
CANCEL_REASON_PPR_NOT_ALLOWED
})
+ /** @hide */
public @interface CancelReason {}
/**
@@ -96,6 +98,7 @@
RESET_OPTION_DELETE_FIELD_LOADED_TEST_PROFILES,
RESET_OPTION_RESET_DEFAULT_SMDP_ADDRESS
})
+ /** @hide */
public @interface ResetOption {}
/** Deletes all operational profiles. */
@@ -143,18 +146,20 @@
}
/**
- * Gets all the profiles on eUicc.
+ * Requests all the profiles on eUicc.
*
* @param cardId The Id of the eUICC.
+ * @param executor The executor through which the callback should be invode.
* @param callback The callback to get the result code and all the profiles.
*/
- public void getAllProfiles(String cardId, ResultCallback<EuiccProfileInfo[]> callback) {
+ public void requestAllProfiles(String cardId, @CallbackExecutor Executor executor,
+ ResultCallback<EuiccProfileInfo[]> callback) {
try {
getIEuiccCardController().getAllProfiles(mContext.getOpPackageName(), cardId,
new IGetAllProfilesCallback.Stub() {
@Override
public void onComplete(int resultCode, EuiccProfileInfo[] profiles) {
- callback.onComplete(resultCode, profiles);
+ executor.execute(() -> callback.onComplete(resultCode, profiles));
}
});
} catch (RemoteException e) {
@@ -164,19 +169,21 @@
}
/**
- * Gets the profile of the given iccid.
+ * Requests the profile of the given iccid.
*
* @param cardId The Id of the eUICC.
* @param iccid The iccid of the profile.
+ * @param executor The executor through which the callback should be invode.
* @param callback The callback to get the result code and profile.
*/
- public void getProfile(String cardId, String iccid, ResultCallback<EuiccProfileInfo> callback) {
+ public void requestProfile(String cardId, String iccid, @CallbackExecutor Executor executor,
+ ResultCallback<EuiccProfileInfo> callback) {
try {
getIEuiccCardController().getProfile(mContext.getOpPackageName(), cardId, iccid,
new IGetProfileCallback.Stub() {
@Override
public void onComplete(int resultCode, EuiccProfileInfo profile) {
- callback.onComplete(resultCode, profile);
+ executor.execute(() -> callback.onComplete(resultCode, profile));
}
});
} catch (RemoteException e) {
@@ -191,16 +198,17 @@
* @param cardId The Id of the eUICC.
* @param iccid The iccid of the profile.
* @param refresh Whether sending the REFRESH command to modem.
+ * @param executor The executor through which the callback should be invode.
* @param callback The callback to get the result code.
*/
public void disableProfile(String cardId, String iccid, boolean refresh,
- ResultCallback<Void> callback) {
+ @CallbackExecutor Executor executor, ResultCallback<Void> callback) {
try {
getIEuiccCardController().disableProfile(mContext.getOpPackageName(), cardId, iccid,
refresh, new IDisableProfileCallback.Stub() {
@Override
public void onComplete(int resultCode) {
- callback.onComplete(resultCode, null);
+ executor.execute(() -> callback.onComplete(resultCode, null));
}
});
} catch (RemoteException e) {
@@ -216,16 +224,17 @@
* @param cardId The Id of the eUICC.
* @param iccid The iccid of the profile to switch to.
* @param refresh Whether sending the REFRESH command to modem.
+ * @param executor The executor through which the callback should be invode.
* @param callback The callback to get the result code and the EuiccProfileInfo enabled.
*/
public void switchToProfile(String cardId, String iccid, boolean refresh,
- ResultCallback<EuiccProfileInfo> callback) {
+ @CallbackExecutor Executor executor, ResultCallback<EuiccProfileInfo> callback) {
try {
getIEuiccCardController().switchToProfile(mContext.getOpPackageName(), cardId, iccid,
refresh, new ISwitchToProfileCallback.Stub() {
@Override
public void onComplete(int resultCode, EuiccProfileInfo profile) {
- callback.onComplete(resultCode, profile);
+ executor.execute(() -> callback.onComplete(resultCode, profile));
}
});
} catch (RemoteException e) {
@@ -240,16 +249,17 @@
* @param cardId The Id of the eUICC.
* @param iccid The iccid of the profile.
* @param nickname The nickname of the profile.
+ * @param executor The executor through which the callback should be invode.
* @param callback The callback to get the result code.
*/
public void setNickname(String cardId, String iccid, String nickname,
- ResultCallback<Void> callback) {
+ @CallbackExecutor Executor executor, ResultCallback<Void> callback) {
try {
getIEuiccCardController().setNickname(mContext.getOpPackageName(), cardId, iccid,
nickname, new ISetNicknameCallback.Stub() {
@Override
public void onComplete(int resultCode) {
- callback.onComplete(resultCode, null);
+ executor.execute(() -> callback.onComplete(resultCode, null));
}
});
} catch (RemoteException e) {
@@ -263,15 +273,17 @@
*
* @param cardId The Id of the eUICC.
* @param iccid The iccid of the profile.
+ * @param executor The executor through which the callback should be invode.
* @param callback The callback to get the result code.
*/
- public void deleteProfile(String cardId, String iccid, ResultCallback<Void> callback) {
+ public void deleteProfile(String cardId, String iccid, @CallbackExecutor Executor executor,
+ ResultCallback<Void> callback) {
try {
getIEuiccCardController().deleteProfile(mContext.getOpPackageName(), cardId, iccid,
new IDeleteProfileCallback.Stub() {
@Override
public void onComplete(int resultCode) {
- callback.onComplete(resultCode, null);
+ executor.execute(() -> callback.onComplete(resultCode, null));
}
});
} catch (RemoteException e) {
@@ -286,15 +298,17 @@
* @param cardId The Id of the eUICC.
* @param options Bits of the options of resetting which parts of the eUICC memory. See
* EuiccCard for details.
+ * @param executor The executor through which the callback should be invode.
* @param callback The callback to get the result code.
*/
- public void resetMemory(String cardId, @ResetOption int options, ResultCallback<Void> callback) {
+ public void resetMemory(String cardId, @ResetOption int options,
+ @CallbackExecutor Executor executor, ResultCallback<Void> callback) {
try {
getIEuiccCardController().resetMemory(mContext.getOpPackageName(), cardId, options,
new IResetMemoryCallback.Stub() {
@Override
public void onComplete(int resultCode) {
- callback.onComplete(resultCode, null);
+ executor.execute(() -> callback.onComplete(resultCode, null));
}
});
} catch (RemoteException e) {
@@ -304,18 +318,20 @@
}
/**
- * Gets the default SM-DP+ address from eUICC.
+ * Requests the default SM-DP+ address from eUICC.
*
* @param cardId The Id of the eUICC.
+ * @param executor The executor through which the callback should be invode.
* @param callback The callback to get the result code and the default SM-DP+ address.
*/
- public void getDefaultSmdpAddress(String cardId, ResultCallback<String> callback) {
+ public void requestDefaultSmdpAddress(String cardId, @CallbackExecutor Executor executor,
+ ResultCallback<String> callback) {
try {
getIEuiccCardController().getDefaultSmdpAddress(mContext.getOpPackageName(), cardId,
new IGetDefaultSmdpAddressCallback.Stub() {
@Override
public void onComplete(int resultCode, String address) {
- callback.onComplete(resultCode, address);
+ executor.execute(() -> callback.onComplete(resultCode, address));
}
});
} catch (RemoteException e) {
@@ -325,18 +341,20 @@
}
/**
- * Gets the SM-DS address from eUICC.
+ * Requests the SM-DS address from eUICC.
*
* @param cardId The Id of the eUICC.
+ * @param executor The executor through which the callback should be invode.
* @param callback The callback to get the result code and the SM-DS address.
*/
- public void getSmdsAddress(String cardId, ResultCallback<String> callback) {
+ public void requestSmdsAddress(String cardId, @CallbackExecutor Executor executor,
+ ResultCallback<String> callback) {
try {
getIEuiccCardController().getSmdsAddress(mContext.getOpPackageName(), cardId,
new IGetSmdsAddressCallback.Stub() {
@Override
public void onComplete(int resultCode, String address) {
- callback.onComplete(resultCode, address);
+ executor.execute(() -> callback.onComplete(resultCode, address));
}
});
} catch (RemoteException e) {
@@ -350,16 +368,18 @@
*
* @param cardId The Id of the eUICC.
* @param defaultSmdpAddress The default SM-DP+ address to set.
+ * @param executor The executor through which the callback should be invode.
* @param callback The callback to get the result code.
*/
- public void setDefaultSmdpAddress(String cardId, String defaultSmdpAddress, ResultCallback<Void> callback) {
+ public void setDefaultSmdpAddress(String cardId, String defaultSmdpAddress,
+ @CallbackExecutor Executor executor, ResultCallback<Void> callback) {
try {
getIEuiccCardController().setDefaultSmdpAddress(mContext.getOpPackageName(), cardId,
defaultSmdpAddress,
new ISetDefaultSmdpAddressCallback.Stub() {
@Override
public void onComplete(int resultCode) {
- callback.onComplete(resultCode, null);
+ executor.execute(() -> callback.onComplete(resultCode, null));
}
});
} catch (RemoteException e) {
@@ -369,18 +389,20 @@
}
/**
- * Gets Rules Authorisation Table.
+ * Requests Rules Authorisation Table.
*
* @param cardId The Id of the eUICC.
+ * @param executor The executor through which the callback should be invode.
* @param callback the callback to get the result code and the rule authorisation table.
*/
- public void getRulesAuthTable(String cardId, ResultCallback<EuiccRulesAuthTable> callback) {
+ public void requestRulesAuthTable(String cardId, @CallbackExecutor Executor executor,
+ ResultCallback<EuiccRulesAuthTable> callback) {
try {
getIEuiccCardController().getRulesAuthTable(mContext.getOpPackageName(), cardId,
new IGetRulesAuthTableCallback.Stub() {
@Override
public void onComplete(int resultCode, EuiccRulesAuthTable rat) {
- callback.onComplete(resultCode, rat);
+ executor.execute(() -> callback.onComplete(resultCode, rat));
}
});
} catch (RemoteException e) {
@@ -390,18 +412,20 @@
}
/**
- * Gets the eUICC challenge for new profile downloading.
+ * Requests the eUICC challenge for new profile downloading.
*
* @param cardId The Id of the eUICC.
+ * @param executor The executor through which the callback should be invode.
* @param callback the callback to get the result code and the challenge.
*/
- public void getEuiccChallenge(String cardId, ResultCallback<byte[]> callback) {
+ public void requestEuiccChallenge(String cardId, @CallbackExecutor Executor executor,
+ ResultCallback<byte[]> callback) {
try {
getIEuiccCardController().getEuiccChallenge(mContext.getOpPackageName(), cardId,
new IGetEuiccChallengeCallback.Stub() {
@Override
public void onComplete(int resultCode, byte[] challenge) {
- callback.onComplete(resultCode, challenge);
+ executor.execute(() -> callback.onComplete(resultCode, challenge));
}
});
} catch (RemoteException e) {
@@ -411,18 +435,20 @@
}
/**
- * Gets the eUICC info1 defined in GSMA RSP v2.0+ for new profile downloading.
+ * Requests the eUICC info1 defined in GSMA RSP v2.0+ for new profile downloading.
*
* @param cardId The Id of the eUICC.
+ * @param executor The executor through which the callback should be invode.
* @param callback the callback to get the result code and the info1.
*/
- public void getEuiccInfo1(String cardId, ResultCallback<byte[]> callback) {
+ public void requestEuiccInfo1(String cardId, @CallbackExecutor Executor executor,
+ ResultCallback<byte[]> callback) {
try {
getIEuiccCardController().getEuiccInfo1(mContext.getOpPackageName(), cardId,
new IGetEuiccInfo1Callback.Stub() {
@Override
public void onComplete(int resultCode, byte[] info) {
- callback.onComplete(resultCode, info);
+ executor.execute(() -> callback.onComplete(resultCode, info));
}
});
} catch (RemoteException e) {
@@ -435,15 +461,17 @@
* Gets the eUICC info2 defined in GSMA RSP v2.0+ for new profile downloading.
*
* @param cardId The Id of the eUICC.
+ * @param executor The executor through which the callback should be invode.
* @param callback the callback to get the result code and the info2.
*/
- public void getEuiccInfo2(String cardId, ResultCallback<byte[]> callback) {
+ public void requestEuiccInfo2(String cardId, @CallbackExecutor Executor executor,
+ ResultCallback<byte[]> callback) {
try {
getIEuiccCardController().getEuiccInfo2(mContext.getOpPackageName(), cardId,
new IGetEuiccInfo2Callback.Stub() {
@Override
public void onComplete(int resultCode, byte[] info) {
- callback.onComplete(resultCode, info);
+ executor.execute(() -> callback.onComplete(resultCode, info));
}
});
} catch (RemoteException e) {
@@ -466,12 +494,13 @@
* GSMA RSP v2.0+.
* @param serverCertificate ASN.1 data in byte array indicating SM-DP+ Certificate returned by
* SM-DP+ server.
+ * @param executor The executor through which the callback should be invode.
* @param callback the callback to get the result code and a byte array which represents a
* {@code AuthenticateServerResponse} defined in GSMA RSP v2.0+.
*/
public void authenticateServer(String cardId, String matchingId, byte[] serverSigned1,
byte[] serverSignature1, byte[] euiccCiPkIdToBeUsed, byte[] serverCertificate,
- ResultCallback<byte[]> callback) {
+ @CallbackExecutor Executor executor, ResultCallback<byte[]> callback) {
try {
getIEuiccCardController().authenticateServer(
mContext.getOpPackageName(),
@@ -484,7 +513,7 @@
new IAuthenticateServerCallback.Stub() {
@Override
public void onComplete(int resultCode, byte[] response) {
- callback.onComplete(resultCode, response);
+ executor.execute(() -> callback.onComplete(resultCode, response));
}
});
} catch (RemoteException e) {
@@ -505,11 +534,13 @@
* SM-DP+ server.
* @param smdpCertificate ASN.1 data in byte array indicating the SM-DP+ Certificate returned
* by SM-DP+ server.
+ * @param executor The executor through which the callback should be invode.
* @param callback the callback to get the result code and a byte array which represents a
* {@code PrepareDownloadResponse} defined in GSMA RSP v2.0+
*/
public void prepareDownload(String cardId, @Nullable byte[] hashCc, byte[] smdpSigned2,
- byte[] smdpSignature2, byte[] smdpCertificate, ResultCallback<byte[]> callback) {
+ byte[] smdpSignature2, byte[] smdpCertificate, @CallbackExecutor Executor executor,
+ ResultCallback<byte[]> callback) {
try {
getIEuiccCardController().prepareDownload(
mContext.getOpPackageName(),
@@ -521,7 +552,7 @@
new IPrepareDownloadCallback.Stub() {
@Override
public void onComplete(int resultCode, byte[] response) {
- callback.onComplete(resultCode, response);
+ executor.execute(() -> callback.onComplete(resultCode, response));
}
});
} catch (RemoteException e) {
@@ -535,11 +566,12 @@
*
* @param cardId The Id of the eUICC.
* @param boundProfilePackage the Bound Profile Package data returned by SM-DP+ server.
+ * @param executor The executor through which the callback should be invode.
* @param callback the callback to get the result code and a byte array which represents a
* {@code LoadBoundProfilePackageResponse} defined in GSMA RSP v2.0+.
*/
public void loadBoundProfilePackage(String cardId, byte[] boundProfilePackage,
- ResultCallback<byte[]> callback) {
+ @CallbackExecutor Executor executor, ResultCallback<byte[]> callback) {
try {
getIEuiccCardController().loadBoundProfilePackage(
mContext.getOpPackageName(),
@@ -548,7 +580,7 @@
new ILoadBoundProfilePackageCallback.Stub() {
@Override
public void onComplete(int resultCode, byte[] response) {
- callback.onComplete(resultCode, response);
+ executor.execute(() -> callback.onComplete(resultCode, response));
}
});
} catch (RemoteException e) {
@@ -563,11 +595,12 @@
* @param cardId The Id of the eUICC.
* @param transactionId the transaction ID returned by SM-DP+ server.
* @param reason the cancel reason.
+ * @param executor The executor through which the callback should be invode.
* @param callback the callback to get the result code and an byte[] which represents a
* {@code CancelSessionResponse} defined in GSMA RSP v2.0+.
*/
public void cancelSession(String cardId, byte[] transactionId, @CancelReason int reason,
- ResultCallback<byte[]> callback) {
+ @CallbackExecutor Executor executor, ResultCallback<byte[]> callback) {
try {
getIEuiccCardController().cancelSession(
mContext.getOpPackageName(),
@@ -577,7 +610,7 @@
new ICancelSessionCallback.Stub() {
@Override
public void onComplete(int resultCode, byte[] response) {
- callback.onComplete(resultCode, response);
+ executor.execute(() -> callback.onComplete(resultCode, response));
}
});
} catch (RemoteException e) {
@@ -591,16 +624,17 @@
*
* @param cardId The Id of the eUICC.
* @param events bits of the event types ({@link EuiccNotification.Event}) to list.
+ * @param executor The executor through which the callback should be invode.
* @param callback the callback to get the result code and the list of notifications.
*/
public void listNotifications(String cardId, @EuiccNotification.Event int events,
- ResultCallback<EuiccNotification[]> callback) {
+ @CallbackExecutor Executor executor, ResultCallback<EuiccNotification[]> callback) {
try {
getIEuiccCardController().listNotifications(mContext.getOpPackageName(), cardId, events,
new IListNotificationsCallback.Stub() {
@Override
public void onComplete(int resultCode, EuiccNotification[] notifications) {
- callback.onComplete(resultCode, notifications);
+ executor.execute(() -> callback.onComplete(resultCode, notifications));
}
});
} catch (RemoteException e) {
@@ -614,16 +648,17 @@
*
* @param cardId The Id of the eUICC.
* @param events bits of the event types ({@link EuiccNotification.Event}) to list.
+ * @param executor The executor through which the callback should be invode.
* @param callback the callback to get the result code and the list of notifications.
*/
public void retrieveNotificationList(String cardId, @EuiccNotification.Event int events,
- ResultCallback<EuiccNotification[]> callback) {
+ @CallbackExecutor Executor executor, ResultCallback<EuiccNotification[]> callback) {
try {
getIEuiccCardController().retrieveNotificationList(mContext.getOpPackageName(), cardId,
events, new IRetrieveNotificationListCallback.Stub() {
@Override
public void onComplete(int resultCode, EuiccNotification[] notifications) {
- callback.onComplete(resultCode, notifications);
+ executor.execute(() -> callback.onComplete(resultCode, notifications));
}
});
} catch (RemoteException e) {
@@ -637,16 +672,17 @@
*
* @param cardId The Id of the eUICC.
* @param seqNumber the sequence number of the notification.
+ * @param executor The executor through which the callback should be invode.
* @param callback the callback to get the result code and the notification.
*/
public void retrieveNotification(String cardId, int seqNumber,
- ResultCallback<EuiccNotification> callback) {
+ @CallbackExecutor Executor executor, ResultCallback<EuiccNotification> callback) {
try {
getIEuiccCardController().retrieveNotification(mContext.getOpPackageName(), cardId,
seqNumber, new IRetrieveNotificationCallback.Stub() {
@Override
public void onComplete(int resultCode, EuiccNotification notification) {
- callback.onComplete(resultCode, notification);
+ executor.execute(() -> callback.onComplete(resultCode, notification));
}
});
} catch (RemoteException e) {
@@ -660,10 +696,11 @@
*
* @param cardId The Id of the eUICC.
* @param seqNumber the sequence number of the notification.
+ * @param executor The executor through which the callback should be invode.
* @param callback the callback to get the result code.
*/
public void removeNotificationFromList(String cardId, int seqNumber,
- ResultCallback<Void> callback) {
+ @CallbackExecutor Executor executor, ResultCallback<Void> callback) {
try {
getIEuiccCardController().removeNotificationFromList(
mContext.getOpPackageName(),
@@ -672,7 +709,7 @@
new IRemoveNotificationFromListCallback.Stub() {
@Override
public void onComplete(int resultCode) {
- callback.onComplete(resultCode, null);
+ executor.execute(() -> callback.onComplete(resultCode, null));
}
});
} catch (RemoteException e) {
diff --git a/telephony/java/android/telephony/euicc/EuiccInfo.java b/telephony/java/android/telephony/euicc/EuiccInfo.java
index 5bfff08..a4adf05 100644
--- a/telephony/java/android/telephony/euicc/EuiccInfo.java
+++ b/telephony/java/android/telephony/euicc/EuiccInfo.java
@@ -23,9 +23,6 @@
* Information about an eUICC chip/device.
*
* @see EuiccManager#getEuiccInfo
- * @hide
- *
- * TODO(b/35851809): Make this public.
*/
// WARNING: Do not add any privacy-sensitive fields to this class (such as an eUICC identifier)!
// This API is accessible to all applications. Privacy-sensitive fields should be returned in their
@@ -45,12 +42,17 @@
}
};
+ @Nullable
+ private final String osVersion;
+
/**
- * Version of the operating system running on the eUICC. This field is hardware-specific and is
- * not guaranteed to match any particular format.
+ * Gets the version of the operating system running on the eUICC. This field is
+ * hardware-specific and is not guaranteed to match any particular format.
*/
@Nullable
- public final String osVersion;
+ public String getOsVersion() {
+ return osVersion;
+ }
public EuiccInfo(@Nullable String osVersion) {
this.osVersion = osVersion;
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index 7f913ce..1637c55 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -42,9 +42,6 @@
* {@link Context#getSystemService(String)} and {@link Context#EUICC_SERVICE}.
*
* <p>See {@link #isEnabled} before attempting to use these APIs.
- *
- * TODO(b/35851809): Make this public.
- * @hide
*/
public class EuiccManager {
@@ -56,6 +53,8 @@
*
* <p>The activity will immediately finish with {@link android.app.Activity#RESULT_CANCELED} if
* {@link #isEnabled} is false.
+ *
+ * This is ued by non-LPA app to bring up LUI.
*/
@SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS =
@@ -69,8 +68,10 @@
*
* <p class="note">This is a protected intent that can only be sent
* by the system.
- * TODO(b/35851809): Make this a SystemApi.
+ *
+ * @hide
*/
+ @SystemApi
@SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_OTA_STATUS_CHANGED =
"android.telephony.euicc.action.OTA_STATUS_CHANGED";
@@ -78,12 +79,10 @@
/**
* Broadcast Action: The action sent to carrier app so it knows the carrier setup is not
* completed.
- *
- * TODO(b/35851809): Make this a public API.
*/
@SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_NOTIFY_CARRIER_SETUP =
- "android.telephony.euicc.action.NOTIFY_CARRIER_SETUP";
+ public static final String ACTION_NOTIFY_CARRIER_SETUP_INCOMPLETE =
+ "android.telephony.euicc.action.NOTIFY_CARRIER_SETUP_INCOMPLETE";
/**
* Intent action to provision an embedded subscription.
@@ -95,8 +94,9 @@
* <p>The activity will immediately finish with {@link android.app.Activity#RESULT_CANCELED} if
* {@link #isEnabled} is false.
*
- * TODO(b/35851809): Make this a SystemApi.
+ * @hide
*/
+ @SystemApi
@SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_PROVISION_EMBEDDED_SUBSCRIPTION =
"android.telephony.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION";
@@ -143,9 +143,8 @@
* Key for an extra set on {@link #getDownloadableSubscriptionMetadata} PendingIntent result
* callbacks providing the downloadable subscription metadata.
* @hide
- *
- * TODO(b/35851809): Make this a SystemApi.
*/
+ @SystemApi
public static final String EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION =
"android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION";
@@ -153,9 +152,8 @@
* Key for an extra set on {@link #getDefaultDownloadableSubscriptionList} PendingIntent result
* callbacks providing the list of available downloadable subscriptions.
* @hide
- *
- * TODO(b/35851809): Make this a SystemApi.
*/
+ @SystemApi
public static final String EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTIONS =
"android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTIONS";
@@ -201,6 +199,7 @@
* Euicc OTA update status which can be got by {@link #getOtaStatus}
* @hide
*/
+ @SystemApi
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = {"EUICC_OTA_"}, value = {
EUICC_OTA_IN_PROGRESS,
@@ -215,15 +214,37 @@
/**
* An OTA is in progress. During this time, the eUICC is not available and the user may lose
* network access.
+ * @hide
*/
+ @SystemApi
public static final int EUICC_OTA_IN_PROGRESS = 1;
- /** The OTA update failed. */
+
+ /**
+ * The OTA update failed.
+ * @hide
+ */
+ @SystemApi
public static final int EUICC_OTA_FAILED = 2;
- /** The OTA update finished successfully. */
+
+ /**
+ * The OTA update finished successfully.
+ * @hide
+ */
+ @SystemApi
public static final int EUICC_OTA_SUCCEEDED = 3;
- /** The OTA update not needed since current eUICC OS is latest. */
+
+ /**
+ * The OTA update not needed since current eUICC OS is latest.
+ * @hide
+ */
+ @SystemApi
public static final int EUICC_OTA_NOT_NEEDED = 4;
- /** The OTA status is unavailable since eUICC service is unavailable. */
+
+ /**
+ * The OTA status is unavailable since eUICC service is unavailable.
+ * @hide
+ */
+ @SystemApi
public static final int EUICC_OTA_STATUS_UNAVAILABLE = 5;
private final Context mContext;
@@ -276,8 +297,10 @@
*
* @return the status of eUICC OTA. If {@link #isEnabled()} is false or the eUICC is not ready,
* {@link OtaStatus#EUICC_OTA_STATUS_UNAVAILABLE} will be returned.
- * TODO(b/35851809): Make this a SystemApi.
+ *
+ * @hide
*/
+ @SystemApi
public int getOtaStatus() {
if (!isEnabled()) {
return EUICC_OTA_STATUS_UNAVAILABLE;
@@ -292,7 +315,7 @@
/**
* Attempt to download the given {@link DownloadableSubscription}.
*
- * <p>Requires the {@link android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission,
+ * <p>Requires the {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission,
* or the calling app must be authorized to manage both the currently-active subscription and
* the subscription to be downloaded according to the subscription metadata. Without the former,
* an {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} will be returned in the callback
@@ -354,14 +377,16 @@
*
* <p>To be called by the LUI upon completion of a resolvable error flow.
*
+ * <p>Requires that the calling app has the
+ * {@link android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission.
+ *
* @param resolutionIntent The original intent used to start the LUI.
* @param resolutionExtras Resolution-specific extras depending on the result of the resolution.
* For example, this may indicate whether the user has consented or may include the input
* they provided.
* @hide
- *
- * TODO(b/35851809): Make this a SystemApi.
*/
+ @SystemApi
public void continueOperation(Intent resolutionIntent, Bundle resolutionExtras) {
if (!isEnabled()) {
PendingIntent callbackIntent =
@@ -395,9 +420,8 @@
* @param subscription the subscription which needs metadata filled in
* @param callbackIntent a PendingIntent to launch when the operation completes.
* @hide
- *
- * TODO(b/35851809): Make this a SystemApi.
*/
+ @SystemApi
public void getDownloadableSubscriptionMetadata(
DownloadableSubscription subscription, PendingIntent callbackIntent) {
if (!isEnabled()) {
@@ -426,9 +450,8 @@
*
* @param callbackIntent a PendingIntent to launch when the operation completes.
* @hide
- *
- * TODO(b/35851809): Make this a SystemApi.
*/
+ @SystemApi
public void getDefaultDownloadableSubscriptionList(PendingIntent callbackIntent) {
if (!isEnabled()) {
sendUnavailableError(callbackIntent);
@@ -468,7 +491,7 @@
*
* <p>Requires that the calling app has carrier privileges according to the metadata of the
* profile to be deleted, or the
- * {@link android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission.
+ * {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission.
*
* @param subscriptionId the ID of the subscription to delete.
* @param callbackIntent a PendingIntent to launch when the operation completes.
@@ -489,7 +512,7 @@
/**
* Switch to (enable) the given subscription.
*
- * <p>Requires the {@link android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission,
+ * <p>Requires the {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission,
* or the calling app must be authorized to manage both the currently-active subscription and
* the subscription to be enabled according to the subscription metadata. Without the former,
* an {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} will be returned in the callback
@@ -599,11 +622,7 @@
}
}
- /**
- * @hide
- */
- @TestApi
- protected IEuiccController getIEuiccController() {
+ private static IEuiccController getIEuiccController() {
return IEuiccController.Stub.asInterface(ServiceManager.getService("econtroller"));
}
}
diff --git a/telephony/java/android/telephony/euicc/EuiccNotification.java b/telephony/java/android/telephony/euicc/EuiccNotification.java
index ef3c1ce..43a7707 100644
--- a/telephony/java/android/telephony/euicc/EuiccNotification.java
+++ b/telephony/java/android/telephony/euicc/EuiccNotification.java
@@ -17,6 +17,7 @@
import android.annotation.IntDef;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -31,10 +32,9 @@
* disabling, or deleting).
*
* @hide
- *
- * TODO(b/35851809): Make this a @SystemApi.
*/
-public class EuiccNotification implements Parcelable {
+@SystemApi
+public final class EuiccNotification implements Parcelable {
/** Event */
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = true, prefix = { "EVENT_" }, value = {
@@ -43,6 +43,7 @@
EVENT_DISABLE,
EVENT_DELETE
})
+ /** @hide */
public @interface Event {}
/** A profile is downloaded and installed. */
@@ -57,7 +58,7 @@
/** A profile is deleted. */
public static final int EVENT_DELETE = 1 << 3;
- /** Value of the bits of all above events */
+ /** Value of the bits of all the events including install, enable, disable and delete. */
@Event
public static final int ALL_EVENTS =
EVENT_INSTALL | EVENT_ENABLE | EVENT_DISABLE | EVENT_DELETE;
diff --git a/telephony/java/android/telephony/euicc/EuiccRulesAuthTable.java b/telephony/java/android/telephony/euicc/EuiccRulesAuthTable.java
index 7efe043..67ae983 100644
--- a/telephony/java/android/telephony/euicc/EuiccRulesAuthTable.java
+++ b/telephony/java/android/telephony/euicc/EuiccRulesAuthTable.java
@@ -16,6 +16,7 @@
package android.telephony.euicc;
import android.annotation.IntDef;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.service.carrier.CarrierIdentifier;
@@ -27,20 +28,21 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.List;
/**
* This represents the RAT (Rules Authorisation Table) stored on eUICC.
- *
* @hide
- *
- * TODO(b/35851809): Make this a @SystemApi.
*/
+@SystemApi
public final class EuiccRulesAuthTable implements Parcelable {
/** Profile policy rule flags */
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = true, prefix = { "POLICY_RULE_FLAG_" }, value = {
POLICY_RULE_FLAG_CONSENT_REQUIRED
})
+ /** @hide */
public @interface PolicyRuleFlag {}
/** User consent is required to install the profile. */
@@ -89,12 +91,14 @@
* @throws ArrayIndexOutOfBoundsException If the {@code mPosition} is larger than the size
* this table.
*/
- public Builder add(int policyRules, CarrierIdentifier[] carrierId, int policyRuleFlags) {
+ public Builder add(int policyRules, List<CarrierIdentifier> carrierId, int policyRuleFlags) {
if (mPosition >= mPolicyRules.length) {
throw new ArrayIndexOutOfBoundsException(mPosition);
}
mPolicyRules[mPosition] = policyRules;
- mCarrierIds[mPosition] = carrierId;
+ if (carrierId != null && carrierId.size() > 0) {
+ mCarrierIds[mPosition] = carrierId.toArray(new CarrierIdentifier[carrierId.size()]);
+ }
mPolicyRuleFlags[mPosition] = policyRuleFlags;
mPosition++;
return this;
diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java
index bfdd453..1fdbae9 100644
--- a/telephony/java/android/telephony/ims/feature/ImsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java
@@ -80,7 +80,7 @@
public static final String EXTRA_PHONE_ID = "android:phone_id";
/**
- * Invalid feature value\
+ * Invalid feature value
* @hide
*/
public static final int FEATURE_INVALID = -1;
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 2b4c059..02cc82c 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1123,33 +1123,33 @@
boolean isHearingAidCompatibilitySupported();
/**
- * Get IMS Registration Status
- */
- boolean isImsRegistered();
-
- /**
* Get IMS Registration Status on a particular subid.
*
* @param subId user preferred subId.
*
* @return {@code true} if the IMS status is registered.
*/
- boolean isImsRegisteredForSubscriber(int subId);
+ boolean isImsRegistered(int subId);
/**
- * Returns the Status of Wi-Fi Calling
+ * Returns the Status of Wi-Fi Calling for the subscription id specified.
*/
- boolean isWifiCallingAvailable();
+ boolean isWifiCallingAvailable(int subId);
/**
- * Returns the Status of Volte
+ * Returns the Status of VoLTE for the subscription ID specified.
*/
- boolean isVolteAvailable();
+ boolean isVolteAvailable(int subId);
/**
- * Returns the Status of VT (video telephony)
+ * Returns the Status of VT (video telephony) for the subscription ID specified.
*/
- boolean isVideoTelephonyAvailable();
+ boolean isVideoTelephonyAvailable(int subId);
+
+ /**
+ * Returns the MMTEL IMS registration technology for the subsciption ID specified.
+ */
+ int getImsRegTechnologyForMmTel(int subId);
/**
* Returns the unique device ID of phone, for example, the IMEI for
diff --git a/tests/ActivityManagerPerfTests/README.txt b/tests/ActivityManagerPerfTests/README.txt
index 77e0e90..1040ed1 100644
--- a/tests/ActivityManagerPerfTests/README.txt
+++ b/tests/ActivityManagerPerfTests/README.txt
@@ -1,12 +1,15 @@
ActivityManagerPerfTests
Performance tests for various ActivityManager components, e.g. Services, Broadcasts
+* These are only for tests that don't require a target package to test against
+* Self-contained perf tests should go in frameworks/base/apct-tests/perftests
-Command to run tests (not working yet, atest seems buggy)
-* atest .../frameworks/base/tests/ActivityManagerPerfTests
+Command to run tests
+* atest .../frameworks/base/tests/ActivityManagerPerfTests/tests/
+ * Command currently not working: b/71859981
* m ActivityManagerPerfTests ActivityManagerPerfTestsTestApp && \
- adb install $OUT/data/app/ActivityManagerPerfTests/ActivityManagerPerfTests.apk && \
- adb install $OUT/data/app/ActivityManagerPerfTestsTestApp/ActivityManagerPerfTestsTestApp.apk && \
+ adb install "$OUT"/data/app/ActivityManagerPerfTests/ActivityManagerPerfTests.apk && \
+ adb install "$OUT"/data/app/ActivityManagerPerfTestsTestApp/ActivityManagerPerfTestsTestApp.apk && \
adb shell am instrument -w \
com.android.frameworks.perftests.amtests/android.support.test.runner.AndroidJUnitRunner
@@ -15,20 +18,42 @@
* For example, the time it takes from sending an Intent to start a Service
to the time the Service runs its callbacks
* System.nanoTime() is monotonic and consistent between processes, so we use that for measuring time
-* To make sure the test app is running, we start an Activity
* If the test app is involved, it will measure the time and send it back to the instrumentation test
- * The time is sent back through a Binder interface in the Intent
+ * The time is sent back through a Binder interface in the Intent with the help of Utils.sendTime()
* Each sent time is tagged with an id since there can be multiple events that send back a time
- * For example, one is sent when the Activity is started, and another could be sent when a
- Broadcast is received
+* Each test will run multiple times to account for variation in test runs
Structure
* tests
* Instrumentation test which runs the various performance tests and reports the results
-
* test-app
* Target package which contains the Services, BroadcastReceivers, etc. to test against
* Sends the time it measures back to the test package
-
* utils
* Utilities that both the instrumentation test and test app can use
+
+Adding tests
+* Example
+ * Look at tests/src/com/android/frameworks/perftests/am/BroadcastPerfTest and
+ test-app/src/com/android/frameworks/perftests/amteststestapp/TestBroadcastReceiver
+ for simple examples using this framework
+* Steps
+ * Add any components you will test against in the target package under
+ test-app/src/com/android/frameworks/perftests/amteststestapp/
+ * Add the test class under tests/src/com/android/frameworks/perftests/am/tests/
+ * The class should extend BasePerfTest
+ * Each test should call runPerfFunction() returning the elapsed time for a single iteration
+ * The test has access to a Context through mContext
+ * If you are measuring the time elapsed of something that either starts or ends in the target
+ package
+ * The target package can report the time it measures through an ITimeReceiverCallback passed
+ through an Intent through Utils.sendTime(intent, "tag")
+ (or however a Binder needs to be passed to the target package)
+ * The instrumentation test can collect that time by calling getReceivedTimeNs("tag") and
+ calculate the elapsed time
+ * Each timestamp sent to the instrumentation test is tagged with a tag since multiple timestamps
+ can be reported in an iteration
+ * If the target package should be running before your test logic starts, add startTargetPackage();
+ at the beginning of the iteration
+* Reporting
+ * Look at go/am-perf for how to add new tests to dashboards and receive notification on regression
diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
index 063060f..228f9bb 100644
--- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
+++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
@@ -65,6 +65,7 @@
private static final int JOIN_TIMEOUT = 10000;
private static final String TAG = AppLaunch.class.getSimpleName();
+
// optional parameter: comma separated list of required account types before proceeding
// with the app launch
private static final String KEY_REQUIRED_ACCOUNTS = "required_accounts";
@@ -73,32 +74,36 @@
private static final String KEY_LAUNCH_ITERATIONS = "launch_iterations";
private static final String KEY_LAUNCH_ORDER = "launch_order";
private static final String KEY_DROP_CACHE = "drop_cache";
- private static final String KEY_SIMULATE_MAINTANANCE = "simulate_maintanance";
- private static final String KEY_SIMPLEPPERF_CMD = "simpleperf_cmd";
+ private static final String KEY_SIMPLEPERF_CMD = "simpleperf_cmd";
+ private static final String KEY_SIMPLEPERF_APP = "simpleperf_app";
private static final String KEY_TRACE_ITERATIONS = "trace_iterations";
private static final String KEY_LAUNCH_DIRECTORY = "launch_directory";
private static final String KEY_TRACE_DIRECTORY = "trace_directory";
private static final String KEY_TRACE_CATEGORY = "trace_categories";
private static final String KEY_TRACE_BUFFERSIZE = "trace_bufferSize";
private static final String KEY_TRACE_DUMPINTERVAL = "tracedump_interval";
+ private static final String KEY_COMPILER_FILTERS = "compiler_filters";
+
+ private static final String SIMPLEPERF_APP_CMD =
+ "simpleperf --log fatal stat --csv -e cpu-cycles,major-faults --app %s & %s";
private static final String WEARABLE_ACTION_GOOGLE =
"com.google.android.wearable.action.GOOGLE";
- private static final int INITIAL_LAUNCH_IDLE_TIMEOUT = 5000; //5s to allow app to idle
- private static final int POST_LAUNCH_IDLE_TIMEOUT = 750; //750ms idle for non initial launches
- private static final int BETWEEN_LAUNCH_SLEEP_TIMEOUT = 5000; //5s between launching apps
+ private static final int INITIAL_LAUNCH_IDLE_TIMEOUT = 5000; // 5s to allow app to idle
+ private static final int POST_LAUNCH_IDLE_TIMEOUT = 750; // 750ms idle for non initial launches
+ private static final int BETWEEN_LAUNCH_SLEEP_TIMEOUT = 5000; // 5s between launching apps
private static final String LAUNCH_SUB_DIRECTORY = "launch_logs";
private static final String LAUNCH_FILE = "applaunch.txt";
private static final String TRACE_SUB_DIRECTORY = "atrace_logs";
- private static final String DEFAULT_TRACE_CATEGORIES = "sched,freq,gfx,view,dalvik,webview,"
- + "input,wm,disk,am,wm";
+ private static final String DEFAULT_TRACE_CATEGORIES =
+ "sched,freq,gfx,view,dalvik,webview,input,wm,disk,am,wm";
private static final String DEFAULT_TRACE_BUFFER_SIZE = "20000";
private static final String DEFAULT_TRACE_DUMP_INTERVAL = "10";
- private static final String TRIAL_LAUNCH = "TRAIL_LAUNCH";
+ private static final String TRIAL_LAUNCH = "TRIAL_LAUNCH";
private static final String DELIMITER = ",";
private static final String DROP_CACHE_SCRIPT = "/data/local/tmp/dropCache.sh";
private static final String APP_LAUNCH_CMD = "am start -W -n";
private static final String SUCCESS_MESSAGE = "Status: ok";
- private static final String PROFILE_COMPILE_SUCCESS = "Success";
+ private static final String COMPILE_SUCCESS = "Success";
private static final String THIS_TIME = "ThisTime:";
private static final String LAUNCH_ITERATION = "LAUNCH_ITERATION - %d";
private static final String TRACE_ITERATION = "TRACE_ITERATION-%d";
@@ -106,14 +111,15 @@
private static final String TRACE_ITERATION_PREFIX = "TRACE_ITERATION";
private static final String LAUNCH_ORDER_CYCLIC = "cyclic";
private static final String LAUNCH_ORDER_SEQUENTIAL = "sequential";
- private static final String SPEED_PROFILE_CMD = "cmd package compile -f -m speed-profile %s";
-
-
+ private static final String COMPILE_CMD = "cmd package compile -f -m %s %s";
+ private static final String SPEED_PROFILE_FILTER = "speed-profile";
+ private static final String VERIFY_FILTER = "verify";
+ private static final String LAUNCH_SCRIPT_NAME = "appLaunch";
private Map<String, Intent> mNameToIntent;
private List<LaunchOrder> mLaunchOrderList = new ArrayList<LaunchOrder>();
private Map<String, String> mNameToResultKey;
- private Map<String, List<Long>> mNameToLaunchTime;
+ private Map<String, Map<String, List<AppLaunchResult>>> mNameToLaunchTime;
private IActivityManager mAm;
private String mSimplePerfCmd = null;
private String mLaunchOrder = null;
@@ -123,12 +129,10 @@
private String mTraceDirectoryStr = null;
private Bundle mResult = new Bundle();
private Set<String> mRequiredAccounts;
- private boolean mTrailLaunch = true;
- private File mFile = null;
- private FileOutputStream mOutputStream = null;
+ private boolean mTrialLaunch = false;
private BufferedWriter mBufferedWriter = null;
- private boolean mSimulateMaintanance = false;
-
+ private boolean mSimplePerfAppOnly = false;
+ private String[] mCompilerFilters = null;
@Override
protected void setUp() throws Exception {
@@ -142,6 +146,16 @@
super.tearDown();
}
+ private void addLaunchResult(LaunchOrder launch, AppLaunchResult result) {
+ mNameToLaunchTime.get(launch.getApp()).get(launch.getCompilerFilter()).add(result);
+ }
+
+ private boolean hasFailureOnFirstLaunch(LaunchOrder launch) {
+ List<AppLaunchResult> results =
+ mNameToLaunchTime.get(launch.getApp()).get(launch.getCompilerFilter());
+ return (results.size() > 0) && (results.get(0).mLaunchTime < 0);
+ }
+
public void testMeasureStartUpTime() throws RemoteException, NameNotFoundException,
IOException, InterruptedException {
InstrumentationTestRunner instrumentation =
@@ -149,11 +163,6 @@
Bundle args = instrumentation.getArguments();
mAm = ActivityManager.getService();
String launchDirectory = args.getString(KEY_LAUNCH_DIRECTORY);
- mTraceDirectoryStr = args.getString(KEY_TRACE_DIRECTORY);
- mDropCache = Boolean.parseBoolean(args.getString(KEY_DROP_CACHE));
- mSimplePerfCmd = args.getString(KEY_SIMPLEPPERF_CMD);
- mLaunchOrder = args.getString(KEY_LAUNCH_ORDER, LAUNCH_ORDER_CYCLIC);
- mSimulateMaintanance = Boolean.parseBoolean(args.getString(KEY_SIMULATE_MAINTANANCE));
createMappings();
parseArgs(args);
@@ -171,13 +180,14 @@
try {
File launchSubDir = new File(launchRootDir, LAUNCH_SUB_DIRECTORY);
+
if (!launchSubDir.exists() && !launchSubDir.mkdirs()) {
throw new IOException("Unable to create the lauch file sub directory");
}
- mFile = new File(launchSubDir, LAUNCH_FILE);
- mOutputStream = new FileOutputStream(mFile);
+ File file = new File(launchSubDir, LAUNCH_FILE);
+ FileOutputStream outputStream = new FileOutputStream(file);
mBufferedWriter = new BufferedWriter(new OutputStreamWriter(
- mOutputStream));
+ outputStream));
// Root directory for trace file during the launches
File rootTrace = null;
@@ -217,70 +227,67 @@
setLaunchOrder();
for (LaunchOrder launch : mLaunchOrderList) {
+ dropCache();
// App launch times for trial launch will not be used for final
// launch time calculations.
if (launch.getLaunchReason().equals(TRIAL_LAUNCH)) {
// In the "applaunch.txt" file, trail launches is referenced using
// "TRIAL_LAUNCH"
- long launchTime = startApp(launch.getApp(), true, launch.getLaunchReason());
- if (launchTime < 0) {
- List<Long> appLaunchList = new ArrayList<Long>();
- appLaunchList.add(-1L);
- mNameToLaunchTime.put(launch.getApp(), appLaunchList);
+ String appPkgName = mNameToIntent.get(launch.getApp())
+ .getComponent().getPackageName();
+ if (SPEED_PROFILE_FILTER.equals(launch.getCompilerFilter())) {
+ assertTrue(String.format("Not able to compile the app : %s", appPkgName),
+ compileApp(VERIFY_FILTER, appPkgName));
+ } else if (launch.getCompilerFilter() != null) {
+ assertTrue(String.format("Not able to compile the app : %s", appPkgName),
+ compileApp(launch.getCompilerFilter(), appPkgName));
+ }
+ // We only need to run a trial for the speed-profile filter, but we always
+ // run one for "applaunch.txt" consistency.
+ AppLaunchResult launchResult =
+ startApp(launch.getApp(), true, launch.getLaunchReason());
+ if (launchResult.mLaunchTime < 0) {
+ addLaunchResult(launch, new AppLaunchResult());
// simply pass the app if launch isn't successful
// error should have already been logged by startApp
continue;
}
sleep(INITIAL_LAUNCH_IDLE_TIMEOUT);
- closeApp(launch.getApp(), true);
- dropCache();
- if (mSimulateMaintanance) {
- String appPkgName = mNameToIntent.get(launch.getApp())
- .getComponent().getPackageName();
- assertTrue(String.format("Not able to speed profile the app : %s",
- appPkgName), profileCompileApp(appPkgName));
+ if (SPEED_PROFILE_FILTER.equals(launch.getCompilerFilter())) {
+ // Send SIGUSR1 to force dumping a profile.
+ String sendSignalCommand =
+ String.format("killall -s SIGUSR1 %s", appPkgName);
+ getInstrumentation().getUiAutomation().executeShellCommand(
+ sendSignalCommand);
+ assertTrue(String.format("Not able to compile the app : %s", appPkgName),
+ compileApp(launch.getCompilerFilter(), appPkgName));
}
- sleep(BETWEEN_LAUNCH_SLEEP_TIMEOUT);
}
// App launch times used for final calculation
- if (launch.getLaunchReason().contains(LAUNCH_ITERATION_PREFIX)) {
- long launchTime = -1;
- if (null != mNameToLaunchTime.get(launch.getApp())) {
- long firstLaunchTime = mNameToLaunchTime.get(launch.getApp()).get(0);
- if (firstLaunchTime < 0) {
- // skip if the app has failures while launched first
- continue;
- }
+ else if (launch.getLaunchReason().contains(LAUNCH_ITERATION_PREFIX)) {
+ AppLaunchResult launchResults = null;
+ if (hasFailureOnFirstLaunch(launch)) {
+ // skip if the app has failures while launched first
+ continue;
}
// In the "applaunch.txt" file app launches are referenced using
// "LAUNCH_ITERATION - ITERATION NUM"
- launchTime = startApp(launch.getApp(), true, launch.getLaunchReason());
- if (launchTime < 0) {
+ launchResults = startApp(launch.getApp(), true, launch.getLaunchReason());
+ if (launchResults.mLaunchTime < 0) {
+ addLaunchResult(launch, new AppLaunchResult());
// if it fails once, skip the rest of the launches
- List<Long> appLaunchList = new ArrayList<Long>();
- appLaunchList.add(-1L);
- mNameToLaunchTime.put(launch.getApp(), appLaunchList);
continue;
} else {
- if (null != mNameToLaunchTime.get(launch.getApp())) {
- mNameToLaunchTime.get(launch.getApp()).add(launchTime);
- } else {
- List<Long> appLaunchList = new ArrayList<Long>();
- appLaunchList.add(launchTime);
- mNameToLaunchTime.put(launch.getApp(), appLaunchList);
- }
+ addLaunchResult(launch, launchResults);
}
sleep(POST_LAUNCH_IDLE_TIMEOUT);
- closeApp(launch.getApp(), true);
- dropCache();
- sleep(BETWEEN_LAUNCH_SLEEP_TIMEOUT);
}
// App launch times for trace launch will not be used for final
// launch time calculations.
- if (launch.getLaunchReason().contains(TRACE_ITERATION_PREFIX)) {
+ else if (launch.getLaunchReason().contains(TRACE_ITERATION_PREFIX)) {
AtraceLogger atraceLogger = AtraceLogger
.getAtraceLoggerInstance(getInstrumentation());
// Start the trace
@@ -293,11 +300,10 @@
} finally {
// Stop the trace
atraceLogger.atraceStop();
- closeApp(launch.getApp(), true);
- dropCache();
- sleep(BETWEEN_LAUNCH_SLEEP_TIMEOUT);
}
}
+ closeApp(launch.getApp(), true);
+ sleep(BETWEEN_LAUNCH_SLEEP_TIMEOUT);
}
} finally {
if (null != mBufferedWriter) {
@@ -306,29 +312,45 @@
}
for (String app : mNameToResultKey.keySet()) {
- StringBuilder launchTimes = new StringBuilder();
- for (Long launch : mNameToLaunchTime.get(app)) {
- launchTimes.append(launch);
- launchTimes.append(",");
+ for (String compilerFilter : mCompilerFilters) {
+ StringBuilder launchTimes = new StringBuilder();
+ StringBuilder cpuCycles = new StringBuilder();
+ StringBuilder majorFaults = new StringBuilder();
+ for (AppLaunchResult result : mNameToLaunchTime.get(app).get(compilerFilter)) {
+ launchTimes.append(result.mLaunchTime);
+ launchTimes.append(",");
+ if (mSimplePerfAppOnly) {
+ cpuCycles.append(result.mCpuCycles);
+ cpuCycles.append(",");
+ majorFaults.append(result.mMajorFaults);
+ majorFaults.append(",");
+ }
+ }
+ String filterName = (compilerFilter == null) ? "" : ("-" + compilerFilter);
+ mResult.putString(mNameToResultKey.get(app) + filterName, launchTimes.toString());
+ if (mSimplePerfAppOnly) {
+ mResult.putString(mNameToResultKey.get(app) + filterName + "-cpuCycles",
+ cpuCycles.toString());
+ mResult.putString(mNameToResultKey.get(app) + filterName + "-majorFaults",
+ majorFaults.toString());
+ }
}
- mResult.putString(mNameToResultKey.get(app), launchTimes.toString());
}
instrumentation.sendStatus(0, mResult);
}
/**
- * Compile the app package using speed compile command and return true or false
+ * Compile the app package using compilerFilter and return true or false
* based on status of the compilation command.
*/
- private boolean profileCompileApp(String appPkgName) throws IOException {
- Log.i(TAG, "Starting to speed profile " + appPkgName);
+ private boolean compileApp(String compilerFilter, String appPkgName) throws IOException {
try (ParcelFileDescriptor result = getInstrumentation().getUiAutomation().
- executeShellCommand(String.format(SPEED_PROFILE_CMD, appPkgName));
+ executeShellCommand(String.format(COMPILE_CMD, compilerFilter, appPkgName));
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(
new FileInputStream(result.getFileDescriptor())))) {
String line;
while ((line = bufferedReader.readLine()) != null) {
- if (line.contains(PROFILE_COMPILE_SUCCESS)) {
+ if (line.contains(COMPILE_SUCCESS)) {
return true;
}
}
@@ -344,38 +366,42 @@
*/
private void setLaunchOrder() {
if (LAUNCH_ORDER_CYCLIC.equalsIgnoreCase(mLaunchOrder)) {
- if (mTrailLaunch) {
- for (String app : mNameToResultKey.keySet()) {
- mLaunchOrderList.add(new LaunchOrder(app, TRIAL_LAUNCH));
- }
- }
- for (int launchCount = 0; launchCount < mLaunchIterations; launchCount++) {
- for (String app : mNameToResultKey.keySet()) {
- mLaunchOrderList.add(new LaunchOrder(app,
- String.format(LAUNCH_ITERATION, launchCount)));
- }
- }
- if (mTraceDirectoryStr != null && !mTraceDirectoryStr.isEmpty()) {
- for (int traceCount = 0; traceCount < mTraceLaunchCount; traceCount++) {
+ for (String compilerFilter : mCompilerFilters) {
+ if (mTrialLaunch) {
for (String app : mNameToResultKey.keySet()) {
- mLaunchOrderList.add(new LaunchOrder(app,
- String.format(TRACE_ITERATION, traceCount)));
+ mLaunchOrderList.add(new LaunchOrder(app, compilerFilter, TRIAL_LAUNCH));
+ }
+ }
+ for (int launchCount = 0; launchCount < mLaunchIterations; launchCount++) {
+ for (String app : mNameToResultKey.keySet()) {
+ mLaunchOrderList.add(new LaunchOrder(app, compilerFilter,
+ String.format(LAUNCH_ITERATION, launchCount)));
+ }
+ }
+ if (mTraceDirectoryStr != null && !mTraceDirectoryStr.isEmpty()) {
+ for (int traceCount = 0; traceCount < mTraceLaunchCount; traceCount++) {
+ for (String app : mNameToResultKey.keySet()) {
+ mLaunchOrderList.add(new LaunchOrder(app, compilerFilter,
+ String.format(TRACE_ITERATION, traceCount)));
+ }
}
}
}
} else if (LAUNCH_ORDER_SEQUENTIAL.equalsIgnoreCase(mLaunchOrder)) {
- for (String app : mNameToResultKey.keySet()) {
- if (mTrailLaunch) {
- mLaunchOrderList.add(new LaunchOrder(app, TRIAL_LAUNCH));
- }
- for (int launchCount = 0; launchCount < mLaunchIterations; launchCount++) {
- mLaunchOrderList.add(new LaunchOrder(app,
- String.format(LAUNCH_ITERATION, launchCount)));
- }
- if (mTraceDirectoryStr != null && !mTraceDirectoryStr.isEmpty()) {
- for (int traceCount = 0; traceCount < mTraceLaunchCount; traceCount++) {
- mLaunchOrderList.add(new LaunchOrder(app,
- String.format(TRACE_ITERATION, traceCount)));
+ for (String compilerFilter : mCompilerFilters) {
+ for (String app : mNameToResultKey.keySet()) {
+ if (mTrialLaunch) {
+ mLaunchOrderList.add(new LaunchOrder(app, compilerFilter, TRIAL_LAUNCH));
+ }
+ for (int launchCount = 0; launchCount < mLaunchIterations; launchCount++) {
+ mLaunchOrderList.add(new LaunchOrder(app, compilerFilter,
+ String.format(LAUNCH_ITERATION, launchCount)));
+ }
+ if (mTraceDirectoryStr != null && !mTraceDirectoryStr.isEmpty()) {
+ for (int traceCount = 0; traceCount < mTraceLaunchCount; traceCount++) {
+ mLaunchOrderList.add(new LaunchOrder(app, compilerFilter,
+ String.format(TRACE_ITERATION, traceCount)));
+ }
}
}
}
@@ -385,7 +411,7 @@
}
private void dropCache() {
- if (true == mDropCache) {
+ if (mDropCache) {
assertNotNull("Issue in dropping the cache",
getInstrumentation().getUiAutomation()
.executeShellCommand(DROP_CACHE_SCRIPT));
@@ -394,7 +420,7 @@
private void parseArgs(Bundle args) {
mNameToResultKey = new LinkedHashMap<String, String>();
- mNameToLaunchTime = new HashMap<String, List<Long>>();
+ mNameToLaunchTime = new HashMap<>();
String launchIterations = args.getString(KEY_LAUNCH_ITERATIONS);
if (launchIterations != null) {
mLaunchIterations = Integer.parseInt(launchIterations);
@@ -421,7 +447,38 @@
mRequiredAccounts.add(accountType);
}
}
- mTrailLaunch = "true".equals(args.getString(KEY_TRIAL_LAUNCH));
+
+ String compilerFilterList = args.getString(KEY_COMPILER_FILTERS);
+ if (compilerFilterList != null) {
+ // If a compiler filter is passed, we make a trial launch to force compilation
+ // of the apps.
+ mTrialLaunch = true;
+ mCompilerFilters = compilerFilterList.split("\\|");
+ } else {
+ // Just pass a null compiler filter to use the current state of the app.
+ mCompilerFilters = new String[1];
+ }
+
+ // Pre-populate the results map to avoid null checks.
+ for (String app : mNameToLaunchTime.keySet()) {
+ HashMap<String, List<AppLaunchResult>> map = new HashMap<>();
+ mNameToLaunchTime.put(app, map);
+ for (String compilerFilter : mCompilerFilters) {
+ map.put(compilerFilter, new ArrayList<>());
+ }
+ }
+
+ mTraceDirectoryStr = args.getString(KEY_TRACE_DIRECTORY);
+ mDropCache = Boolean.parseBoolean(args.getString(KEY_DROP_CACHE));
+ mSimplePerfCmd = args.getString(KEY_SIMPLEPERF_CMD);
+ mLaunchOrder = args.getString(KEY_LAUNCH_ORDER, LAUNCH_ORDER_CYCLIC);
+ mSimplePerfAppOnly = Boolean.parseBoolean(args.getString(KEY_SIMPLEPERF_APP));
+ mTrialLaunch = mTrialLaunch || Boolean.parseBoolean(args.getString(KEY_TRIAL_LAUNCH));
+
+ if (mSimplePerfCmd != null && mSimplePerfAppOnly) {
+ Log.w(TAG, String.format("Passing both %s and %s is not supported, ignoring %s",
+ KEY_SIMPLEPERF_CMD, KEY_SIMPLEPERF_APP));
+ }
}
private boolean hasLeanback(Context context) {
@@ -465,17 +522,17 @@
}
}
- private long startApp(String appName, boolean forceStopBeforeLaunch, String launchReason)
- throws NameNotFoundException, RemoteException {
+ private AppLaunchResult startApp(String appName, boolean forceStopBeforeLaunch,
+ String launchReason) throws NameNotFoundException, RemoteException {
Log.i(TAG, "Starting " + appName);
Intent startIntent = mNameToIntent.get(appName);
if (startIntent == null) {
Log.w(TAG, "App does not exist: " + appName);
mResult.putString(mNameToResultKey.get(appName), "App does not exist");
- return -1L;
+ return new AppLaunchResult();
}
- AppLaunchRunnable runnable = new AppLaunchRunnable(startIntent, forceStopBeforeLaunch ,
+ AppLaunchRunnable runnable = new AppLaunchRunnable(startIntent, forceStopBeforeLaunch,
launchReason);
Thread t = new Thread(runnable);
t.start();
@@ -569,10 +626,12 @@
private class LaunchOrder {
private String mApp;
+ private String mCompilerFilter;
private String mLaunchReason;
- LaunchOrder(String app,String launchReason){
+ LaunchOrder(String app, String compilerFilter, String launchReason){
mApp = app;
+ mCompilerFilter = compilerFilter;
mLaunchReason = launchReason;
}
@@ -584,6 +643,10 @@
mApp = app;
}
+ public String getCompilerFilter() {
+ return mCompilerFilter;
+ }
+
public String getLaunchReason() {
return mLaunchReason;
}
@@ -593,9 +656,31 @@
}
}
+ private class AppLaunchResult {
+ long mLaunchTime;
+ long mCpuCycles;
+ long mMajorFaults;
+
+ AppLaunchResult() {
+ mLaunchTime = -1L;
+ mCpuCycles = -1L;
+ mMajorFaults = -1L;
+ }
+
+ AppLaunchResult(String launchTime, String cpuCycles, String majorFaults) {
+ try {
+ mLaunchTime = Long.parseLong(launchTime, 10);
+ mCpuCycles = Long.parseLong(cpuCycles, 10);
+ mMajorFaults = Long.parseLong(majorFaults, 10);
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "Error parsing result", e);
+ }
+ }
+ }
+
private class AppLaunchRunnable implements Runnable {
private Intent mLaunchIntent;
- private Long mResult;
+ private AppLaunchResult mLaunchResult;
private boolean mForceStopBeforeLaunch;
private String mLaunchReason;
@@ -604,14 +689,15 @@
mLaunchIntent = intent;
mForceStopBeforeLaunch = forceStopBeforeLaunch;
mLaunchReason = launchReason;
- mResult = -1L;
+ mLaunchResult = new AppLaunchResult();
}
- public Long getResult() {
- return mResult;
+ public AppLaunchResult getResult() {
+ return mLaunchResult;
}
public void run() {
+ File launchFile = null;
try {
String packageName = mLaunchIntent.getComponent().getPackageName();
String componentName = mLaunchIntent.getComponent().flattenToShortString();
@@ -619,17 +705,38 @@
mAm.forceStopPackage(packageName, UserHandle.USER_CURRENT);
}
String launchCmd = String.format("%s %s", APP_LAUNCH_CMD, componentName);
- if (null != mSimplePerfCmd) {
+ if (mSimplePerfAppOnly) {
+ try {
+ // executeShellCommand cannot handle shell specific actions, like '&'.
+ // Therefore, we create a file containing the command and make that
+ // the command to launch.
+ launchFile = File.createTempFile(LAUNCH_SCRIPT_NAME, ".sh");
+ launchFile.setExecutable(true);
+ try (FileOutputStream stream = new FileOutputStream(launchFile);
+ BufferedWriter writer =
+ new BufferedWriter(new OutputStreamWriter(stream))) {
+ String cmd = String.format(SIMPLEPERF_APP_CMD, packageName, launchCmd);
+ writer.write(cmd);
+ }
+ launchCmd = launchFile.getAbsolutePath();
+ } catch (IOException e) {
+ Log.w(TAG, "Error writing the launch command", e);
+ return;
+ }
+ } else if (null != mSimplePerfCmd) {
launchCmd = String.format("%s %s", mSimplePerfCmd, launchCmd);
}
Log.v(TAG, "Final launch cmd:" + launchCmd);
ParcelFileDescriptor parcelDesc = getInstrumentation().getUiAutomation()
.executeShellCommand(launchCmd);
- mResult = Long.parseLong(parseLaunchTimeAndWrite(parcelDesc, String.format
- ("App Launch :%s %s",
- componentName, mLaunchReason)), 10);
+ mLaunchResult = parseLaunchTimeAndWrite(parcelDesc, String.format
+ ("App Launch :%s %s", componentName, mLaunchReason));
} catch (RemoteException e) {
Log.w(TAG, "Error launching app", e);
+ } finally {
+ if (launchFile != null) {
+ launchFile.delete();
+ }
}
}
@@ -639,12 +746,14 @@
* @param parcelDesc
* @return
*/
- private String parseLaunchTimeAndWrite(ParcelFileDescriptor parcelDesc, String headerInfo) {
+ private AppLaunchResult parseLaunchTimeAndWrite(ParcelFileDescriptor parcelDesc,
+ String headerInfo) {
String launchTime = "-1";
+ String cpuCycles = "-1";
+ String majorFaults = "-1";
boolean launchSuccess = false;
try {
InputStream inputStream = new FileInputStream(parcelDesc.getFileDescriptor());
- StringBuilder appLaunchOuput = new StringBuilder();
/* SAMPLE OUTPUT :
Starting: Intent { cmp=com.google.android.calculator/com.android.calculator2.Calculator }
Status: ok
@@ -653,6 +762,11 @@
TotalTime: 357
WaitTime: 377
Complete*/
+ /* WITH SIMPLEPERF :
+ Performance counter statistics,
+ 6595722690,cpu-cycles,4.511040,GHz,(100%),
+ 0,major-faults,0.000,/sec,(100%),
+ Total test time,1.462129,seconds,*/
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(
inputStream));
String line = null;
@@ -669,6 +783,23 @@
String launchSplit[] = line.split(":");
launchTime = launchSplit[1].trim();
}
+
+ if (mSimplePerfAppOnly) {
+ // Parse simpleperf output.
+ if (lineCount == 9) {
+ if (!line.contains("cpu-cycles")) {
+ Log.e(TAG, "Error in simpleperf output");
+ } else {
+ cpuCycles = line.split(",")[0].trim();
+ }
+ } else if (lineCount == 10) {
+ if (!line.contains("major-faults")) {
+ Log.e(TAG, "Error in simpleperf output");
+ } else {
+ majorFaults = line.split(",")[0].trim();
+ }
+ }
+ }
mBufferedWriter.write(line);
mBufferedWriter.newLine();
lineCount++;
@@ -678,7 +809,7 @@
} catch (IOException e) {
Log.w(TAG, "Error writing the launch file", e);
}
- return launchTime;
+ return new AppLaunchResult(launchTime, cpuCycles, majorFaults);
}
}
diff --git a/tests/FrameworkPerf/AndroidManifest.xml b/tests/FrameworkPerf/AndroidManifest.xml
index d62ef9e..2591aaf 100644
--- a/tests/FrameworkPerf/AndroidManifest.xml
+++ b/tests/FrameworkPerf/AndroidManifest.xml
@@ -1,6 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.frameworkperf">
- <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-sdk android:minSdkVersion="5" />
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/DrawIntoHwBitmapActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/DrawIntoHwBitmapActivity.java
index faabdfc..af8e10b 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/DrawIntoHwBitmapActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/DrawIntoHwBitmapActivity.java
@@ -27,6 +27,7 @@
import android.graphics.Color;
import android.graphics.GraphicBuffer;
import android.graphics.Paint;
+import android.graphics.Picture;
import android.graphics.PixelFormat;
import android.graphics.SurfaceTexture;
import android.os.Bundle;
@@ -47,10 +48,8 @@
}
Bitmap createBitmap() {
- RenderNode node = RenderNode.create("HwuiCanvas", null);
- node.setLeftTopRightBottom(0, 0, 500, 500);
- node.setClipToBounds(false);
- DisplayListCanvas canvas = node.start(500, 500);
+ Picture picture = new Picture();
+ Canvas canvas = picture.beginRecording(500, 500);
Paint p = new Paint();
p.setColor(Color.BLACK);
p.setTextSize(20 * getResources().getDisplayMetrics().density);
@@ -59,7 +58,7 @@
canvas.drawRect(0, 0, 500, 100, p);
p.setColor(Color.BLACK);
canvas.drawText("Hello, World!", 0, 90, p);
- node.end(canvas);
- return ThreadedRenderer.createHardwareBitmap(node, 500, 500);
+ picture.endRecording();
+ return Bitmap.createBitmap(picture);
}
}
diff --git a/tests/OneMedia/AndroidManifest.xml b/tests/OneMedia/AndroidManifest.xml
index 8697f1b..c6824ec 100644
--- a/tests/OneMedia/AndroidManifest.xml
+++ b/tests/OneMedia/AndroidManifest.xml
@@ -5,7 +5,6 @@
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="19"/>
- <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
diff --git a/tests/net/java/android/net/ConnectivityManagerTest.java b/tests/net/java/android/net/ConnectivityManagerTest.java
index cc792cc..03a617c 100644
--- a/tests/net/java/android/net/ConnectivityManagerTest.java
+++ b/tests/net/java/android/net/ConnectivityManagerTest.java
@@ -38,6 +38,7 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.timeout;
@@ -217,7 +218,8 @@
// callback triggers
captor.getValue().send(makeMessage(request, ConnectivityManager.CALLBACK_AVAILABLE));
- verify(callback, timeout(500).times(1)).onAvailable(any());
+ verify(callback, timeout(500).times(1)).onAvailable(any(Network.class),
+ any(NetworkCapabilities.class), any(LinkProperties.class));
// unregister callback
manager.unregisterNetworkCallback(callback);
@@ -244,7 +246,8 @@
// callback triggers
captor.getValue().send(makeMessage(req1, ConnectivityManager.CALLBACK_AVAILABLE));
- verify(callback, timeout(100).times(1)).onAvailable(any());
+ verify(callback, timeout(100).times(1)).onAvailable(any(Network.class),
+ any(NetworkCapabilities.class), any(LinkProperties.class));
// unregister callback
manager.unregisterNetworkCallback(callback);
@@ -335,6 +338,10 @@
static Message makeMessage(NetworkRequest req, int messageType) {
Bundle bundle = new Bundle();
bundle.putParcelable(NetworkRequest.class.getSimpleName(), req);
+ // Pass default objects as we don't care which get passed here
+ bundle.putParcelable(Network.class.getSimpleName(), new Network(1));
+ bundle.putParcelable(NetworkCapabilities.class.getSimpleName(), new NetworkCapabilities());
+ bundle.putParcelable(LinkProperties.class.getSimpleName(), new LinkProperties());
Message msg = Message.obtain();
msg.what = messageType;
msg.setData(bundle);
diff --git a/tests/net/java/android/net/IpSecConfigTest.java b/tests/net/java/android/net/IpSecConfigTest.java
index f6c5532..f186ee5 100644
--- a/tests/net/java/android/net/IpSecConfigTest.java
+++ b/tests/net/java/android/net/IpSecConfigTest.java
@@ -17,6 +17,7 @@
package android.net;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -48,18 +49,12 @@
assertEquals(IpSecManager.INVALID_RESOURCE_ID, c.getSpiResourceId());
}
- @Test
- public void testParcelUnparcel() throws Exception {
- assertParcelingIsLossless(new IpSecConfig());
-
+ private IpSecConfig getSampleConfig() {
IpSecConfig c = new IpSecConfig();
c.setMode(IpSecTransform.MODE_TUNNEL);
c.setSourceAddress("0.0.0.0");
c.setDestinationAddress("1.2.3.4");
- c.setEncapType(android.system.OsConstants.UDP_ENCAP_ESPINUDP);
- c.setEncapSocketResourceId(7);
- c.setEncapRemotePort(22);
- c.setNattKeepaliveInterval(42);
+ c.setSpiResourceId(1984);
c.setEncryption(
new IpSecAlgorithm(
IpSecAlgorithm.CRYPT_AES_CBC,
@@ -68,7 +63,37 @@
new IpSecAlgorithm(
IpSecAlgorithm.AUTH_HMAC_MD5,
new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0}));
- c.setSpiResourceId(1984);
+ c.setAuthenticatedEncryption(
+ new IpSecAlgorithm(
+ IpSecAlgorithm.AUTH_CRYPT_AES_GCM,
+ new byte[] {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0, 1, 2, 3, 4
+ },
+ 128));
+ c.setEncapType(android.system.OsConstants.UDP_ENCAP_ESPINUDP);
+ c.setEncapSocketResourceId(7);
+ c.setEncapRemotePort(22);
+ c.setNattKeepaliveInterval(42);
+ c.setMarkValue(12);
+ c.setMarkMask(23);
+
+ return c;
+ }
+
+ @Test
+ public void testCopyConstructor() {
+ IpSecConfig original = getSampleConfig();
+ IpSecConfig copy = new IpSecConfig(original);
+
+ assertTrue(IpSecConfig.equals(original, copy));
+ assertFalse(original == copy);
+ }
+
+ @Test
+ public void testParcelUnparcel() throws Exception {
+ assertParcelingIsLossless(new IpSecConfig());
+
+ IpSecConfig c = getSampleConfig();
assertParcelingIsLossless(c);
}
diff --git a/tests/net/java/android/net/IpSecTransformTest.java b/tests/net/java/android/net/IpSecTransformTest.java
new file mode 100644
index 0000000..b4342df
--- /dev/null
+++ b/tests/net/java/android/net/IpSecTransformTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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.net;
+
+import static org.junit.Assert.assertFalse;
+
+import android.support.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Unit tests for {@link IpSecTransform}. */
+@SmallTest
+@RunWith(JUnit4.class)
+public class IpSecTransformTest {
+
+ @Test
+ public void testCreateTransformCopiesConfig() {
+ // Create a config with a few parameters to make sure it's not empty
+ IpSecConfig config = new IpSecConfig();
+ config.setSourceAddress("0.0.0.0");
+ config.setDestinationAddress("1.2.3.4");
+ config.setSpiResourceId(1984);
+
+ IpSecTransform preModification = new IpSecTransform(null, config);
+
+ config.setSpiResourceId(1985);
+ IpSecTransform postModification = new IpSecTransform(null, config);
+
+ assertFalse(IpSecTransform.equals(preModification, postModification));
+ }
+
+ @Test
+ public void testCreateTransformsWithSameConfigEqual() {
+ // Create a config with a few parameters to make sure it's not empty
+ IpSecConfig config = new IpSecConfig();
+ config.setSourceAddress("0.0.0.0");
+ config.setDestinationAddress("1.2.3.4");
+ config.setSpiResourceId(1984);
+
+ IpSecTransform config1 = new IpSecTransform(null, config);
+ IpSecTransform config2 = new IpSecTransform(null, config);
+
+ assertFalse(IpSecTransform.equals(config1, config2));
+ }
+}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index e7abede..24639e9 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -35,6 +35,7 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_RCS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_SUPL;
@@ -528,6 +529,11 @@
mNetworkAgent.sendNetworkInfo(mNetworkInfo);
}
+ public void resume() {
+ mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
+ mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+ }
+
public void disconnect() {
mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
mNetworkAgent.sendNetworkInfo(mNetworkInfo);
@@ -569,6 +575,10 @@
assertTrue(mNetworkStatusReceived.block(TIMEOUT_MS));
return mRedirectUrl;
}
+
+ public NetworkCapabilities getNetworkCapabilities() {
+ return mNetworkCapabilities;
+ }
}
/**
@@ -1273,6 +1283,7 @@
NETWORK_CAPABILITIES,
LINK_PROPERTIES,
SUSPENDED,
+ RESUMED,
LOSING,
LOST,
UNAVAILABLE
@@ -1344,6 +1355,11 @@
}
@Override
+ public void onNetworkResumed(Network network) {
+ setLastCallback(CallbackState.RESUMED, network, null);
+ }
+
+ @Override
public void onLosing(Network network, int maxMsToLive) {
setLastCallback(CallbackState.LOSING, network, maxMsToLive /* autoboxed int */);
}
@@ -2459,16 +2475,31 @@
// Suspend the network.
mCellNetworkAgent.suspend();
+ cellNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_SUSPENDED,
+ mCellNetworkAgent);
cellNetworkCallback.expectCallback(CallbackState.SUSPENDED, mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
// Register a garden variety default network request.
- final TestNetworkCallback dfltNetworkCallback = new TestNetworkCallback();
+ TestNetworkCallback dfltNetworkCallback = new TestNetworkCallback();
mCm.registerDefaultNetworkCallback(dfltNetworkCallback);
// We should get onAvailable(), onCapabilitiesChanged(), onLinkPropertiesChanged(),
// as well as onNetworkSuspended() in rapid succession.
dfltNetworkCallback.expectAvailableAndSuspendedCallbacks(mCellNetworkAgent, true);
dfltNetworkCallback.assertNoCallback();
+ mCm.unregisterNetworkCallback(dfltNetworkCallback);
+
+ mCellNetworkAgent.resume();
+ cellNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_SUSPENDED,
+ mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackState.RESUMED, mCellNetworkAgent);
+ cellNetworkCallback.assertNoCallback();
+
+ dfltNetworkCallback = new TestNetworkCallback();
+ mCm.registerDefaultNetworkCallback(dfltNetworkCallback);
+ // This time onNetworkSuspended should not be called.
+ dfltNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
+ dfltNetworkCallback.assertNoCallback();
mCm.unregisterNetworkCallback(dfltNetworkCallback);
mCm.unregisterNetworkCallback(cellNetworkCallback);
@@ -3682,8 +3713,7 @@
vpnNetworkCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent);
genericNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent);
- vpnNetworkCallback.expectCapabilitiesLike(
- nc -> nc.appliesToUid(uid) && !nc.appliesToUid(uid + 1), vpnNetworkAgent);
+ vpnNetworkCallback.expectCapabilitiesLike(nc -> null == nc.getUids(), vpnNetworkAgent);
ranges.clear();
vpnNetworkAgent.setUids(ranges);
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index 5831875..f064cb1 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -414,59 +414,78 @@
public:
using xml::ConstVisitor::Visit;
+ XmlPrinter(Printer* printer) : printer_(printer) {
+ }
+
void Visit(const xml::Element* el) override {
- const size_t previous_size = prefix_.size();
-
for (const xml::NamespaceDecl& decl : el->namespace_decls) {
- std::cerr << prefix_ << "N: " << decl.prefix << "=" << decl.uri
- << " (line=" << decl.line_number << ")\n";
- prefix_ += " ";
+ printer_->Println(StringPrintf("N: %s=%s (line=%zu)", decl.prefix.c_str(), decl.uri.c_str(),
+ decl.line_number));
+ printer_->Indent();
}
- std::cerr << prefix_ << "E: ";
+ printer_->Print("E: ");
if (!el->namespace_uri.empty()) {
- std::cerr << el->namespace_uri << ":";
+ printer_->Print(el->namespace_uri);
+ printer_->Print(":");
}
- std::cerr << el->name << " (line=" << el->line_number << ")\n";
+ printer_->Println(StringPrintf("%s (line=%zu)", el->name.c_str(), el->line_number));
+ printer_->Indent();
for (const xml::Attribute& attr : el->attributes) {
- std::cerr << prefix_ << " A: ";
+ printer_->Print("A: ");
if (!attr.namespace_uri.empty()) {
- std::cerr << attr.namespace_uri << ":";
+ printer_->Print(attr.namespace_uri);
+ printer_->Print(":");
}
- std::cerr << attr.name;
+ printer_->Print(attr.name);
if (attr.compiled_attribute) {
- std::cerr << "(" << attr.compiled_attribute.value().id.value_or_default(ResourceId(0x0))
- << ")";
+ printer_->Print("(");
+ printer_->Print(
+ attr.compiled_attribute.value().id.value_or_default(ResourceId(0)).to_string());
+ printer_->Print(")");
}
- std::cerr << "=";
+ printer_->Print("=");
if (attr.compiled_value != nullptr) {
- std::cerr << *attr.compiled_value;
+ attr.compiled_value->PrettyPrint(printer_);
} else {
- std::cerr << attr.value;
+ printer_->Print("\"");
+ printer_->Print(attr.value);
+ printer_->Print("\"");
}
- std::cerr << "\n";
+
+ if (!attr.value.empty()) {
+ printer_->Print(" (Raw: \"");
+ printer_->Print(attr.value);
+ printer_->Print("\")");
+ }
+ printer_->Println();
}
- prefix_ += " ";
+ printer_->Indent();
xml::ConstVisitor::Visit(el);
- prefix_.resize(previous_size);
+ printer_->Undent();
+ printer_->Undent();
+
+ for (size_t i = 0; i < el->namespace_decls.size(); i++) {
+ printer_->Undent();
+ }
}
void Visit(const xml::Text* text) override {
- std::cerr << prefix_ << "T: '" << text->text << "'\n";
+ printer_->Println(StringPrintf("T: '%s'", text->text.c_str()));
}
private:
- std::string prefix_;
+ Printer* printer_;
};
} // namespace
-void Debug::DumpXml(const xml::XmlResource& doc) {
- XmlPrinter printer;
- doc.root->Accept(&printer);
+void Debug::DumpXml(const xml::XmlResource& doc, Printer* printer) {
+ XmlPrinter xml_visitor(printer);
+ doc.root->Accept(&xml_visitor);
}
} // namespace aapt
diff --git a/tools/aapt2/Debug.h b/tools/aapt2/Debug.h
index 6209a04..382707e 100644
--- a/tools/aapt2/Debug.h
+++ b/tools/aapt2/Debug.h
@@ -37,7 +37,7 @@
text::Printer* printer);
static void PrintStyleGraph(ResourceTable* table, const ResourceName& target_style);
static void DumpHex(const void* data, size_t len);
- static void DumpXml(const xml::XmlResource& doc);
+ static void DumpXml(const xml::XmlResource& doc, text::Printer* printer);
};
} // namespace aapt
diff --git a/tools/aapt2/LoadedApk.cpp b/tools/aapt2/LoadedApk.cpp
index 20a9f41..ac28227 100644
--- a/tools/aapt2/LoadedApk.cpp
+++ b/tools/aapt2/LoadedApk.cpp
@@ -222,7 +222,9 @@
} else if (manifest != nullptr && path == "AndroidManifest.xml") {
BigBuffer buffer(8192);
- XmlFlattener xml_flattener(&buffer, {});
+ XmlFlattenerOptions xml_flattener_options;
+ xml_flattener_options.use_utf16 = true;
+ XmlFlattener xml_flattener(&buffer, xml_flattener_options);
if (!xml_flattener.Consume(context, manifest)) {
context->GetDiagnostics()->Error(DiagMessage(path) << "flattening failed");
return false;
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index 02ac86c..628466d 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -520,6 +520,10 @@
return util::make_unique<BinaryPrimitive>(value);
}
+std::unique_ptr<BinaryPrimitive> MakeInt(uint32_t val) {
+ return util::make_unique<BinaryPrimitive>(android::Res_value::TYPE_INT_DEC, val);
+}
+
std::unique_ptr<BinaryPrimitive> TryParseFloat(const StringPiece& str) {
std::u16string str16 = util::Utf8ToUtf16(util::TrimWhitespace(str));
android::Res_value value;
diff --git a/tools/aapt2/ResourceUtils.h b/tools/aapt2/ResourceUtils.h
index 36f6c2b..f83d49e 100644
--- a/tools/aapt2/ResourceUtils.h
+++ b/tools/aapt2/ResourceUtils.h
@@ -165,6 +165,9 @@
*/
std::unique_ptr<BinaryPrimitive> TryParseInt(const android::StringPiece& str);
+// Returns an integer BinaryPrimitive.
+std::unique_ptr<BinaryPrimitive> MakeInt(uint32_t value);
+
/*
* Returns a BinaryPrimitve object representing a floating point number
* (float, dimension, etc) if the string was parsed as one.
diff --git a/tools/aapt2/cmd/Convert.cpp b/tools/aapt2/cmd/Convert.cpp
index d80307c..7f956c5 100644
--- a/tools/aapt2/cmd/Convert.cpp
+++ b/tools/aapt2/cmd/Convert.cpp
@@ -139,6 +139,7 @@
BigBuffer buffer(4096);
XmlFlattenerOptions options = {};
options.use_utf16 = utf16;
+ options.keep_raw_values = true;
XmlFlattener flattener(&buffer, options);
if (!flattener.Consume(context_, xml)) {
return false;
diff --git a/tools/aapt2/cmd/Dump.cpp b/tools/aapt2/cmd/Dump.cpp
index 3d2fb55..8e7e5e5 100644
--- a/tools/aapt2/cmd/Dump.cpp
+++ b/tools/aapt2/cmd/Dump.cpp
@@ -38,6 +38,13 @@
namespace aapt {
+struct DumpOptions {
+ DebugPrintTableOptions print_options;
+
+ // The path to a file within an APK to dump.
+ Maybe<std::string> file_to_dump_path;
+};
+
static const char* ResourceFileTypeToString(const ResourceFile::Type& type) {
switch (type) {
case ResourceFile::Type::kPng:
@@ -69,8 +76,52 @@
printer->Println(StringPrintf("Data: offset=%" PRIi64 " length=%zd", offset, len));
}
+static bool DumpXmlFile(IAaptContext* context, io::IFile* file, bool proto,
+ text::Printer* printer) {
+ std::unique_ptr<xml::XmlResource> doc;
+ if (proto) {
+ std::unique_ptr<io::InputStream> in = file->OpenInputStream();
+ if (in == nullptr) {
+ context->GetDiagnostics()->Error(DiagMessage() << "failed to open file");
+ return false;
+ }
+
+ io::ZeroCopyInputAdaptor adaptor(in.get());
+ pb::XmlNode pb_node;
+ if (!pb_node.ParseFromZeroCopyStream(&adaptor)) {
+ context->GetDiagnostics()->Error(DiagMessage() << "failed to parse file as proto XML");
+ return false;
+ }
+
+ std::string err;
+ doc = DeserializeXmlResourceFromPb(pb_node, &err);
+ if (doc == nullptr) {
+ context->GetDiagnostics()->Error(DiagMessage() << "failed to deserialize proto XML");
+ return false;
+ }
+ printer->Println("Proto XML");
+ } else {
+ std::unique_ptr<io::IData> data = file->OpenAsData();
+ if (data == nullptr) {
+ context->GetDiagnostics()->Error(DiagMessage() << "failed to open file");
+ return false;
+ }
+
+ std::string err;
+ doc = xml::Inflate(data->data(), data->size(), &err);
+ if (doc == nullptr) {
+ context->GetDiagnostics()->Error(DiagMessage() << "failed to parse file as binary XML");
+ return false;
+ }
+ printer->Println("Binary XML");
+ }
+
+ Debug::DumpXml(*doc, printer);
+ return true;
+}
+
static bool TryDumpFile(IAaptContext* context, const std::string& file_path,
- const DebugPrintTableOptions& print_options) {
+ const DumpOptions& options) {
// Use a smaller buffer so that there is less latency for dumping to stdout.
constexpr size_t kStdOutBufferSize = 1024u;
io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
@@ -80,7 +131,10 @@
std::unique_ptr<io::ZipFileCollection> zip = io::ZipFileCollection::Create(file_path, &err);
if (zip) {
ResourceTable table;
+ bool proto = false;
if (io::IFile* file = zip->FindFile("resources.pb")) {
+ proto = true;
+
std::unique_ptr<io::IData> data = file->OpenAsData();
if (data == nullptr) {
context->GetDiagnostics()->Error(DiagMessage(file_path) << "failed to open resources.pb");
@@ -98,8 +152,6 @@
<< "failed to parse table: " << err);
return false;
}
-
- printer.Println("Proto APK");
} else if (io::IFile* file = zip->FindFile("resources.arsc")) {
std::unique_ptr<io::IData> data = file->OpenAsData();
if (!data) {
@@ -112,12 +164,26 @@
if (!parser.Parse()) {
return false;
}
-
- printer.Println("Binary APK");
}
- Debug::PrintTable(table, print_options, &printer);
- return true;
+ if (!options.file_to_dump_path) {
+ if (proto) {
+ printer.Println("Proto APK");
+ } else {
+ printer.Println("Binary APK");
+ }
+ Debug::PrintTable(table, options.print_options, &printer);
+ return true;
+ }
+
+ io::IFile* file = zip->FindFile(options.file_to_dump_path.value());
+ if (file == nullptr) {
+ context->GetDiagnostics()->Error(DiagMessage(file_path)
+ << "file '" << options.file_to_dump_path.value()
+ << "' not found in APK");
+ return false;
+ }
+ return DumpXmlFile(context, file, proto, &printer);
}
err.clear();
@@ -159,7 +225,7 @@
}
printer.Indent();
- Debug::PrintTable(table, print_options, &printer);
+ Debug::PrintTable(table, options.print_options, &printer);
printer.Undent();
} else if (entry->Type() == ContainerEntryType::kResFile) {
printer.Println("kResFile");
@@ -243,10 +309,13 @@
int Dump(const std::vector<StringPiece>& args) {
bool verbose = false;
bool no_values = false;
+ DumpOptions options;
Flags flags = Flags()
.OptionalSwitch("--no-values",
"Suppresses output of values when displaying resource tables.",
&no_values)
+ .OptionalFlag("--file", "Dumps the specified file from the APK passed as arg.",
+ &options.file_to_dump_path)
.OptionalSwitch("-v", "increase verbosity of output", &verbose);
if (!flags.Parse("aapt2 dump", args, &std::cerr)) {
return 1;
@@ -255,11 +324,10 @@
DumpContext context;
context.SetVerbose(verbose);
- DebugPrintTableOptions dump_table_options;
- dump_table_options.show_sources = true;
- dump_table_options.show_values = !no_values;
+ options.print_options.show_sources = true;
+ options.print_options.show_values = !no_values;
for (const std::string& arg : flags.GetArgs()) {
- if (!TryDumpFile(&context, arg, dump_table_options)) {
+ if (!TryDumpFile(&context, arg, options)) {
return 1;
}
}
diff --git a/tools/aapt2/configuration/ConfigurationParser.cpp b/tools/aapt2/configuration/ConfigurationParser.cpp
index eabeb47..902334b 100644
--- a/tools/aapt2/configuration/ConfigurationParser.cpp
+++ b/tools/aapt2/configuration/ConfigurationParser.cpp
@@ -20,6 +20,7 @@
#include <functional>
#include <map>
#include <memory>
+#include <string>
#include <utility>
#include "android-base/file.h"
@@ -93,6 +94,7 @@
};
NoopDiagnostics noop_;
+/** Returns the value of the label attribute for a given element. */
std::string GetLabel(const Element* element, IDiagnostics* diag) {
std::string label;
for (const auto& attr : element->attributes) {
@@ -108,6 +110,18 @@
return label;
}
+/** Returns the value of the version-code-order attribute for a given element. */
+Maybe<int32_t> GetVersionCodeOrder(const Element* element, IDiagnostics* diag) {
+ const xml::Attribute* version = element->FindAttribute("", "version-code-order");
+ if (version == nullptr) {
+ std::string label = GetLabel(element, diag);
+ diag->Error(DiagMessage() << "No version-code-order found for element '" << element->name
+ << "' with label '" << label << "'");
+ return {};
+ }
+ return std::stoi(version->value);
+}
+
/** XML node visitor that removes all of the namespace URIs from the node and all children. */
class NamespaceVisitor : public xml::Visitor {
public:
@@ -437,26 +451,37 @@
// Convert from a parsed configuration to a list of artifacts for processing.
const std::string& apk_name = file::GetFilename(apk_path).to_string();
std::vector<OutputArtifact> output_artifacts;
- bool has_errors = false;
PostProcessingConfiguration& config = maybe_config.value();
- config.SortArtifacts();
+ bool valid = true;
int version = 1;
+
for (const ConfiguredArtifact& artifact : config.artifacts) {
Maybe<OutputArtifact> output_artifact = ToOutputArtifact(artifact, apk_name, config, diag_);
if (!output_artifact) {
// Defer return an error condition so that all errors are reported.
- has_errors = true;
+ valid = false;
} else {
output_artifact.value().version = version++;
output_artifacts.push_back(std::move(output_artifact.value()));
}
}
- if (has_errors) {
+ if (!config.ValidateVersionCodeOrdering(diag_)) {
+ diag_->Error(DiagMessage() << "could not validate post processing configuration");
+ valid = false;
+ }
+
+ if (valid) {
+ // Sorting artifacts requires that all references are valid as it uses them to determine order.
+ config.SortArtifacts();
+ }
+
+ if (!valid) {
return {};
}
+
return {output_artifacts};
}
@@ -509,8 +534,15 @@
return false;
}
- auto& group = GetOrCreateGroup(label, &config->abi_groups);
bool valid = true;
+ OrderedEntry<Abi>& entry = config->abi_groups[label];
+ Maybe<int32_t> order = GetVersionCodeOrder(root_element, diag);
+ if (!order) {
+ valid = false;
+ } else {
+ entry.order = order.value();
+ }
+ auto& group = entry.entry;
// Special case for empty abi-group tag. Label will be used as the ABI.
if (root_element->GetChildElements().empty()) {
@@ -519,7 +551,7 @@
return false;
}
group.push_back(abi->second);
- return true;
+ return valid;
}
for (auto* child : root_element->GetChildElements()) {
@@ -553,8 +585,15 @@
return false;
}
- auto& group = GetOrCreateGroup(label, &config->screen_density_groups);
bool valid = true;
+ OrderedEntry<ConfigDescription>& entry = config->screen_density_groups[label];
+ Maybe<int32_t> order = GetVersionCodeOrder(root_element, diag);
+ if (!order) {
+ valid = false;
+ } else {
+ entry.order = order.value();
+ }
+ auto& group = entry.entry;
// Special case for empty screen-density-group tag. Label will be used as the screen density.
if (root_element->GetChildElements().empty()) {
@@ -613,8 +652,15 @@
return false;
}
- auto& group = GetOrCreateGroup(label, &config->locale_groups);
bool valid = true;
+ OrderedEntry<ConfigDescription>& entry = config->locale_groups[label];
+ Maybe<int32_t> order = GetVersionCodeOrder(root_element, diag);
+ if (!order) {
+ valid = false;
+ } else {
+ entry.order = order.value();
+ }
+ auto& group = entry.entry;
// Special case to auto insert a locale for an empty group. Label will be used for locale.
if (root_element->GetChildElements().empty()) {
@@ -728,8 +774,15 @@
return false;
}
- auto& group = GetOrCreateGroup(label, &config->gl_texture_groups);
bool valid = true;
+ OrderedEntry<GlTexture>& entry = config->gl_texture_groups[label];
+ Maybe<int32_t> order = GetVersionCodeOrder(root_element, diag);
+ if (!order) {
+ valid = false;
+ } else {
+ entry.order = order.value();
+ }
+ auto& group = entry.entry;
GlTexture result;
for (auto* child : root_element->GetChildElements()) {
@@ -771,8 +824,15 @@
return false;
}
- auto& group = GetOrCreateGroup(label, &config->device_feature_groups);
bool valid = true;
+ OrderedEntry<DeviceFeature>& entry = config->device_feature_groups[label];
+ Maybe<int32_t> order = GetVersionCodeOrder(root_element, diag);
+ if (!order) {
+ valid = false;
+ } else {
+ entry.order = order.value();
+ }
+ auto& group = entry.entry;
for (auto* child : root_element->GetChildElements()) {
if (child->name != "supports-feature") {
diff --git a/tools/aapt2/configuration/ConfigurationParser.internal.h b/tools/aapt2/configuration/ConfigurationParser.internal.h
index a583057..f071a69 100644
--- a/tools/aapt2/configuration/ConfigurationParser.internal.h
+++ b/tools/aapt2/configuration/ConfigurationParser.internal.h
@@ -33,18 +33,31 @@
template <typename T>
struct OrderedEntry {
- size_t order;
+ int32_t order;
std::vector<T> entry;
};
-/** A mapping of group labels to group of configuration items. */
-template <class T>
-using Group = std::unordered_map<std::string, OrderedEntry<T>>;
-
/** A mapping of group label to a single configuration item. */
template <class T>
using Entry = std::unordered_map<std::string, T>;
+/** A mapping of group labels to group of configuration items. */
+template <class T>
+using Group = Entry<OrderedEntry<T>>;
+
+template<typename T>
+bool IsGroupValid(const Group<T>& group, const std::string& name, IDiagnostics* diag) {
+ std::set<int32_t> orders;
+ for (const auto& p : group) {
+ orders.insert(p.second.order);
+ }
+ bool valid = orders.size() == group.size();
+ if (!valid) {
+ diag->Error(DiagMessage() << name << " have overlapping version-code-order attributes");
+ }
+ return valid;
+}
+
/** Retrieves an entry from the provided Group, creating a new instance if one does not exist. */
template <typename T>
std::vector<T>& GetOrCreateGroup(std::string label, Group<T>* group) {
@@ -93,7 +106,7 @@
private:
template <typename T>
- inline size_t GetGroupOrder(const Group<T>& groups, const Maybe<std::string>& label) {
+ inline size_t GetGroupOrder(const Entry<T>& groups, const Maybe<std::string>& label) {
if (!label) {
return std::numeric_limits<size_t>::max();
}
@@ -141,6 +154,15 @@
Group<GlTexture> gl_texture_groups;
Entry<AndroidSdk> android_sdks;
+ bool ValidateVersionCodeOrdering(IDiagnostics* diag) {
+ bool valid = IsGroupValid(abi_groups, "abi-groups", diag);
+ valid &= IsGroupValid(screen_density_groups, "screen-density-groups", diag);
+ valid &= IsGroupValid(locale_groups, "locale-groups", diag);
+ valid &= IsGroupValid(device_feature_groups, "device-feature-groups", diag);
+ valid &= IsGroupValid(gl_texture_groups, "gl-texture-groups", diag);
+ return valid;
+ }
+
/**
* Sorts the configured artifacts based on the ordering of the groups in the configuration file.
* The only exception to this rule is Android SDK versions. Larger SDK versions will have a larger
diff --git a/tools/aapt2/configuration/ConfigurationParser_test.cpp b/tools/aapt2/configuration/ConfigurationParser_test.cpp
index 0329846..febbb2e 100644
--- a/tools/aapt2/configuration/ConfigurationParser_test.cpp
+++ b/tools/aapt2/configuration/ConfigurationParser_test.cpp
@@ -82,22 +82,22 @@
constexpr const char* kValidConfig = R"(<?xml version="1.0" encoding="utf-8" ?>
<post-process xmlns="http://schemas.android.com/tools/aapt">
<abi-groups>
- <abi-group label="arm">
- <abi>armeabi-v7a</abi>
- <abi>arm64-v8a</abi>
- </abi-group>
- <abi-group label="other">
+ <abi-group label="other" version-code-order="2">
<abi>x86</abi>
<abi>mips</abi>
</abi-group>
+ <abi-group label="arm" version-code-order="1">
+ <abi>armeabi-v7a</abi>
+ <abi>arm64-v8a</abi>
+ </abi-group>
</abi-groups>
<screen-density-groups>
- <screen-density-group label="large">
+ <screen-density-group label="large" version-code-order="2">
<screen-density>xhdpi</screen-density>
<screen-density>xxhdpi</screen-density>
<screen-density>xxxhdpi</screen-density>
</screen-density-group>
- <screen-density-group label="alldpi">
+ <screen-density-group label="alldpi" version-code-order="1">
<screen-density>ldpi</screen-density>
<screen-density>mdpi</screen-density>
<screen-density>hdpi</screen-density>
@@ -107,17 +107,20 @@
</screen-density-group>
</screen-density-groups>
<locale-groups>
- <locale-group label="europe">
+ <locale-group label="europe" version-code-order="1">
<locale>en</locale>
<locale>es</locale>
<locale>fr</locale>
<locale>de</locale>
</locale-group>
- <locale-group label="north-america">
+ <locale-group label="north-america" version-code-order="2">
<locale>en</locale>
<locale>es-rMX</locale>
<locale>fr-rCA</locale>
</locale-group>
+ <locale-group label="all" version-code-order="-1">
+ <locale />
+ </locale-group>
</locale-groups>
<android-sdks>
<android-sdk
@@ -131,14 +134,14 @@
</android-sdk>
</android-sdks>
<gl-texture-groups>
- <gl-texture-group label="dxt1">
+ <gl-texture-group label="dxt1" version-code-order="2">
<gl-texture name="GL_EXT_texture_compression_dxt1">
<texture-path>assets/dxt1/*</texture-path>
</gl-texture>
</gl-texture-group>
</gl-texture-groups>
<device-feature-groups>
- <device-feature-group label="low-latency">
+ <device-feature-group label="low-latency" version-code-order="2">
<supports-feature>android.hardware.audio.low_latency</supports-feature>
</device-feature-group>
</device-feature-groups>
@@ -188,19 +191,22 @@
auto& arm = config.abi_groups["arm"];
auto& other = config.abi_groups["other"];
- EXPECT_EQ(arm.order, 1ul);
- EXPECT_EQ(other.order, 2ul);
+ EXPECT_EQ(arm.order, 1);
+ EXPECT_EQ(other.order, 2);
auto& large = config.screen_density_groups["large"];
auto& alldpi = config.screen_density_groups["alldpi"];
- EXPECT_EQ(large.order, 1ul);
- EXPECT_EQ(alldpi.order, 2ul);
+ EXPECT_EQ(large.order, 2);
+ EXPECT_EQ(alldpi.order, 1);
auto& north_america = config.locale_groups["north-america"];
auto& europe = config.locale_groups["europe"];
+ auto& all = config.locale_groups["all"];
// Checked in reverse to make sure access order does not matter.
- EXPECT_EQ(north_america.order, 2ul);
- EXPECT_EQ(europe.order, 1ul);
+ EXPECT_EQ(north_america.order, 2);
+ EXPECT_EQ(europe.order, 1);
+ EXPECT_EQ(all.order, -1);
+ EXPECT_EQ(3ul, config.locale_groups.size());
}
TEST_F(ConfigurationParserTest, ValidateFile) {
@@ -392,7 +398,7 @@
TEST_F(ConfigurationParserTest, AbiGroupAction) {
static constexpr const char* xml = R"xml(
- <abi-group label="arm">
+ <abi-group label="arm" version-code-order="2">
<!-- First comment. -->
<abi>
armeabi-v7a
@@ -415,7 +421,8 @@
}
TEST_F(ConfigurationParserTest, AbiGroupAction_EmptyGroup) {
- static constexpr const char* xml = R"xml(<abi-group label="arm64-v8a"/>)xml";
+ static constexpr const char* xml =
+ R"xml(<abi-group label="arm64-v8a" version-code-order="3"/>)xml";
auto doc = test::BuildXmlDom(xml);
@@ -426,12 +433,23 @@
EXPECT_THAT(config.abi_groups, SizeIs(1ul));
ASSERT_EQ(1u, config.abi_groups.count("arm64-v8a"));
- auto& out = config.abi_groups["arm64-v8a"].entry;
- ASSERT_THAT(out, ElementsAre(Abi::kArm64V8a));
+ auto& out = config.abi_groups["arm64-v8a"];
+ ASSERT_THAT(out.entry, ElementsAre(Abi::kArm64V8a));
+ EXPECT_EQ(3, out.order);
+}
+
+TEST_F(ConfigurationParserTest, AbiGroupAction_EmptyGroup_NoOrder) {
+ static constexpr const char* xml = R"xml(<abi-group label="arm64-v8a"/>)xml";
+
+ auto doc = test::BuildXmlDom(xml);
+
+ PostProcessingConfiguration config;
+ bool ok = AbiGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
+ ASSERT_FALSE(ok);
}
TEST_F(ConfigurationParserTest, AbiGroupAction_InvalidEmptyGroup) {
- static constexpr const char* xml = R"xml(<abi-group label="arm"/>)xml";
+ static constexpr const char* xml = R"xml(<abi-group label="arm" order="2"/>)xml";
auto doc = test::BuildXmlDom(xml);
@@ -442,7 +460,7 @@
TEST_F(ConfigurationParserTest, ScreenDensityGroupAction) {
static constexpr const char* xml = R"xml(
- <screen-density-group label="large">
+ <screen-density-group label="large" version-code-order="2">
<screen-density>xhdpi</screen-density>
<screen-density>
xxhdpi
@@ -471,7 +489,8 @@
}
TEST_F(ConfigurationParserTest, ScreenDensityGroupAction_EmtpyGroup) {
- static constexpr const char* xml = R"xml(<screen-density-group label="xhdpi"/>)xml";
+ static constexpr const char* xml =
+ R"xml(<screen-density-group label="xhdpi" version-code-order="4"/>)xml";
auto doc = test::BuildXmlDom(xml);
@@ -485,8 +504,19 @@
ConfigDescription xhdpi;
xhdpi.density = ResTable_config::DENSITY_XHIGH;
- auto& out = config.screen_density_groups["xhdpi"].entry;
- ASSERT_THAT(out, ElementsAre(xhdpi));
+ auto& out = config.screen_density_groups["xhdpi"];
+ EXPECT_THAT(out.entry, ElementsAre(xhdpi));
+ EXPECT_EQ(4, out.order);
+}
+
+TEST_F(ConfigurationParserTest, ScreenDensityGroupAction_EmtpyGroup_NoVersion) {
+ static constexpr const char* xml = R"xml(<screen-density-group label="xhdpi"/>)xml";
+
+ auto doc = test::BuildXmlDom(xml);
+
+ PostProcessingConfiguration config;
+ bool ok = ScreenDensityGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
+ ASSERT_FALSE(ok);
}
TEST_F(ConfigurationParserTest, ScreenDensityGroupAction_InvalidEmtpyGroup) {
@@ -501,7 +531,7 @@
TEST_F(ConfigurationParserTest, LocaleGroupAction) {
static constexpr const char* xml = R"xml(
- <locale-group label="europe">
+ <locale-group label="europe" version-code-order="2">
<locale>en</locale>
<locale>es</locale>
<locale>fr</locale>
@@ -528,7 +558,7 @@
}
TEST_F(ConfigurationParserTest, LocaleGroupAction_EmtpyGroup) {
- static constexpr const char* xml = R"xml(<locale-group label="en"/>)xml";
+ static constexpr const char* xml = R"xml(<locale-group label="en" version-code-order="6"/>)xml";
auto doc = test::BuildXmlDom(xml);
@@ -539,11 +569,22 @@
ASSERT_EQ(1ul, config.locale_groups.size());
ASSERT_EQ(1u, config.locale_groups.count("en"));
- const auto& out = config.locale_groups["en"].entry;
+ const auto& out = config.locale_groups["en"];
ConfigDescription en = test::ParseConfigOrDie("en");
- ASSERT_THAT(out, ElementsAre(en));
+ EXPECT_THAT(out.entry, ElementsAre(en));
+ EXPECT_EQ(6, out.order);
+}
+
+TEST_F(ConfigurationParserTest, LocaleGroupAction_EmtpyGroup_NoOrder) {
+ static constexpr const char* xml = R"xml(<locale-group label="en"/>)xml";
+
+ auto doc = test::BuildXmlDom(xml);
+
+ PostProcessingConfiguration config;
+ bool ok = LocaleGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
+ ASSERT_FALSE(ok);
}
TEST_F(ConfigurationParserTest, LocaleGroupAction_InvalidEmtpyGroup) {
@@ -695,7 +736,7 @@
TEST_F(ConfigurationParserTest, GlTextureGroupAction) {
static constexpr const char* xml = R"xml(
- <gl-texture-group label="dxt1">
+ <gl-texture-group label="dxt1" version-code-order="2">
<gl-texture name="GL_EXT_texture_compression_dxt1">
<texture-path>assets/dxt1/main/*</texture-path>
<texture-path>
@@ -726,7 +767,7 @@
TEST_F(ConfigurationParserTest, DeviceFeatureGroupAction) {
static constexpr const char* xml = R"xml(
- <device-feature-group label="low-latency">
+ <device-feature-group label="low-latency" version-code-order="2">
<supports-feature>android.hardware.audio.low_latency</supports-feature>
<supports-feature>
android.hardware.audio.pro
@@ -749,6 +790,30 @@
ASSERT_THAT(out, ElementsAre(low_latency, pro));
}
+TEST_F(ConfigurationParserTest, Group_Valid) {
+ Group<int32_t> group;
+ group["item1"].order = 1;
+ group["item2"].order = 2;
+ group["item3"].order = 3;
+ group["item4"].order = 4;
+ group["item5"].order = 5;
+ group["item6"].order = 6;
+
+ EXPECT_TRUE(IsGroupValid(group, "test", &diag_));
+}
+
+TEST_F(ConfigurationParserTest, Group_OverlappingOrder) {
+ Group<int32_t> group;
+ group["item1"].order = 1;
+ group["item2"].order = 2;
+ group["item3"].order = 3;
+ group["item4"].order = 2;
+ group["item5"].order = 5;
+ group["item6"].order = 1;
+
+ EXPECT_FALSE(IsGroupValid(group, "test", &diag_));
+}
+
// Artifact name parser test cases.
TEST(ArtifactTest, Simple) {
diff --git a/tools/aapt2/configuration/aapt2.xsd b/tools/aapt2/configuration/aapt2.xsd
index fb2f49b..a28e28b 100644
--- a/tools/aapt2/configuration/aapt2.xsd
+++ b/tools/aapt2/configuration/aapt2.xsd
@@ -81,6 +81,7 @@
<xsd:element name="gl-texture" type="gl-texture" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="label" type="xsd:string"/>
+ <xsd:attribute name="version-code-order" type="xsd:unsignedInt" use="required"/>
</xsd:complexType>
<xsd:complexType name="gl-texture">
@@ -95,6 +96,7 @@
<xsd:element name="supports-feature" type="xsd:string" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="label" type="xsd:string"/>
+ <xsd:attribute name="version-code-order" type="xsd:unsignedInt" use="required"/>
</xsd:complexType>
<xsd:complexType name="abi-group">
@@ -102,6 +104,7 @@
<xsd:element name="abi" type="abi-name" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="label" type="xsd:string"/>
+ <xsd:attribute name="version-code-order" type="xsd:unsignedInt" use="required"/>
</xsd:complexType>
<xsd:simpleType name="abi-name">
@@ -122,6 +125,7 @@
<xsd:element name="screen-density" type="screen-density" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="label" type="xsd:string"/>
+ <xsd:attribute name="version-code-order" type="xsd:unsignedInt" use="required"/>
</xsd:complexType>
<xsd:simpleType name="screen-density">
@@ -158,6 +162,7 @@
<xsd:element name="locale" type="locale" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="label" type="xsd:string"/>
+ <xsd:attribute name="version-code-order" type="xsd:unsignedInt" use="required"/>
</xsd:complexType>
<xsd:complexType name="locale">
diff --git a/tools/aapt2/configuration/example/config.xml b/tools/aapt2/configuration/example/config.xml
index d8aba09..e6db2a0 100644
--- a/tools/aapt2/configuration/example/config.xml
+++ b/tools/aapt2/configuration/example/config.xml
@@ -36,25 +36,19 @@
</android-sdks>
<abi-groups>
- <abi-group label="arm">
+ <abi-group label="arm" version-code-order="1">
<abi>armeabi-v7a</abi>
<abi>arm64-v8a</abi>
</abi-group>
- <abi-group label="other">
+ <abi-group label="other" version-code-order="2">
<abi>x86</abi>
<abi>mips</abi>
</abi-group>
</abi-groups>
<screen-density-groups>
- <screen-density-group label="large">
- <screen-density>xhdpi</screen-density>
- <screen-density>xxhdpi</screen-density>
- <screen-density>xxxhdpi</screen-density>
- </screen-density-group>
-
- <screen-density-group label="alldpi">
+ <screen-density-group label="alldpi" version-code-order="1">
<screen-density>ldpi</screen-density>
<screen-density>mdpi</screen-density>
<screen-density>hdpi</screen-density>
@@ -62,29 +56,35 @@
<screen-density>xxhdpi</screen-density>
<screen-density>xxxhdpi</screen-density>
</screen-density-group>
+
+ <screen-density-group label="large" version-code-order="2">
+ <screen-density>xhdpi</screen-density>
+ <screen-density>xxhdpi</screen-density>
+ <screen-density>xxxhdpi</screen-density>
+ </screen-density-group>
</screen-density-groups>
<locale-groups>
- <locale-group label="europe">
+ <locale-group label="europe" version-code-order="1">
<locale lang="en"/>
<locale lang="es"/>
<locale lang="fr"/>
<locale lang="de" compressed="true"/>
</locale-group>
- <locale-group label="north-america">
+ <locale-group label="north-america" version-code-order="2">
<locale lang="en"/>
<locale lang="es" region="MX"/>
<locale lang="fr" region="CA" compressed="true"/>
</locale-group>
- <locale-group label="all">
+ <locale-group label="all" version-code-order="0">
<locale compressed="true"/>
</locale-group>
</locale-groups>
<gl-texture-groups>
- <gl-texture-group label="dxt1">
+ <gl-texture-group label="dxt1" version-code-order="1">
<gl-texture name="GL_EXT_texture_compression_dxt1">
<texture-path>assets/dxt1/*</texture-path>
</gl-texture>
@@ -92,7 +92,7 @@
</gl-texture-groups>
<device-feature-groups>
- <device-feature-group label="low-latency">
+ <device-feature-group label="low-latency" version-code-order="1">
<supports-feature>android.hardware.audio.low_latency</supports-feature>
</device-feature-group>
</device-feature-groups>
diff --git a/tools/aapt2/link/XmlCompatVersioner_test.cpp b/tools/aapt2/link/XmlCompatVersioner_test.cpp
index 1ed4536..a98ab0f 100644
--- a/tools/aapt2/link/XmlCompatVersioner_test.cpp
+++ b/tools/aapt2/link/XmlCompatVersioner_test.cpp
@@ -23,6 +23,7 @@
using ::testing::Eq;
using ::testing::IsNull;
using ::testing::NotNull;
+using ::testing::Pointee;
using ::testing::SizeIs;
namespace aapt {
@@ -287,13 +288,13 @@
ASSERT_THAT(attr, NotNull());
ASSERT_THAT(attr->compiled_value, NotNull());
ASSERT_TRUE(attr->compiled_attribute);
- ASSERT_THAT(*attr->compiled_value, ValueEq(padding_horizontal_value));
+ ASSERT_THAT(attr->compiled_value, Pointee(ValueEq(padding_horizontal_value)));
attr = el->FindAttribute(xml::kSchemaAndroid, "paddingRight");
ASSERT_THAT(attr, NotNull());
ASSERT_THAT(attr->compiled_value, NotNull());
ASSERT_TRUE(attr->compiled_attribute);
- ASSERT_THAT(*attr->compiled_value, ValueEq(padding_horizontal_value));
+ ASSERT_THAT(attr->compiled_value, Pointee(ValueEq(padding_horizontal_value)));
EXPECT_THAT(versioned_docs[1]->file.config.sdkVersion, Eq(SDK_LOLLIPOP_MR1));
el = versioned_docs[1]->root.get();
@@ -302,21 +303,20 @@
attr = el->FindAttribute(xml::kSchemaAndroid, "paddingHorizontal");
ASSERT_THAT(attr, NotNull());
- ASSERT_THAT(attr->compiled_value, NotNull());
ASSERT_TRUE(attr->compiled_attribute);
- ASSERT_THAT(*attr->compiled_value, ValueEq(padding_horizontal_value));
+ ASSERT_THAT(attr->compiled_value, Pointee(ValueEq(padding_horizontal_value)));
attr = el->FindAttribute(xml::kSchemaAndroid, "paddingLeft");
ASSERT_THAT(attr, NotNull());
ASSERT_THAT(attr->compiled_value, NotNull());
ASSERT_TRUE(attr->compiled_attribute);
- ASSERT_THAT(*attr->compiled_value, ValueEq(padding_horizontal_value));
+ ASSERT_THAT(attr->compiled_value, Pointee(ValueEq(padding_horizontal_value)));
attr = el->FindAttribute(xml::kSchemaAndroid, "paddingRight");
ASSERT_THAT(attr, NotNull());
ASSERT_THAT(attr->compiled_value, NotNull());
ASSERT_TRUE(attr->compiled_attribute);
- ASSERT_THAT(*attr->compiled_value, ValueEq(padding_horizontal_value));
+ ASSERT_THAT(attr->compiled_value, Pointee(ValueEq(padding_horizontal_value)));
}
} // namespace aapt
diff --git a/tools/aapt2/optimize/MultiApkGenerator.cpp b/tools/aapt2/optimize/MultiApkGenerator.cpp
index 991faad..588b331 100644
--- a/tools/aapt2/optimize/MultiApkGenerator.cpp
+++ b/tools/aapt2/optimize/MultiApkGenerator.cpp
@@ -322,22 +322,56 @@
std::unique_ptr<xml::Element> new_screens_el = util::make_unique<xml::Element>();
new_screens_el->name = "compatible-screens";
screens_el = new_screens_el.get();
- manifest_el->InsertChild(0, std::move(new_screens_el));
+ manifest_el->AppendChild(std::move(new_screens_el));
} else {
// clear out the old element.
screens_el->GetChildElements().clear();
}
for (const auto& density : artifact.screen_densities) {
- std::unique_ptr<xml::Element> screen_el = util::make_unique<xml::Element>();
- screen_el->name = "screen";
- const char* density_str = density.toString().string();
- screen_el->attributes.push_back(xml::Attribute{kSchemaAndroid, "screenDensity", density_str});
- screens_el->AppendChild(std::move(screen_el));
+ AddScreens(density, screens_el);
}
}
return true;
}
+/**
+ * Adds a screen element with both screenSize and screenDensity set. Since we only know the density
+ * we add it for all screen sizes.
+ *
+ * This requires the resource IDs for the attributes from the framework library. Since these IDs are
+ * a part of the public API (and in public.xml) we hard code the values.
+ *
+ * The excert from the framework is as follows:
+ * <public type="attr" name="screenSize" id="0x010102ca" />
+ * <public type="attr" name="screenDensity" id="0x010102cb" />
+ */
+void MultiApkGenerator::AddScreens(const ConfigDescription& config, xml::Element* parent) {
+ // Hard coded integer representation of the supported screen sizes:
+ // small = 200
+ // normal = 300
+ // large = 400
+ // xlarge = 500
+ constexpr const uint32_t kScreenSizes[4] = {200, 300, 400, 500,};
+ constexpr const uint32_t kScreenSizeResourceId = 0x010102ca;
+ constexpr const uint32_t kScreenDensityResourceId = 0x010102cb;
+
+ for (uint32_t screen_size : kScreenSizes) {
+ std::unique_ptr<xml::Element> screen = util::make_unique<xml::Element>();
+ screen->name = "screen";
+
+ xml::Attribute* size = screen->FindOrCreateAttribute(kSchemaAndroid, "screenSize");
+ size->compiled_attribute = xml::AaptAttribute(Attribute(), {kScreenSizeResourceId});
+ size->compiled_value = ResourceUtils::MakeInt(screen_size);
+
+ xml::Attribute* density = screen->FindOrCreateAttribute(kSchemaAndroid, "screenDensity");
+ density->compiled_attribute = xml::AaptAttribute(Attribute(), {kScreenDensityResourceId});
+ density->compiled_value = ResourceUtils::MakeInt(config.density);
+
+
+ parent->AppendChild(std::move(screen));
+ }
+}
+
} // namespace aapt
diff --git a/tools/aapt2/optimize/MultiApkGenerator.h b/tools/aapt2/optimize/MultiApkGenerator.h
index 19f64cc..c858879 100644
--- a/tools/aapt2/optimize/MultiApkGenerator.h
+++ b/tools/aapt2/optimize/MultiApkGenerator.h
@@ -63,6 +63,11 @@
bool UpdateManifest(const configuration::OutputArtifact& artifact,
std::unique_ptr<xml::XmlResource>* updated_manifest, IDiagnostics* diag);
+ /**
+ * Adds the <screen> elements to the parent node for the provided density configuration.
+ */
+ void AddScreens(const ConfigDescription& config, xml::Element* parent);
+
LoadedApk* apk_;
IAaptContext* context_;
};
diff --git a/tools/aapt2/test/Common.h b/tools/aapt2/test/Common.h
index 4e318a9..aca161a 100644
--- a/tools/aapt2/test/Common.h
+++ b/tools/aapt2/test/Common.h
@@ -146,97 +146,70 @@
return android::StringPiece16(arg) == a;
}
-class ValueEq {
+template <typename T>
+class ValueEqImpl : public ::testing::MatcherInterface<T> {
public:
- template <typename arg_type>
- class BaseImpl : public ::testing::MatcherInterface<arg_type> {
- BaseImpl(const BaseImpl&) = default;
-
- void DescribeTo(::std::ostream* os) const override {
- *os << "is equal to " << *expected_;
- }
-
- void DescribeNegationTo(::std::ostream* os) const override {
- *os << "is not equal to " << *expected_;
- }
-
- protected:
- BaseImpl(const Value* expected) : expected_(expected) {
- }
-
- const Value* expected_;
- };
-
- template <typename T, bool>
- class Impl {};
-
- template <typename T>
- class Impl<T, false> : public ::testing::MatcherInterface<T> {
- public:
- explicit Impl(const Value* expected) : expected_(expected) {
- }
-
- bool MatchAndExplain(T x, ::testing::MatchResultListener* listener) const override {
- return expected_->Equals(&x);
- }
-
- void DescribeTo(::std::ostream* os) const override {
- *os << "is equal to " << *expected_;
- }
-
- void DescribeNegationTo(::std::ostream* os) const override {
- *os << "is not equal to " << *expected_;
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(Impl);
-
- const Value* expected_;
- };
-
- template <typename T>
- class Impl<T, true> : public ::testing::MatcherInterface<T> {
- public:
- explicit Impl(const Value* expected) : expected_(expected) {
- }
-
- bool MatchAndExplain(T x, ::testing::MatchResultListener* listener) const override {
- return expected_->Equals(x);
- }
-
- void DescribeTo(::std::ostream* os) const override {
- *os << "is equal to " << *expected_;
- }
-
- void DescribeNegationTo(::std::ostream* os) const override {
- *os << "is not equal to " << *expected_;
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(Impl);
-
- const Value* expected_;
- };
-
- ValueEq(const Value& expected) : expected_(&expected) {
+ explicit ValueEqImpl(const Value* expected) : expected_(expected) {
}
- ValueEq(const Value* expected) : expected_(expected) {
- }
- ValueEq(const ValueEq&) = default;
- template <typename T>
- operator ::testing::Matcher<T>() const {
- return ::testing::Matcher<T>(new Impl<T, std::is_pointer<T>::value>(expected_));
+ bool MatchAndExplain(T x, ::testing::MatchResultListener* listener) const override {
+ return expected_->Equals(&x);
+ }
+
+ void DescribeTo(::std::ostream* os) const override {
+ *os << "is equal to " << *expected_;
+ }
+
+ void DescribeNegationTo(::std::ostream* os) const override {
+ *os << "is not equal to " << *expected_;
}
private:
+ DISALLOW_COPY_AND_ASSIGN(ValueEqImpl);
+
const Value* expected_;
};
-// MATCHER_P(ValueEq, a,
-// std::string(negation ? "isn't" : "is") + " equal to " + ::testing::PrintToString(a)) {
-// return arg.Equals(&a);
-//}
+template <typename TValue>
+class ValueEqMatcher {
+ public:
+ ValueEqMatcher(TValue expected) : expected_(std::move(expected)) {
+ }
+
+ template <typename T>
+ operator ::testing::Matcher<T>() const {
+ return ::testing::Matcher<T>(new ValueEqImpl<T>(&expected_));
+ }
+
+ private:
+ TValue expected_;
+};
+
+template <typename TValue>
+class ValueEqPointerMatcher {
+ public:
+ ValueEqPointerMatcher(const TValue* expected) : expected_(expected) {
+ }
+
+ template <typename T>
+ operator ::testing::Matcher<T>() const {
+ return ::testing::Matcher<T>(new ValueEqImpl<T>(expected_));
+ }
+
+ private:
+ const TValue* expected_;
+};
+
+template <typename TValue,
+ typename = typename std::enable_if<!std::is_pointer<TValue>::value, void>::type>
+inline ValueEqMatcher<TValue> ValueEq(TValue value) {
+ return ValueEqMatcher<TValue>(std::move(value));
+}
+
+template <typename TValue>
+inline ValueEqPointerMatcher<TValue> ValueEq(const TValue* value) {
+ return ValueEqPointerMatcher<TValue>(value);
+}
MATCHER_P(StrValueEq, a,
std::string(negation ? "isn't" : "is") + " equal to " + ::testing::PrintToString(a)) {
diff --git a/tools/aapt2/xml/XmlDom.cpp b/tools/aapt2/xml/XmlDom.cpp
index fddb6b8..7b748ce 100644
--- a/tools/aapt2/xml/XmlDom.cpp
+++ b/tools/aapt2/xml/XmlDom.cpp
@@ -244,14 +244,13 @@
str16 = parser->getAttributeStringValue(i, &len);
if (str16) {
attr.value = util::Utf16ToUtf8(StringPiece16(str16, len));
- } else {
- android::Res_value res_value;
- if (parser->getAttributeValue(i, &res_value) > 0) {
- attr.compiled_value = ResourceUtils::ParseBinaryResValue(
- ResourceType::kAnim, {}, parser->getStrings(), res_value, out_pool);
- }
}
+ android::Res_value res_value;
+ if (parser->getAttributeValue(i, &res_value) > 0) {
+ attr.compiled_value = ResourceUtils::ParseBinaryResValue(
+ ResourceType::kAnim, {}, parser->getStrings(), res_value, out_pool);
+ }
el->attributes.push_back(std::move(attr));
}
diff --git a/tools/aapt2/xml/XmlDom_test.cpp b/tools/aapt2/xml/XmlDom_test.cpp
index e5012d6..486b53a 100644
--- a/tools/aapt2/xml/XmlDom_test.cpp
+++ b/tools/aapt2/xml/XmlDom_test.cpp
@@ -23,8 +23,10 @@
#include "test/Test.h"
using ::aapt::io::StringInputStream;
+using ::aapt::test::ValueEq;
using ::testing::Eq;
using ::testing::NotNull;
+using ::testing::Pointee;
using ::testing::SizeIs;
using ::testing::StrEq;
@@ -59,6 +61,16 @@
doc->root->name = "Layout";
doc->root->line_number = 2u;
+ xml::Attribute attr;
+ attr.name = "text";
+ attr.namespace_uri = kSchemaAndroid;
+ attr.compiled_attribute = AaptAttribute(
+ aapt::Attribute(android::ResTable_map::TYPE_REFERENCE | android::ResTable_map::TYPE_STRING),
+ ResourceId(0x01010001u));
+ attr.value = "@string/foo";
+ attr.compiled_value = test::BuildReference("string/foo", ResourceId(0x7f010000u));
+ doc->root->attributes.push_back(std::move(attr));
+
NamespaceDecl decl;
decl.uri = kSchemaAndroid;
decl.prefix = "android";
@@ -66,7 +78,9 @@
doc->root->namespace_decls.push_back(decl);
BigBuffer buffer(4096);
- XmlFlattener flattener(&buffer, {});
+ XmlFlattenerOptions options;
+ options.keep_raw_values = true;
+ XmlFlattener flattener(&buffer, options);
ASSERT_TRUE(flattener.Consume(context.get(), doc.get()));
auto block = util::Copy(buffer);
@@ -75,6 +89,21 @@
EXPECT_THAT(new_doc->root->name, StrEq("Layout"));
EXPECT_THAT(new_doc->root->line_number, Eq(2u));
+
+ ASSERT_THAT(new_doc->root->attributes, SizeIs(1u));
+ EXPECT_THAT(new_doc->root->attributes[0].name, StrEq("text"));
+ EXPECT_THAT(new_doc->root->attributes[0].namespace_uri, StrEq(kSchemaAndroid));
+
+ // We only check that the resource ID was preserved. There is no where to encode the types that
+ // the Attribute accepts (eg: string|reference).
+ ASSERT_TRUE(new_doc->root->attributes[0].compiled_attribute);
+ EXPECT_THAT(new_doc->root->attributes[0].compiled_attribute.value().id,
+ Eq(make_value(ResourceId(0x01010001u))));
+
+ EXPECT_THAT(new_doc->root->attributes[0].value, StrEq("@string/foo"));
+ EXPECT_THAT(new_doc->root->attributes[0].compiled_value,
+ Pointee(ValueEq(Reference(ResourceId(0x7f010000u)))));
+
ASSERT_THAT(new_doc->root->namespace_decls, SizeIs(1u));
EXPECT_THAT(new_doc->root->namespace_decls[0].uri, StrEq(kSchemaAndroid));
EXPECT_THAT(new_doc->root->namespace_decls[0].prefix, StrEq("android"));
diff --git a/tools/sdkparcelables/src/com/android/sdkparcelables/ParcelableDetector.kt b/tools/sdkparcelables/src/com/android/sdkparcelables/ParcelableDetector.kt
index d6a0a45..45027b5 100644
--- a/tools/sdkparcelables/src/com/android/sdkparcelables/ParcelableDetector.kt
+++ b/tools/sdkparcelables/src/com/android/sdkparcelables/ParcelableDetector.kt
@@ -27,6 +27,8 @@
impl.build()
return impl.parcelables
}
+
+ const val PARCELABLE_CLASS = "android/os/Parcelable"
}
private class Impl(val ancestors: Map<String, Ancestors>) {
@@ -35,7 +37,7 @@
fun build() {
val classList = ancestors.keys
- classList.filterTo(parcelables, this::isParcelable)
+ classList.filterTo(parcelables, { (it != PARCELABLE_CLASS) && isParcelable(it) })
parcelables.sort()
}
@@ -44,7 +46,7 @@
return false
}
- if (c == "android/os/Parcelable") {
+ if (c == PARCELABLE_CLASS) {
return true
}
diff --git a/tools/sdkparcelables/tests/com/android/sdkparcelables/ParcelableDetectorTest.kt b/tools/sdkparcelables/tests/com/android/sdkparcelables/ParcelableDetectorTest.kt
index c9bcbc9..f08173d 100644
--- a/tools/sdkparcelables/tests/com/android/sdkparcelables/ParcelableDetectorTest.kt
+++ b/tools/sdkparcelables/tests/com/android/sdkparcelables/ParcelableDetectorTest.kt
@@ -28,7 +28,7 @@
val parcelables = ParcelableDetector.ancestorsToParcelables(ancestorMap)
- assertEquals(parcelables, listOf("android/os/Parcelable", "android/test/Parcelable"))
+ assertEquals(parcelables, listOf("android/test/Parcelable"))
}
@Test
@@ -39,7 +39,7 @@
val parcelables = ParcelableDetector.ancestorsToParcelables(ancestorMap)
- assertEquals(parcelables, listOf("android/os/Parcelable", "android/test/Parcelable"))
+ assertEquals(parcelables, listOf("android/test/Parcelable"))
}
@Test
@@ -51,7 +51,7 @@
val parcelables = ParcelableDetector.ancestorsToParcelables(ancestorMap)
- assertEquals(parcelables, listOf("android/os/Parcelable", "android/test/Parcelable", "android/test/SuperParcelable"))
+ assertEquals(parcelables, listOf("android/test/Parcelable", "android/test/SuperParcelable"))
}
@Test
@@ -63,7 +63,7 @@
val parcelables = ParcelableDetector.ancestorsToParcelables(ancestorMap)
- assertEquals(parcelables, listOf("android/os/Parcelable", "android/test/IParcelable", "android/test/Parcelable"))
+ assertEquals(parcelables, listOf("android/test/IParcelable", "android/test/Parcelable"))
}
}
diff --git a/tools/stats_log_api_gen/Android.bp b/tools/stats_log_api_gen/Android.bp
index e301eb1..dc2ed43 100644
--- a/tools/stats_log_api_gen/Android.bp
+++ b/tools/stats_log_api_gen/Android.bp
@@ -102,6 +102,7 @@
export_generated_headers: ["statslog.h"],
shared_libs: [
"liblog",
+ "libutils",
],
}
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index 3dbb503..f0628c0 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -105,6 +105,7 @@
fprintf(out, "#include <log/log_event_list.h>\n");
fprintf(out, "#include <log/log.h>\n");
fprintf(out, "#include <statslog.h>\n");
+ fprintf(out, "#include <utils/SystemClock.h>\n");
fprintf(out, "\n");
fprintf(out, "namespace android {\n");
@@ -145,6 +146,7 @@
fprintf(out, "{\n");
argIndex = 1;
fprintf(out, " android_log_event_list event(kStatsEventTag);\n");
+ fprintf(out, " event << android::elapsedRealtimeNano();\n\n");
fprintf(out, " event << code;\n\n");
for (vector<java_type_t>::const_iterator arg = signature->begin();
arg != signature->end(); arg++) {
@@ -212,6 +214,7 @@
fprintf(out, "{\n");
argIndex = 1;
fprintf(out, " android_log_event_list event(kStatsEventTag);\n");
+ fprintf(out, " event << android::elapsedRealtimeNano();\n\n");
fprintf(out, " event << code;\n\n");
for (vector<java_type_t>::const_iterator arg = signature->begin();
arg != signature->end(); arg++) {
diff --git a/wifi/OWNERS b/wifi/OWNERS
new file mode 100644
index 0000000..0efa464
--- /dev/null
+++ b/wifi/OWNERS
@@ -0,0 +1,5 @@
+set noparent
+
+etancohen@google.com
+satk@google.com
+silberst@google.com
diff --git a/wifi/java/android/net/wifi/RttManager.java b/wifi/java/android/net/wifi/RttManager.java
index bdbc149..a61ac54 100644
--- a/wifi/java/android/net/wifi/RttManager.java
+++ b/wifi/java/android/net/wifi/RttManager.java
@@ -15,6 +15,7 @@
import android.os.Handler;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.SystemClock;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
@@ -986,11 +987,16 @@
legacyResults[i] = new RttResult();
legacyResults[i].status = result.getStatus();
legacyResults[i].bssid = result.getMacAddress().toString();
- legacyResults[i].distance = result.getDistanceMm() / 10;
- legacyResults[i].distanceStandardDeviation =
- result.getDistanceStdDevMm() / 10;
- legacyResults[i].rssi = result.getRssi();
- legacyResults[i].ts = result.getRangingTimestampUs();
+ if (result.getStatus() == RangingResult.STATUS_SUCCESS) {
+ legacyResults[i].distance = result.getDistanceMm() / 10;
+ legacyResults[i].distanceStandardDeviation =
+ result.getDistanceStdDevMm() / 10;
+ legacyResults[i].rssi = result.getRssi();
+ legacyResults[i].ts = result.getRangingTimestampUs();
+ } else {
+ // just in case legacy API needed some relatively real timestamp
+ legacyResults[i].ts = SystemClock.elapsedRealtime() * 1000;
+ }
}
listener.onSuccess(legacyResults);
}
diff --git a/wifi/java/android/net/wifi/rtt/RangingRequest.java b/wifi/java/android/net/wifi/rtt/RangingRequest.java
index 52b3d86..4348ed4 100644
--- a/wifi/java/android/net/wifi/rtt/RangingRequest.java
+++ b/wifi/java/android/net/wifi/rtt/RangingRequest.java
@@ -122,6 +122,11 @@
* Add the device specified by the {@link ScanResult} to the list of devices with
* which to measure range. The total number of peers added to a request cannot exceed the
* limit specified by {@link #getMaxPeers()}.
+ * <p>
+ * Ranging may not be supported if the Access Point does not support IEEE 802.11mc. Use
+ * {@link ScanResult#is80211mcResponder()} to verify the Access Point's capabilities. If
+ * not supported the result status will be
+ * {@link RangingResult#STATUS_RESPONDER_DOES_NOT_SUPPORT_IEEE80211MC}.
*
* @param apInfo Information of an Access Point (AP) obtained in a Scan Result.
* @return The builder to facilitate chaining
@@ -138,6 +143,11 @@
* Add the devices specified by the {@link ScanResult}s to the list of devices with
* which to measure range. The total number of peers added to a request cannot exceed the
* limit specified by {@link #getMaxPeers()}.
+ * <p>
+ * Ranging may not be supported if the Access Point does not support IEEE 802.11mc. Use
+ * {@link ScanResult#is80211mcResponder()} to verify the Access Point's capabilities. If
+ * not supported the result status will be
+ * {@link RangingResult#STATUS_RESPONDER_DOES_NOT_SUPPORT_IEEE80211MC}.
*
* @param apInfos Information of an Access Points (APs) obtained in a Scan Result.
* @return The builder to facilitate chaining
diff --git a/wifi/java/android/net/wifi/rtt/RangingResult.java b/wifi/java/android/net/wifi/rtt/RangingResult.java
index 201833b..5c9bd19 100644
--- a/wifi/java/android/net/wifi/rtt/RangingResult.java
+++ b/wifi/java/android/net/wifi/rtt/RangingResult.java
@@ -42,7 +42,7 @@
private static final String TAG = "RangingResult";
/** @hide */
- @IntDef({STATUS_SUCCESS, STATUS_FAIL})
+ @IntDef({STATUS_SUCCESS, STATUS_FAIL, STATUS_RESPONDER_DOES_NOT_SUPPORT_IEEE80211MC})
@Retention(RetentionPolicy.SOURCE)
public @interface RangeResultStatus {
}
@@ -59,6 +59,17 @@
*/
public static final int STATUS_FAIL = 1;
+ /**
+ * Individual range request status, {@link #getStatus()}. Indicates that the ranging operation
+ * failed because the specified peer does not support IEEE 802.11mc RTT operations. Support by
+ * an Access Point can be confirmed using
+ * {@link android.net.wifi.ScanResult#is80211mcResponder()}.
+ * <p>
+ * On such a failure, the individual result fields of {@link RangingResult} such as
+ * {@link RangingResult#getDistanceMm()} are invalid.
+ */
+ public static final int STATUS_RESPONDER_DOES_NOT_SUPPORT_IEEE80211MC = 2;
+
private final int mStatus;
private final MacAddress mMac;
private final PeerHandle mPeerHandle;