Merge "Check if the given user is unlocked when unlock by token" into pi-dev
diff --git a/api/current.txt b/api/current.txt
index 414491c..b8f1324 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5401,6 +5401,7 @@
method public android.app.Notification.Builder extend(android.app.Notification.Extender);
method public android.os.Bundle getExtras();
method public deprecated android.app.Notification getNotification();
+ method public android.app.Notification.Style getStyle();
method public static android.app.Notification.Builder recoverBuilder(android.content.Context, android.app.Notification);
method public android.app.Notification.Builder setActions(android.app.Notification.Action...);
method public android.app.Notification.Builder setAutoCancel(boolean);
@@ -7281,6 +7282,13 @@
field public static final java.lang.String SLICE_METADATA_KEY = "android.metadata.SLICE_URI";
}
+ public class SliceMetrics {
+ ctor public SliceMetrics(android.content.Context, android.net.Uri);
+ method public void logHidden();
+ method public void logTouch(android.net.Uri);
+ method public void logVisible();
+ }
+
public abstract class SliceProvider extends android.content.ContentProvider {
ctor public SliceProvider();
method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]);
@@ -15804,6 +15812,7 @@
field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> INFO_SUPPORTED_HARDWARE_LEVEL;
field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.String> INFO_VERSION;
field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Size[]> JPEG_AVAILABLE_THUMBNAIL_SIZES;
+ field public static final android.hardware.camera2.CameraCharacteristics.Key<float[]> LENS_DISTORTION;
field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> LENS_FACING;
field public static final android.hardware.camera2.CameraCharacteristics.Key<float[]> LENS_INFO_AVAILABLE_APERTURES;
field public static final android.hardware.camera2.CameraCharacteristics.Key<float[]> LENS_INFO_AVAILABLE_FILTER_DENSITIES;
@@ -15816,7 +15825,7 @@
field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> LENS_POSE_REFERENCE;
field public static final android.hardware.camera2.CameraCharacteristics.Key<float[]> LENS_POSE_ROTATION;
field public static final android.hardware.camera2.CameraCharacteristics.Key<float[]> LENS_POSE_TRANSLATION;
- field public static final android.hardware.camera2.CameraCharacteristics.Key<float[]> LENS_RADIAL_DISTORTION;
+ field public static final deprecated android.hardware.camera2.CameraCharacteristics.Key<float[]> LENS_RADIAL_DISTORTION;
field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE;
field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES;
field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REPROCESS_MAX_CAPTURE_STALL;
@@ -16274,6 +16283,7 @@
field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Byte> JPEG_THUMBNAIL_QUALITY;
field public static final android.hardware.camera2.CaptureResult.Key<android.util.Size> JPEG_THUMBNAIL_SIZE;
field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Float> LENS_APERTURE;
+ field public static final android.hardware.camera2.CaptureResult.Key<float[]> LENS_DISTORTION;
field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Float> LENS_FILTER_DENSITY;
field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Float> LENS_FOCAL_LENGTH;
field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Float> LENS_FOCUS_DISTANCE;
@@ -16282,7 +16292,7 @@
field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> LENS_OPTICAL_STABILIZATION_MODE;
field public static final android.hardware.camera2.CaptureResult.Key<float[]> LENS_POSE_ROTATION;
field public static final android.hardware.camera2.CaptureResult.Key<float[]> LENS_POSE_TRANSLATION;
- field public static final android.hardware.camera2.CaptureResult.Key<float[]> LENS_RADIAL_DISTORTION;
+ field public static final deprecated android.hardware.camera2.CaptureResult.Key<float[]> LENS_RADIAL_DISTORTION;
field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> LENS_STATE;
field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> NOISE_REDUCTION_MODE;
field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Float> REPROCESS_EFFECTIVE_EXPOSURE_FACTOR;
@@ -29475,7 +29485,7 @@
field public static final java.lang.String EXTRA_ID = "android.nfc.extra.ID";
field public static final java.lang.String EXTRA_NDEF_MESSAGES = "android.nfc.extra.NDEF_MESSAGES";
field public static final java.lang.String EXTRA_READER_PRESENCE_CHECK_DELAY = "presence";
- field public static final java.lang.String EXTRA_SE_NAME = "android.nfc.extra.SE_NAME";
+ field public static final java.lang.String EXTRA_SECURE_ELEMENT_NAME = "android.nfc.extra.SECURE_ELEMENT_NAME";
field public static final java.lang.String EXTRA_TAG = "android.nfc.extra.TAG";
field public static final int FLAG_READER_NFC_A = 1; // 0x1
field public static final int FLAG_READER_NFC_B = 2; // 0x2
diff --git a/api/system-current.txt b/api/system-current.txt
index 0e33c17..038c6ed 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -723,6 +723,7 @@
method public java.lang.String getNotificationChannelId();
field public static final int NOTIFICATION_INTERRUPTION = 12; // 0xc
field public static final int NOTIFICATION_SEEN = 10; // 0xa
+ field public static final int SYSTEM_INTERACTION = 6; // 0x6
}
public final class UsageStatsManager {
@@ -5213,10 +5214,10 @@
method public boolean handlePinMmi(java.lang.String);
method public boolean handlePinMmiForSubscriber(int, java.lang.String);
method public boolean isDataConnectivityPossible();
- method public deprecated boolean isIdle();
- method public deprecated boolean isOffhook();
- method public deprecated boolean isRadioOn();
- method public deprecated boolean isRinging();
+ method public boolean isIdle();
+ method public boolean isOffhook();
+ method public boolean isRadioOn();
+ method public boolean isRinging();
method public boolean isVideoCallingEnabled();
method public deprecated boolean isVisualVoicemailEnabled(android.telecom.PhoneAccountHandle);
method public boolean needsOtaServiceProvisioning();
@@ -5442,6 +5443,7 @@
public class EuiccManager {
method public void continueOperation(android.content.Intent, android.os.Bundle);
+ method public void eraseSubscriptions(android.app.PendingIntent);
method public void getDefaultDownloadableSubscriptionList(android.app.PendingIntent);
method public void getDownloadableSubscriptionMetadata(android.telephony.euicc.DownloadableSubscription, android.app.PendingIntent);
method public int getOtaStatus();
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 652ec9d..8b681edd 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -112,8 +112,8 @@
}
void StatsLogProcessor::mapIsolatedUidToHostUidIfNecessaryLocked(LogEvent* event) const {
- if (android::util::kAtomsWithAttributionChain.find(event->GetTagId()) !=
- android::util::kAtomsWithAttributionChain.end()) {
+ if (android::util::AtomsInfo::kAtomsWithAttributionChain.find(event->GetTagId()) !=
+ android::util::AtomsInfo::kAtomsWithAttributionChain.end()) {
for (auto& value : *(event->getMutableValues())) {
if (value.mField.getPosAtDepth(0) > kAttributionField) {
break;
@@ -123,12 +123,20 @@
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);
+ } else {
+ auto it = android::util::AtomsInfo::kAtomsWithUidField.find(event->GetTagId());
+ if (it != android::util::AtomsInfo::kAtomsWithUidField.end()) {
+ int uidField = it->second; // uidField is the field number in proto,
+ // starting from 1
+ if (uidField > 0 && (int)event->getValues().size() >= uidField &&
+ (event->getValues())[uidField - 1].mValue.getType() == INT) {
+ Value& value = (*event->getMutableValues())[uidField - 1].mValue;
+ const int hostUid = mUidMap->getHostUidOrSelf(value.int_value);
+ updateUid(&value, hostUid);
+ } else {
+ ALOGE("Malformed log, uid not found. %s", event->ToString().c_str());
+ }
+ }
}
}
diff --git a/cmds/statsd/src/atom_field_options.proto b/cmds/statsd/src/atom_field_options.proto
index 19d00b7..a2a03b1 100644
--- a/cmds/statsd/src/atom_field_options.proto
+++ b/cmds/statsd/src/atom_field_options.proto
@@ -67,4 +67,7 @@
extend google.protobuf.FieldOptions {
// Flags to decorate an atom that presents a state change.
optional StateAtomFieldOption stateFieldOption = 50000;
+
+ // Flags to decorate the uid fields in an atom.
+ optional bool is_uid = 50001 [default = false];
}
\ No newline at end of file
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index f74188f..40eff4c 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -209,7 +209,7 @@
* frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
*/
message UidProcessStateChanged {
- optional int32 uid = 1 [(stateFieldOption).option = PRIMARY];
+ optional int32 uid = 1 [(stateFieldOption).option = PRIMARY, (is_uid) = true];
// The state, from frameworks/base/core/proto/android/app/enums.proto.
optional android.app.ProcessStateEnum state = 2 [(stateFieldOption).option = EXCLUSIVE];
@@ -223,7 +223,7 @@
*/
message ProcessLifeCycleStateChanged {
// TODO: should be a string tagged w/ uid annotation
- optional int32 uid = 1;
+ optional int32 uid = 1 [(is_uid) = true];
// The process name (usually same as the app name).
optional string name = 2;
@@ -593,7 +593,7 @@
*/
message MobileRadioPowerStateChanged {
// TODO: Add attribution instead of uid?
- optional int32 uid = 1;
+ optional int32 uid = 1 [(is_uid) = true];
// Power state, from frameworks/base/core/proto/android/telephony/enums.proto.
optional android.telephony.DataConnectionPowerStateEnum state = 2;
@@ -608,7 +608,7 @@
*/
message WifiRadioPowerStateChanged {
// TODO: Add attribution instead of uid?
- optional int32 uid = 1;
+ optional int32 uid = 1 [(is_uid) = true];
// Power state, from frameworks/base/core/proto/android/telephony/enums.proto.
optional android.telephony.DataConnectionPowerStateEnum state = 2;
@@ -1130,7 +1130,8 @@
*/
message DaveyOccurred {
// The UID that logged this atom.
- optional int32 uid = 1;
+ optional int32 uid = 1 [(is_uid) = true];
+ ;
// Amount of time it took to render the frame. Should be >=700ms.
optional int64 jank_duration_millis = 2;
@@ -1150,7 +1151,7 @@
/**
* Logs that a setting was updated.
* Logged from:
- * frameworks/base/core/java/android/provider/Settings.java
+ * frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
* The tag and is_default allow resetting of settings to default values based on the specified
* tag. See Settings#putString(ContentResolver, String, String, String, boolean) for more details.
*/
@@ -1176,8 +1177,14 @@
// True if this setting with tag should be resettable.
optional bool is_default = 6;
- // The user ID associated. Defined in android/os/UserHandle.java
+ // The associated user (for multi-user feature). Defined in android/os/UserHandle.java
optional int32 user = 7;
+
+ enum ChangeReason {
+ UPDATED = 1; // Updated can be an insertion or an update.
+ DELETED = 2;
+ }
+ optional ChangeReason reason = 8;
}
/**
@@ -1187,7 +1194,7 @@
* frameworks/base/services/core/java/com/android/server/am/ActivityRecord.java
*/
message ActivityForegroundStateChanged {
- optional int32 uid = 1;
+ optional int32 uid = 1 [(is_uid) = true];
optional string pkg_name = 2;
optional string class_name = 3;
@@ -1205,7 +1212,7 @@
*/
message DropboxErrorChanged {
// The uid if available. -1 means not available.
- optional int32 uid = 1;
+ optional int32 uid = 1 [(is_uid) = true];
// Tag used when recording this error to dropbox. Contains data_ or system_ prefix.
optional string tag = 2;
@@ -1236,7 +1243,7 @@
*/
message AppBreadcrumbReported {
// The uid of the application that sent this custom atom.
- optional int32 uid = 1;
+ optional int32 uid = 1 [(is_uid) = true];
// An arbitrary label chosen by the developer. For Android P, the label should be in [0, 16).
optional int32 label = 2;
@@ -1260,7 +1267,7 @@
*/
message AnomalyDetected {
// Uid that owns the config whose anomaly detection alert fired.
- optional int32 config_uid = 1;
+ optional int32 config_uid = 1 [(is_uid) = true];
// Id of the config whose anomaly detection alert fired.
optional int64 config_id = 2;
@@ -1271,7 +1278,7 @@
message AppStartChanged {
// The uid if available. -1 means not available.
- optional int32 uid = 1;
+ optional int32 uid = 1 [(is_uid) = true];
// The app package name.
optional string pkg_name = 2;
@@ -1318,7 +1325,7 @@
message AppStartCancelChanged {
// The uid if available. -1 means not available.
- optional int32 uid = 1;
+ optional int32 uid = 1 [(is_uid) = true];
// The app package name.
optional string pkg_name = 2;
@@ -1338,7 +1345,7 @@
message AppStartFullyDrawnChanged {
// The uid if available. -1 means not available.
- optional int32 uid = 1;
+ optional int32 uid = 1 [(is_uid) = true];
// The app package name.
optional string pkg_name = 2;
@@ -1369,7 +1376,7 @@
*/
message PictureInPictureStateChanged {
// -1 if it is not available
- optional int32 uid = 1;
+ optional int32 uid = 1 [(is_uid) = true];
optional string short_name = 2;
@@ -1388,7 +1395,7 @@
* services/core/java/com/android/server/wm/Session.java
*/
message OverlayStateChanged {
- optional int32 uid = 1;
+ optional int32 uid = 1 [(is_uid) = true];
optional string package_name = 2;
@@ -1409,7 +1416,7 @@
* //frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
*/
message ForegroundServiceStateChanged {
- optional int32 uid = 1;
+ optional int32 uid = 1 [(is_uid) = true];
// package_name + "/" + class_name
optional string short_name = 2;
@@ -1429,6 +1436,7 @@
* frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
*/
message IsolatedUidChanged {
+ // NOTE: DO NOT annotate uid field in this atom. This atom is specially handled in statsd.
// The host UID. Generally, we should attribute metrics from the isolated uid to the host uid.
optional int32 parent_uid = 1;
@@ -1450,7 +1458,7 @@
message PacketWakeupOccurred {
// The uid owning the socket into which the packet was delivered, or -1 if the packet was
// delivered nowhere.
- optional int32 uid = 1;
+ optional int32 uid = 1 [(is_uid) = true];
// The interface name on which the packet was received.
optional string iface = 2;
// The ethertype value of the packet.
@@ -1478,7 +1486,7 @@
*/
message AppStartMemoryStateCaptured {
// The uid if available. -1 means not available.
- optional int32 uid = 1;
+ optional int32 uid = 1 [(is_uid) = true];
// The process name.
optional string process_name = 2;
@@ -1524,7 +1532,7 @@
*/
message LmkKillOccurred {
// The uid if available. -1 means not available.
- optional int32 uid = 1;
+ optional int32 uid = 1 [(is_uid) = true];
// The process name.
optional string process_name = 2;
@@ -1556,7 +1564,7 @@
*/
message AppDied {
// timestamp(elapsedRealtime) of record creation
- optional uint64 timestamp_millis = 1;
+ optional uint64 timestamp_millis = 1 [(stateFieldOption).option = EXCLUSIVE];
}
//////////////////////////////////////////////////////////////////////
@@ -1570,7 +1578,7 @@
* StatsCompanionService (using BatteryStats to get which interfaces are wifi)
*/
message WifiBytesTransfer {
- optional int32 uid = 1;
+ optional int32 uid = 1 [(is_uid) = true];
optional int64 rx_bytes = 2;
@@ -1588,9 +1596,10 @@
* StatsCompanionService (using BatteryStats to get which interfaces are wifi)
*/
message WifiBytesTransferByFgBg {
- optional int32 uid = 1;
+ optional int32 uid = 1 [(is_uid) = true];
- // 1 denotes foreground and 0 denotes background. This is called Set in NetworkStats.
+ // 1 denotes foreground and 0 denotes background. This is called Set in
+ // NetworkStats.
optional int32 is_foreground = 2;
optional int64 rx_bytes = 3;
@@ -1609,7 +1618,7 @@
* StatsCompanionService (using BatteryStats to get which interfaces are mobile data)
*/
message MobileBytesTransfer {
- optional int32 uid = 1;
+ optional int32 uid = 1 [(is_uid) = true];
optional int64 rx_bytes = 2;
@@ -1627,9 +1636,10 @@
* StatsCompanionService (using BatteryStats to get which interfaces are mobile data)
*/
message MobileBytesTransferByFgBg {
- optional int32 uid = 1;
+ optional int32 uid = 1 [(is_uid) = true];
- // 1 denotes foreground and 0 denotes background. This is called Set in NetworkStats.
+ // 1 denotes foreground and 0 denotes background. This is called Set in
+ // NetworkStats.
optional int32 is_foreground = 2;
optional int64 rx_bytes = 3;
@@ -1648,7 +1658,7 @@
* StatsCompanionService
*/
message BluetoothBytesTransfer {
- optional int32 uid = 1;
+ optional int32 uid = 1 [(is_uid) = true];
optional int64 rx_bytes = 2;
@@ -1708,7 +1718,7 @@
* Note that isolated process uid time should be attributed to host uids.
*/
message CpuTimePerUid {
- optional int32 uid = 1;
+ optional int32 uid = 1 [(is_uid) = true];
optional uint64 user_time_millis = 2;
optional uint64 sys_time_millis = 3;
}
@@ -1719,7 +1729,7 @@
* For each uid, we order the time by descending frequencies.
*/
message CpuTimePerUidFreq {
- optional int32 uid = 1;
+ optional int32 uid = 1 [(is_uid) = true];
optional uint32 freq_index = 2;
optional uint64 time_millis = 3;
}
@@ -1801,7 +1811,7 @@
*/
message ProcessMemoryState {
// The uid if available. -1 means not available.
- optional int32 uid = 1;
+ optional int32 uid = 1 [(is_uid) = true];
// The process name.
optional string process_name = 2;
@@ -1853,7 +1863,7 @@
* The file contains a monotonically increasing count of time for a single boot.
*/
message CpuActiveTime {
- optional int32 uid = 1;
+ optional int32 uid = 1 [(is_uid) = true];
optional uint64 time_millis = 2;
}
@@ -1867,7 +1877,7 @@
* The file contains a monotonically increasing count of time for a single boot.
*/
message CpuClusterTime {
- optional int32 uid = 1;
+ optional int32 uid = 1 [(is_uid) = true];
optional int32 cluster_index = 2;
optional uint64 time_millis = 3;
}
diff --git a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
index 72a00cb..fb0be73 100644
--- a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
+++ b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
@@ -166,6 +166,11 @@
// Round it to the nearest minutes. This is the limit of alarm manager.
// In practice, we should limit it higher.
long roundedIntervalMs = intervalMs/1000/60 * 1000 * 60;
+ // Scheduled pulling should be at least 1 min apart.
+ // This can be lower in cts tests, in which case we round it to 1 min.
+ if (roundedIntervalMs < 60 * 1000) {
+ roundedIntervalMs = 60 * 1000;
+ }
// There is only one alarm for all pulled events. So only set it to the smallest denom.
if (roundedIntervalMs < mCurrentPullingInterval) {
VLOG("Updating pulling interval %ld", intervalMs);
diff --git a/cmds/statsd/src/external/puller_util.cpp b/cmds/statsd/src/external/puller_util.cpp
index 0b0c5c4..ea23623 100644
--- a/cmds/statsd/src/external/puller_util.cpp
+++ b/cmds/statsd/src/external/puller_util.cpp
@@ -112,7 +112,8 @@
VLOG("Unknown pull atom id %d", tagId);
return;
}
- if (android::util::kAtomsWithUidField.find(tagId) == android::util::kAtomsWithUidField.end()) {
+ if (android::util::AtomsInfo::kAtomsWithUidField.find(tagId) ==
+ android::util::AtomsInfo::kAtomsWithUidField.end()) {
VLOG("No uid to merge for atom %d", tagId);
return;
}
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
index 778eb8e..bd8b293 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -134,8 +134,8 @@
uint64_t wrapperToken =
mProto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DATA);
const bool truncateTimestamp =
- android::util::kNotTruncatingTimestampAtomWhiteList.find(event.GetTagId()) ==
- android::util::kNotTruncatingTimestampAtomWhiteList.end();
+ android::util::AtomsInfo::kNotTruncatingTimestampAtomWhiteList.find(event.GetTagId()) ==
+ android::util::AtomsInfo::kNotTruncatingTimestampAtomWhiteList.end();
if (truncateTimestamp) {
mProto->write(FIELD_TYPE_INT64 | FIELD_ID_ELAPSED_TIMESTAMP_NANOS,
(long long)truncateTimestampNsToFiveMinutes(event.GetElapsedTimestampNs()));
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index 55a281e..49034ac 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -195,8 +195,9 @@
protoOutput->end(atomsToken);
}
const bool truncateTimestamp =
- android::util::kNotTruncatingTimestampAtomWhiteList.find(mTagId) ==
- android::util::kNotTruncatingTimestampAtomWhiteList.end();
+ android::util::AtomsInfo::kNotTruncatingTimestampAtomWhiteList.find(
+ mTagId) ==
+ android::util::AtomsInfo::kNotTruncatingTimestampAtomWhiteList.end();
const int64_t wall_clock_ns = truncateTimestamp ?
truncateTimestampNsToFiveMinutes(getWallClockNs()) : getWallClockNs();
for (const auto& atom : bucket.mGaugeAtoms) {
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index 901f500..c6112fd 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -170,9 +170,10 @@
// 1. must not have "stop". must have "dimension"
if (!simplePredicate.has_stop() && simplePredicate.has_dimensions()) {
// TODO: need to check the start atom matcher too.
- auto it = android::util::kStateAtomsFieldOptions.find(simplePredicate.dimensions().field());
+ auto it = android::util::AtomsInfo::kStateAtomsFieldOptions.find(
+ simplePredicate.dimensions().field());
// 2. must be based on a state atom.
- if (it != android::util::kStateAtomsFieldOptions.end()) {
+ if (it != android::util::AtomsInfo::kStateAtomsFieldOptions.end()) {
// 3. dimension must be primary fields + state field IN ORDER
size_t expectedDimensionCount = it->second.primaryFields.size() + 1;
vector<Matcher> dimensions;
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 0b10a35..452225c 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -16,6 +16,8 @@
package android.accessibilityservice;
+import static android.content.pm.PackageManager.FEATURE_FINGERPRINT;
+
import android.annotation.IntDef;
import android.content.ComponentName;
import android.content.Context;
@@ -50,8 +52,6 @@
import java.util.Collections;
import java.util.List;
-import static android.content.pm.PackageManager.FEATURE_FINGERPRINT;
-
/**
* This class describes an {@link AccessibilityService}. The system notifies an
* {@link AccessibilityService} for {@link android.view.accessibility.AccessibilityEvent}s
@@ -410,6 +410,15 @@
public int flags;
/**
+ * Whether or not the service has crashed and is awaiting restart. Only valid from {@link
+ * android.view.accessibility.AccessibilityManager#getEnabledAccessibilityServiceList(int)},
+ * because that is populated from the internal list of running services.
+ *
+ * @hide
+ */
+ public boolean crashed;
+
+ /**
* The component name the accessibility service.
*/
private ComponentName mComponentName;
@@ -757,6 +766,7 @@
parcel.writeInt(feedbackType);
parcel.writeLong(notificationTimeout);
parcel.writeInt(flags);
+ parcel.writeInt(crashed ? 1 : 0);
parcel.writeParcelable(mComponentName, flagz);
parcel.writeParcelable(mResolveInfo, 0);
parcel.writeString(mSettingsActivityName);
@@ -773,6 +783,7 @@
feedbackType = parcel.readInt();
notificationTimeout = parcel.readLong();
flags = parcel.readInt();
+ crashed = parcel.readInt() != 0;
mComponentName = parcel.readParcelable(this.getClass().getClassLoader());
mResolveInfo = parcel.readParcelable(null);
mSettingsActivityName = parcel.readString();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 459a587..1d069bc 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -30,12 +30,15 @@
import android.app.assist.AssistContent;
import android.app.assist.AssistStructure;
import android.app.backup.BackupAgent;
+import android.app.servertransaction.ActivityLifecycleItem;
import android.app.servertransaction.ActivityLifecycleItem.LifecycleState;
+import android.app.servertransaction.ActivityRelaunchItem;
import android.app.servertransaction.ActivityResultItem;
import android.app.servertransaction.ClientTransaction;
import android.app.servertransaction.PendingTransactionActions;
import android.app.servertransaction.PendingTransactionActions.StopInfo;
import android.app.servertransaction.TransactionExecutor;
+import android.app.servertransaction.TransactionExecutorHelper;
import android.content.BroadcastReceiver;
import android.content.ComponentCallbacks2;
import android.content.ComponentName;
@@ -520,6 +523,10 @@
return activityInfo.persistableMode == ActivityInfo.PERSIST_ACROSS_REBOOTS;
}
+ public boolean isVisibleFromServer() {
+ return activity != null && activity.mVisibleFromServer;
+ }
+
public String toString() {
ComponentName componentName = intent != null ? intent.getComponent() : null;
return "ActivityRecord{"
@@ -1797,6 +1804,7 @@
// message is handled.
transaction.recycle();
}
+ // TODO(lifecycler): Recycle locally scheduled transactions.
break;
}
Object obj = msg.obj;
@@ -4034,9 +4042,11 @@
r.setState(ON_PAUSE);
}
+ /** Called from {@link LocalActivityManager}. */
final void performStopActivity(IBinder token, boolean saveState, String reason) {
ActivityClientRecord r = mActivities.get(token);
- performStopActivityInner(r, null, false, saveState, reason);
+ performStopActivityInner(r, null /* stopInfo */, false /* keepShown */, saveState,
+ false /* finalStateRequest */, reason);
}
private static final class ProviderRefCount {
@@ -4068,9 +4078,16 @@
* it the result when it is done, but the window may still be visible.
* For the client, we want to call onStop()/onStart() to indicate when
* the activity's UI visibility changes.
+ * @param r Target activity client record.
+ * @param info Action that will report activity stop to server.
+ * @param keepShown Flag indicating whether the activity is still shown.
+ * @param saveState Flag indicating whether the activity state should be saved.
+ * @param finalStateRequest Flag indicating if this call is handling final lifecycle state
+ * request for a transaction.
+ * @param reason Reason for performing this operation.
*/
private void performStopActivityInner(ActivityClientRecord r, StopInfo info, boolean keepShown,
- boolean saveState, String reason) {
+ boolean saveState, boolean finalStateRequest, String reason) {
if (localLOGV) Slog.v(TAG, "Performing stop of " + r);
if (r != null) {
if (!keepShown && r.stopped) {
@@ -4080,11 +4097,13 @@
// if the activity isn't resumed.
return;
}
- RuntimeException e = new RuntimeException(
- "Performing stop of activity that is already stopped: "
- + r.intent.getComponent().toShortString());
- Slog.e(TAG, e.getMessage(), e);
- Slog.e(TAG, r.getStateString());
+ if (!finalStateRequest) {
+ final RuntimeException e = new RuntimeException(
+ "Performing stop of activity that is already stopped: "
+ + r.intent.getComponent().toShortString());
+ Slog.e(TAG, e.getMessage(), e);
+ Slog.e(TAG, r.getStateString());
+ }
}
// One must first be paused before stopped...
@@ -4177,12 +4196,13 @@
@Override
public void handleStopActivity(IBinder token, boolean show, int configChanges,
- PendingTransactionActions pendingActions, String reason) {
+ PendingTransactionActions pendingActions, boolean finalStateRequest, String reason) {
final ActivityClientRecord r = mActivities.get(token);
r.activity.mConfigChangeFlags |= configChanges;
final StopInfo stopInfo = new StopInfo();
- performStopActivityInner(r, stopInfo, show, true, reason);
+ performStopActivityInner(r, stopInfo, show, true /* saveState */, finalStateRequest,
+ reason);
if (localLOGV) Slog.v(
TAG, "Finishing stop of " + r + ": show=" + show
@@ -4234,7 +4254,8 @@
}
if (!show && !r.stopped) {
- performStopActivityInner(r, null, show, false, "handleWindowVisibility");
+ performStopActivityInner(r, null /* stopInfo */, show, false /* saveState */,
+ false /* finalStateRequest */, "handleWindowVisibility");
} else if (show && r.stopped) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
@@ -4710,14 +4731,25 @@
return;
}
- // TODO(b/73747058): Investigate converting this to use transaction to relaunch.
- handleRelaunchActivityInner(r, 0 /* configChanges */, null /* pendingResults */,
- null /* pendingIntents */, null /* pendingActions */, prevState != ON_RESUME,
- r.overrideConfig, "handleRelaunchActivityLocally");
- // Restore back to the previous state before relaunch if needed.
- if (prevState != r.getLifecycleState()) {
- mTransactionExecutor.cycleToPath(r, prevState);
+ // Initialize a relaunch request.
+ final MergedConfiguration mergedConfiguration = new MergedConfiguration(
+ r.createdConfig != null ? r.createdConfig : mConfiguration,
+ r.overrideConfig);
+ final ActivityRelaunchItem activityRelaunchItem = ActivityRelaunchItem.obtain(
+ null /* pendingResults */, null /* pendingIntents */, 0 /* configChanges */,
+ mergedConfiguration, r.mPreserveWindow);
+ // Make sure to match the existing lifecycle state in the end of the transaction.
+ final ActivityLifecycleItem lifecycleRequest =
+ TransactionExecutorHelper.getLifecycleRequestForCurrentState(r);
+ // Schedule the transaction.
+ final ClientTransaction transaction = ClientTransaction.obtain(this.mAppThread, r.token);
+ transaction.addCallback(activityRelaunchItem);
+ transaction.setLifecycleStateRequest(lifecycleRequest);
+ try {
+ mAppThread.scheduleTransaction(transaction);
+ } catch (RemoteException e) {
+ // Local scheduling
}
}
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 5d0143a..7032a2f 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -27,6 +27,7 @@
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
+import android.view.IWindowManager;
import android.view.InputDevice;
import android.view.InputEvent;
import android.view.MotionEvent;
@@ -308,8 +309,14 @@
return;
}
- mInputForwarder = InputManager.getInstance().createInputForwarder(
- mVirtualDisplay.getDisplay().getDisplayId());
+ final int displayId = mVirtualDisplay.getDisplay().getDisplayId();
+ final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+ try {
+ wm.dontOverrideDisplayInfo(displayId);
+ } catch (RemoteException e) {
+ e.rethrowAsRuntimeException();
+ }
+ mInputForwarder = InputManager.getInstance().createInputForwarder(displayId);
mTaskStackListener = new TaskBackgroundChangeListener();
try {
mActivityManager.registerTaskStackListener(mTaskStackListener);
diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java
index 206495d..961bca2 100644
--- a/core/java/android/app/ClientTransactionHandler.java
+++ b/core/java/android/app/ClientTransactionHandler.java
@@ -78,9 +78,19 @@
public abstract void handleResumeActivity(IBinder token, boolean finalStateRequest,
boolean isForward, String reason);
- /** Stop the activity. */
+ /**
+ * Stop the activity.
+ * @param token Target activity token.
+ * @param show Flag indicating whether activity is still shown.
+ * @param configChanges Activity configuration changes.
+ * @param pendingActions Pending actions to be used on this or later stages of activity
+ * transaction.
+ * @param finalStateRequest Flag indicating if this call is handling final lifecycle state
+ * request for a transaction.
+ * @param reason Reason for performing this operation.
+ */
public abstract void handleStopActivity(IBinder token, boolean show, int configChanges,
- PendingTransactionActions pendingActions, String reason);
+ PendingTransactionActions pendingActions, boolean finalStateRequest, String reason);
/** Report that activity was stopped to server. */
public abstract void reportStop(PendingTransactionActions pendingActions);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 2ac3e23..d8e1c89 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -89,6 +89,7 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
/**
@@ -2599,6 +2600,80 @@
};
/**
+ * @hide
+ */
+ public static boolean areActionsVisiblyDifferent(Notification first, Notification second) {
+ Notification.Action[] firstAs = first.actions;
+ Notification.Action[] secondAs = second.actions;
+ if (firstAs == null && secondAs != null || firstAs != null && secondAs == null) {
+ return true;
+ }
+ if (firstAs != null && secondAs != null) {
+ if (firstAs.length != secondAs.length) {
+ return true;
+ }
+ for (int i = 0; i < firstAs.length; i++) {
+ if (!Objects.equals(firstAs[i].title, secondAs[i].title)) {
+ return true;
+ }
+ RemoteInput[] firstRs = firstAs[i].getRemoteInputs();
+ RemoteInput[] secondRs = secondAs[i].getRemoteInputs();
+ if (firstRs == null) {
+ firstRs = new RemoteInput[0];
+ }
+ if (secondRs == null) {
+ secondRs = new RemoteInput[0];
+ }
+ if (firstRs.length != secondRs.length) {
+ return true;
+ }
+ for (int j = 0; j < firstRs.length; j++) {
+ if (!Objects.equals(firstRs[j].getLabel(), secondRs[j].getLabel())) {
+ return true;
+ }
+ CharSequence[] firstCs = firstRs[i].getChoices();
+ CharSequence[] secondCs = secondRs[i].getChoices();
+ if (firstCs == null) {
+ firstCs = new CharSequence[0];
+ }
+ if (secondCs == null) {
+ secondCs = new CharSequence[0];
+ }
+ if (firstCs.length != secondCs.length) {
+ return true;
+ }
+ for (int k = 0; k < firstCs.length; k++) {
+ if (!Objects.equals(firstCs[k], secondCs[k])) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @hide
+ */
+ public static boolean areStyledNotificationsVisiblyDifferent(Builder first, Builder second) {
+ if (first.getStyle() == null) {
+ return second.getStyle() != null;
+ }
+ if (second.getStyle() == null) {
+ return true;
+ }
+ return first.getStyle().areNotificationsVisiblyDifferent(second.getStyle());
+ }
+
+ /**
+ * @hide
+ */
+ public static boolean areRemoteViewsChanged(Builder first, Builder second) {
+ return !first.usesStandardHeader() || !second.usesStandardHeader();
+ }
+
+ /**
* Parcelling creates multiple copies of objects in {@code extras}. Fix them.
* <p>
* For backwards compatibility {@code extras} holds some references to "real" member data such
@@ -4039,6 +4114,13 @@
}
/**
+ * Returns the style set by {@link #setStyle(Style)}.
+ */
+ public Style getStyle() {
+ return mStyle;
+ }
+
+ /**
* Specify the value of {@link #visibility}.
*
* @return The same Builder.
@@ -5867,6 +5949,11 @@
*/
public void validate(Context context) {
}
+
+ /**
+ * @hide
+ */
+ public abstract boolean areNotificationsVisiblyDifferent(Style other);
}
/**
@@ -5920,6 +6007,13 @@
}
/**
+ * @hide
+ */
+ public Bitmap getBigPicture() {
+ return mPicture;
+ }
+
+ /**
* Provide the bitmap to be used as the payload for the BigPicture notification.
*/
public BigPictureStyle bigPicture(Bitmap b) {
@@ -6059,6 +6153,18 @@
public boolean hasSummaryInHeader() {
return false;
}
+
+ /**
+ * @hide
+ */
+ @Override
+ public boolean areNotificationsVisiblyDifferent(Style other) {
+ if (other == null || getClass() != other.getClass()) {
+ return true;
+ }
+ BigPictureStyle otherS = (BigPictureStyle) other;
+ return !Objects.equals(getBigPicture(), otherS.getBigPicture());
+ }
}
/**
@@ -6122,6 +6228,13 @@
/**
* @hide
*/
+ public CharSequence getBigText() {
+ return mBigText;
+ }
+
+ /**
+ * @hide
+ */
public void addExtras(Bundle extras) {
super.addExtras(extras);
@@ -6191,6 +6304,18 @@
return contentView;
}
+ /**
+ * @hide
+ */
+ @Override
+ public boolean areNotificationsVisiblyDifferent(Style other) {
+ if (other == null || getClass() != other.getClass()) {
+ return true;
+ }
+ BigTextStyle newS = (BigTextStyle) other;
+ return !Objects.equals(getBigText(), newS.getBigText());
+ }
+
static void applyBigTextContentView(Builder builder,
RemoteViews contentView, CharSequence bigTextText) {
contentView.setTextViewText(R.id.big_text, builder.processTextSpans(bigTextText));
@@ -6533,6 +6658,58 @@
return remoteViews;
}
+ /**
+ * @hide
+ */
+ @Override
+ public boolean areNotificationsVisiblyDifferent(Style other) {
+ if (other == null || getClass() != other.getClass()) {
+ return true;
+ }
+ MessagingStyle newS = (MessagingStyle) other;
+ List<MessagingStyle.Message> oldMs = getMessages();
+ List<MessagingStyle.Message> newMs = newS.getMessages();
+
+ if (oldMs == null) {
+ oldMs = new ArrayList<>();
+ }
+ if (newMs == null) {
+ newMs = new ArrayList<>();
+ }
+
+ int n = oldMs.size();
+ if (n != newMs.size()) {
+ return true;
+ }
+ for (int i = 0; i < n; i++) {
+ MessagingStyle.Message oldM = oldMs.get(i);
+ MessagingStyle.Message newM = newMs.get(i);
+ if (!Objects.equals(oldM.getText(), newM.getText())) {
+ return true;
+ }
+ if (!Objects.equals(oldM.getDataUri(), newM.getDataUri())) {
+ return true;
+ }
+ CharSequence oldSender = oldM.getSenderPerson() == null ? oldM.getSender()
+ : oldM.getSenderPerson().getName();
+ CharSequence newSender = newM.getSenderPerson() == null ? newM.getSender()
+ : newM.getSenderPerson().getName();
+ if (!Objects.equals(oldSender, newSender)) {
+ return true;
+ }
+
+ String oldKey = oldM.getSenderPerson() == null
+ ? null : oldM.getSenderPerson().getKey();
+ String newKey = newM.getSenderPerson() == null
+ ? null : newM.getSenderPerson().getKey();
+ if (!Objects.equals(oldKey, newKey)) {
+ return true;
+ }
+ // Other fields (like timestamp) intentionally excluded
+ }
+ return false;
+ }
+
private Message findLatestIncomingMessage() {
return findLatestIncomingMessage(mMessages);
}
@@ -6964,6 +7141,13 @@
/**
* @hide
*/
+ public ArrayList<CharSequence> getLines() {
+ return mTexts;
+ }
+
+ /**
+ * @hide
+ */
public void addExtras(Bundle extras) {
super.addExtras(extras);
@@ -7042,6 +7226,18 @@
return contentView;
}
+ /**
+ * @hide
+ */
+ @Override
+ public boolean areNotificationsVisiblyDifferent(Style other) {
+ if (other == null || getClass() != other.getClass()) {
+ return true;
+ }
+ InboxStyle newS = (InboxStyle) other;
+ return !Objects.equals(getLines(), newS.getLines());
+ }
+
private void handleInboxImageMargin(RemoteViews contentView, int id, boolean first) {
int endMargin = 0;
if (first) {
@@ -7205,6 +7401,18 @@
}
}
+ /**
+ * @hide
+ */
+ @Override
+ public boolean areNotificationsVisiblyDifferent(Style other) {
+ if (other == null || getClass() != other.getClass()) {
+ return true;
+ }
+ // All fields to compare are on the Notification object
+ return false;
+ }
+
private RemoteViews generateMediaActionButton(Action action, int color) {
final boolean tombstone = (action.actionIntent == null);
RemoteViews button = new BuilderRemoteViews(mBuilder.mContext.getApplicationInfo(),
@@ -7414,6 +7622,18 @@
}
remoteViews.setViewLayoutMarginEndDimen(R.id.notification_main_column, endMargin);
}
+
+ /**
+ * @hide
+ */
+ @Override
+ public boolean areNotificationsVisiblyDifferent(Style other) {
+ if (other == null || getClass() != other.getClass()) {
+ return true;
+ }
+ // Comparison done for all custom RemoteViews, independent of style
+ return false;
+ }
}
/**
@@ -7504,6 +7724,18 @@
return makeBigContentViewWithCustomContent(customRemoteView);
}
+ /**
+ * @hide
+ */
+ @Override
+ public boolean areNotificationsVisiblyDifferent(Style other) {
+ if (other == null || getClass() != other.getClass()) {
+ return true;
+ }
+ // Comparison done for all custom RemoteViews, independent of style
+ return false;
+ }
+
private RemoteViews buildIntoRemoteView(RemoteViews remoteViews, int id,
RemoteViews customContent) {
if (customContent != null) {
diff --git a/core/java/android/app/servertransaction/StopActivityItem.java b/core/java/android/app/servertransaction/StopActivityItem.java
index 0a61fab..8db38d3 100644
--- a/core/java/android/app/servertransaction/StopActivityItem.java
+++ b/core/java/android/app/servertransaction/StopActivityItem.java
@@ -39,7 +39,7 @@
PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStop");
client.handleStopActivity(token, mShowWindow, mConfigChanges, pendingActions,
- "STOP_ACTIVITY_ITEM");
+ true /* finalStateRequest */, "STOP_ACTIVITY_ITEM");
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
diff --git a/core/java/android/app/servertransaction/TransactionExecutor.java b/core/java/android/app/servertransaction/TransactionExecutor.java
index 0d995e8..553c3ae 100644
--- a/core/java/android/app/servertransaction/TransactionExecutor.java
+++ b/core/java/android/app/servertransaction/TransactionExecutor.java
@@ -204,7 +204,8 @@
break;
case ON_STOP:
mTransactionHandler.handleStopActivity(r.token, false /* show */,
- 0 /* configChanges */, mPendingActions, "LIFECYCLER_STOP_ACTIVITY");
+ 0 /* configChanges */, mPendingActions, false /* finalStateRequest */,
+ "LIFECYCLER_STOP_ACTIVITY");
break;
case ON_DESTROY:
mTransactionHandler.handleDestroyActivity(r.token, false /* finishing */,
diff --git a/core/java/android/app/servertransaction/TransactionExecutorHelper.java b/core/java/android/app/servertransaction/TransactionExecutorHelper.java
index 7e66fd7..01b13a2 100644
--- a/core/java/android/app/servertransaction/TransactionExecutorHelper.java
+++ b/core/java/android/app/servertransaction/TransactionExecutorHelper.java
@@ -26,7 +26,7 @@
import static android.app.servertransaction.ActivityLifecycleItem.PRE_ON_CREATE;
import static android.app.servertransaction.ActivityLifecycleItem.UNDEFINED;
-import android.app.ActivityThread;
+import android.app.ActivityThread.ActivityClientRecord;
import android.util.IntArray;
import com.android.internal.annotations.VisibleForTesting;
@@ -124,7 +124,7 @@
* {@link ActivityLifecycleItem#UNDEFINED} if there is not path.
*/
@VisibleForTesting
- public int getClosestPreExecutionState(ActivityThread.ActivityClientRecord r,
+ public int getClosestPreExecutionState(ActivityClientRecord r,
int postExecutionState) {
switch (postExecutionState) {
case UNDEFINED:
@@ -147,7 +147,7 @@
* were provided or there is not path.
*/
@VisibleForTesting
- public int getClosestOfStates(ActivityThread.ActivityClientRecord r, int[] finalStates) {
+ public int getClosestOfStates(ActivityClientRecord r, int[] finalStates) {
if (finalStates == null || finalStates.length == 0) {
return UNDEFINED;
}
@@ -168,6 +168,27 @@
return closestState;
}
+ /** Get the lifecycle state request to match the current state in the end of a transaction. */
+ public static ActivityLifecycleItem getLifecycleRequestForCurrentState(ActivityClientRecord r) {
+ final int prevState = r.getLifecycleState();
+ final ActivityLifecycleItem lifecycleItem;
+ switch (prevState) {
+ // TODO(lifecycler): Extend to support all possible states.
+ case ON_PAUSE:
+ lifecycleItem = PauseActivityItem.obtain();
+ break;
+ case ON_STOP:
+ lifecycleItem = StopActivityItem.obtain(r.isVisibleFromServer(),
+ 0 /* configChanges */);
+ break;
+ default:
+ lifecycleItem = ResumeActivityItem.obtain(false /* isForward */);
+ break;
+ }
+
+ return lifecycleItem;
+ }
+
/**
* Check if there is a destruction involved in the path. We want to avoid a lifecycle sequence
* that involves destruction and recreation if there is another path.
diff --git a/core/java/android/app/slice/SliceMetrics.java b/core/java/android/app/slice/SliceMetrics.java
new file mode 100644
index 0000000..a7069bc
--- /dev/null
+++ b/core/java/android/app/slice/SliceMetrics.java
@@ -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.
+ */
+
+package android.app.slice;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.net.Uri;
+
+import com.android.internal.logging.MetricsLogger;
+
+/**
+ * Metrics interface for slices.
+ *
+ * This is called by SliceView, so Slice develoers should
+ * not need to reference this class.
+ *
+ * @see androidx.slice.widget.SliceView
+ */
+public class SliceMetrics {
+
+ private static final String TAG = "SliceMetrics";
+ private MetricsLogger mMetricsLogger;
+
+ /**
+ * An object to be used throughout the life of a slice to register events.
+ */
+ public SliceMetrics(@NonNull Context context, @NonNull Uri uri) {
+ mMetricsLogger = new MetricsLogger();
+ }
+
+ /**
+ * To be called whenever the slice becomes visible to the user.
+ */
+ public void logVisible() {
+ }
+
+ /**
+ * To be called whenever the slice becomes invisible to the user.
+ */
+ public void logHidden() {
+ }
+
+ /**
+ * To be called whenever the use interacts with a slice.
+ *@param subSlice The URI of the sub-slice that is the subject of the interaction.
+ */
+ public void logTouch(@NonNull Uri subSlice) {
+ }
+}
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index 4c7e97b..8550ac0 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -81,6 +81,7 @@
* An event type denoting that a package was interacted with in some way by the system.
* @hide
*/
+ @SystemApi
public static final int SYSTEM_INTERACTION = 6;
/**
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index f67ec4a..20248b9 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -679,11 +679,13 @@
}
/**
- * Updates the info for the supplied AppWidget provider.
+ * Updates the info for the supplied AppWidget provider. Apps can use this to change the default
+ * behavior of the widget based on the state of the app (for e.g., if the user is logged in
+ * or not). Calling this API completely replaces the previous definition.
*
* <p>
* The manifest entry of the provider should contain an additional meta-data tag similar to
- * {@link #META_DATA_APPWIDGET_PROVIDER} which should point to any additional definitions for
+ * {@link #META_DATA_APPWIDGET_PROVIDER} which should point to any alternative definitions for
* the provider.
*
* <p>
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index d5b052e..390b83f 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -1242,7 +1242,7 @@
* from the main sensor along the +X axis (to the right from the user's perspective) will
* report <code>(0.03, 0, 0)</code>.</p>
* <p>To transform a pixel coordinates between two cameras facing the same direction, first
- * the source camera {@link CameraCharacteristics#LENS_RADIAL_DISTORTION android.lens.radialDistortion} must be corrected for. Then the source
+ * the source camera {@link CameraCharacteristics#LENS_DISTORTION android.lens.distortion} must be corrected for. Then the source
* camera {@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration} needs to be applied, followed by the
* {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation} of the source camera, the translation of the source camera
* relative to the destination camera, the {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation} of the destination
@@ -1256,10 +1256,10 @@
* <p><b>Units</b>: Meters</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*
+ * @see CameraCharacteristics#LENS_DISTORTION
* @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
* @see CameraCharacteristics#LENS_POSE_REFERENCE
* @see CameraCharacteristics#LENS_POSE_ROTATION
- * @see CameraCharacteristics#LENS_RADIAL_DISTORTION
*/
@PublicKey
public static final Key<float[]> LENS_POSE_TRANSLATION =
@@ -1305,7 +1305,7 @@
* where <code>(0,0)</code> is the top-left of the
* preCorrectionActiveArraySize rectangle. Once the pose and
* intrinsic calibration transforms have been applied to a
- * world point, then the {@link CameraCharacteristics#LENS_RADIAL_DISTORTION android.lens.radialDistortion}
+ * world point, then the {@link CameraCharacteristics#LENS_DISTORTION android.lens.distortion}
* transform needs to be applied, and the result adjusted to
* be in the {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} coordinate
* system (where <code>(0, 0)</code> is the top-left of the
@@ -1318,9 +1318,9 @@
* coordinate system.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*
+ * @see CameraCharacteristics#LENS_DISTORTION
* @see CameraCharacteristics#LENS_POSE_ROTATION
* @see CameraCharacteristics#LENS_POSE_TRANSLATION
- * @see CameraCharacteristics#LENS_RADIAL_DISTORTION
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
* @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
*/
@@ -1362,7 +1362,14 @@
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*
* @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
+ * @deprecated
+ * <p>This field was inconsistently defined in terms of its
+ * normalization. Use {@link CameraCharacteristics#LENS_DISTORTION android.lens.distortion} instead.</p>
+ *
+ * @see CameraCharacteristics#LENS_DISTORTION
+
*/
+ @Deprecated
@PublicKey
public static final Key<float[]> LENS_RADIAL_DISTORTION =
new Key<float[]>("android.lens.radialDistortion", float[].class);
@@ -1387,6 +1394,46 @@
new Key<Integer>("android.lens.poseReference", int.class);
/**
+ * <p>The correction coefficients to correct for this camera device's
+ * radial and tangential lens distortion.</p>
+ * <p>Replaces the deprecated {@link CameraCharacteristics#LENS_RADIAL_DISTORTION android.lens.radialDistortion} field, which was
+ * inconsistently defined.</p>
+ * <p>Three radial distortion coefficients <code>[kappa_1, kappa_2,
+ * kappa_3]</code> and two tangential distortion coefficients
+ * <code>[kappa_4, kappa_5]</code> that can be used to correct the
+ * lens's geometric distortion with the mapping equations:</p>
+ * <pre><code> x_c = x_i * ( 1 + kappa_1 * r^2 + kappa_2 * r^4 + kappa_3 * r^6 ) +
+ * kappa_4 * (2 * x_i * y_i) + kappa_5 * ( r^2 + 2 * x_i^2 )
+ * y_c = y_i * ( 1 + kappa_1 * r^2 + kappa_2 * r^4 + kappa_3 * r^6 ) +
+ * kappa_5 * (2 * x_i * y_i) + kappa_4 * ( r^2 + 2 * y_i^2 )
+ * </code></pre>
+ * <p>Here, <code>[x_c, y_c]</code> are the coordinates to sample in the
+ * input image that correspond to the pixel values in the
+ * corrected image at the coordinate <code>[x_i, y_i]</code>:</p>
+ * <pre><code> correctedImage(x_i, y_i) = sample_at(x_c, y_c, inputImage)
+ * </code></pre>
+ * <p>The pixel coordinates are defined in a coordinate system
+ * related to the {@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration}
+ * calibration fields; see that entry for details of the mapping stages.
+ * Both <code>[x_i, y_i]</code> and <code>[x_c, y_c]</code>
+ * have <code>(0,0)</code> at the lens optical center <code>[c_x, c_y]</code>, and
+ * the range of the coordinates depends on the focal length
+ * terms of the intrinsic calibration.</p>
+ * <p>Finally, <code>r</code> represents the radial distance from the
+ * optical center, <code>r^2 = x_i^2 + y_i^2</code>.</p>
+ * <p>The distortion model used is the Brown-Conrady model.</p>
+ * <p><b>Units</b>:
+ * Unitless coefficients.</p>
+ * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ *
+ * @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
+ * @see CameraCharacteristics#LENS_RADIAL_DISTORTION
+ */
+ @PublicKey
+ public static final Key<float[]> LENS_DISTORTION =
+ new Key<float[]>("android.lens.distortion", float[].class);
+
+ /**
* <p>List of noise reduction modes for {@link CaptureRequest#NOISE_REDUCTION_MODE android.noiseReduction.mode} that are supported
* by this camera device.</p>
* <p>Full-capability camera devices will always support OFF and FAST.</p>
@@ -1418,6 +1465,8 @@
* consideration of future support.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
* @deprecated
+ * <p>Not used in HALv3 or newer; replaced by better partials mechanism</p>
+
* @hide
*/
@Deprecated
@@ -1808,6 +1857,8 @@
* <p>When set to YUV_420_888, application can access the YUV420 data directly.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
* @deprecated
+ * <p>Not used in HALv3 or newer</p>
+
* @hide
*/
@Deprecated
@@ -1828,6 +1879,8 @@
* TODO: Remove property.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
* @deprecated
+ * <p>Not used in HALv3 or newer</p>
+
* @hide
*/
@Deprecated
@@ -1844,6 +1897,8 @@
*
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
* @deprecated
+ * <p>Not used in HALv3 or newer</p>
+
* @hide
*/
@Deprecated
@@ -1883,6 +1938,8 @@
* <p><b>Units</b>: Nanoseconds</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
* @deprecated
+ * <p>Not used in HALv3 or newer</p>
+
* @hide
*/
@Deprecated
@@ -1905,6 +1962,8 @@
* check if it limits the maximum size for image data.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
* @deprecated
+ * <p>Not used in HALv3 or newer</p>
+
* @hide
*/
@Deprecated
@@ -2544,7 +2603,7 @@
* {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.</p>
* <p>The currently supported fields that correct for geometric distortion are:</p>
* <ol>
- * <li>{@link CameraCharacteristics#LENS_RADIAL_DISTORTION android.lens.radialDistortion}.</li>
+ * <li>{@link CameraCharacteristics#LENS_DISTORTION android.lens.distortion}.</li>
* </ol>
* <p>If all of the geometric distortion fields are no-ops, this rectangle will be the same
* as the post-distortion-corrected rectangle given in
@@ -2557,7 +2616,7 @@
* <p><b>Units</b>: Pixel coordinates on the image sensor</p>
* <p>This key is available on all devices.</p>
*
- * @see CameraCharacteristics#LENS_RADIAL_DISTORTION
+ * @see CameraCharacteristics#LENS_DISTORTION
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
* @see CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE
* @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 14c2865..7669c01 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -684,7 +684,7 @@
* <li>{@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation}</li>
* <li>{@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation}</li>
* <li>{@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration}</li>
- * <li>{@link CameraCharacteristics#LENS_RADIAL_DISTORTION android.lens.radialDistortion}</li>
+ * <li>{@link CameraCharacteristics#LENS_DISTORTION android.lens.distortion}</li>
* </ul>
* </li>
* <li>The {@link CameraCharacteristics#DEPTH_DEPTH_IS_EXCLUSIVE android.depth.depthIsExclusive} entry is listed by this device.</li>
@@ -702,12 +702,12 @@
* rate, including depth stall time.</p>
*
* @see CameraCharacteristics#DEPTH_DEPTH_IS_EXCLUSIVE
+ * @see CameraCharacteristics#LENS_DISTORTION
* @see CameraCharacteristics#LENS_FACING
* @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 CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
*/
public static final int REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT = 8;
@@ -826,7 +826,7 @@
* <li>{@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation}</li>
* <li>{@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation}</li>
* <li>{@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration}</li>
- * <li>{@link CameraCharacteristics#LENS_RADIAL_DISTORTION android.lens.radialDistortion}</li>
+ * <li>{@link CameraCharacteristics#LENS_DISTORTION android.lens.distortion}</li>
* </ul>
* </li>
* <li>The SENSOR_INFO_TIMESTAMP_SOURCE of the logical device and physical devices must be
@@ -852,11 +852,11 @@
* not slow down the frame rate of the capture, as long as the minimum frame duration
* of the physical and logical streams are the same.</p>
*
+ * @see CameraCharacteristics#LENS_DISTORTION
* @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 CameraCharacteristics#LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE
* @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
*/
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index d7c5564..b0cbec7 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -2791,8 +2791,10 @@
* <li>{@link #STATISTICS_OIS_DATA_MODE_ON ON}</li>
* </ul></p>
* <p><b>Available values for this device:</b><br>
- * android.Statistics.info.availableOisDataModes</p>
+ * {@link CameraCharacteristics#STATISTICS_INFO_AVAILABLE_OIS_DATA_MODES android.statistics.info.availableOisDataModes}</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ *
+ * @see CameraCharacteristics#STATISTICS_INFO_AVAILABLE_OIS_DATA_MODES
* @see #STATISTICS_OIS_DATA_MODE_OFF
* @see #STATISTICS_OIS_DATA_MODE_ON
*/
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index e84e48f..6331942 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2783,7 +2783,7 @@
* from the main sensor along the +X axis (to the right from the user's perspective) will
* report <code>(0.03, 0, 0)</code>.</p>
* <p>To transform a pixel coordinates between two cameras facing the same direction, first
- * the source camera {@link CameraCharacteristics#LENS_RADIAL_DISTORTION android.lens.radialDistortion} must be corrected for. Then the source
+ * the source camera {@link CameraCharacteristics#LENS_DISTORTION android.lens.distortion} must be corrected for. Then the source
* camera {@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration} needs to be applied, followed by the
* {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation} of the source camera, the translation of the source camera
* relative to the destination camera, the {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation} of the destination
@@ -2797,10 +2797,10 @@
* <p><b>Units</b>: Meters</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*
+ * @see CameraCharacteristics#LENS_DISTORTION
* @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
* @see CameraCharacteristics#LENS_POSE_REFERENCE
* @see CameraCharacteristics#LENS_POSE_ROTATION
- * @see CameraCharacteristics#LENS_RADIAL_DISTORTION
*/
@PublicKey
public static final Key<float[]> LENS_POSE_TRANSLATION =
@@ -2846,7 +2846,7 @@
* where <code>(0,0)</code> is the top-left of the
* preCorrectionActiveArraySize rectangle. Once the pose and
* intrinsic calibration transforms have been applied to a
- * world point, then the {@link CameraCharacteristics#LENS_RADIAL_DISTORTION android.lens.radialDistortion}
+ * world point, then the {@link CameraCharacteristics#LENS_DISTORTION android.lens.distortion}
* transform needs to be applied, and the result adjusted to
* be in the {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} coordinate
* system (where <code>(0, 0)</code> is the top-left of the
@@ -2859,9 +2859,9 @@
* coordinate system.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*
+ * @see CameraCharacteristics#LENS_DISTORTION
* @see CameraCharacteristics#LENS_POSE_ROTATION
* @see CameraCharacteristics#LENS_POSE_TRANSLATION
- * @see CameraCharacteristics#LENS_RADIAL_DISTORTION
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
* @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
*/
@@ -2903,12 +2903,59 @@
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*
* @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
+ * @deprecated
+ * <p>This field was inconsistently defined in terms of its
+ * normalization. Use {@link CameraCharacteristics#LENS_DISTORTION android.lens.distortion} instead.</p>
+ *
+ * @see CameraCharacteristics#LENS_DISTORTION
+
*/
+ @Deprecated
@PublicKey
public static final Key<float[]> LENS_RADIAL_DISTORTION =
new Key<float[]>("android.lens.radialDistortion", float[].class);
/**
+ * <p>The correction coefficients to correct for this camera device's
+ * radial and tangential lens distortion.</p>
+ * <p>Replaces the deprecated {@link CameraCharacteristics#LENS_RADIAL_DISTORTION android.lens.radialDistortion} field, which was
+ * inconsistently defined.</p>
+ * <p>Three radial distortion coefficients <code>[kappa_1, kappa_2,
+ * kappa_3]</code> and two tangential distortion coefficients
+ * <code>[kappa_4, kappa_5]</code> that can be used to correct the
+ * lens's geometric distortion with the mapping equations:</p>
+ * <pre><code> x_c = x_i * ( 1 + kappa_1 * r^2 + kappa_2 * r^4 + kappa_3 * r^6 ) +
+ * kappa_4 * (2 * x_i * y_i) + kappa_5 * ( r^2 + 2 * x_i^2 )
+ * y_c = y_i * ( 1 + kappa_1 * r^2 + kappa_2 * r^4 + kappa_3 * r^6 ) +
+ * kappa_5 * (2 * x_i * y_i) + kappa_4 * ( r^2 + 2 * y_i^2 )
+ * </code></pre>
+ * <p>Here, <code>[x_c, y_c]</code> are the coordinates to sample in the
+ * input image that correspond to the pixel values in the
+ * corrected image at the coordinate <code>[x_i, y_i]</code>:</p>
+ * <pre><code> correctedImage(x_i, y_i) = sample_at(x_c, y_c, inputImage)
+ * </code></pre>
+ * <p>The pixel coordinates are defined in a coordinate system
+ * related to the {@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration}
+ * calibration fields; see that entry for details of the mapping stages.
+ * Both <code>[x_i, y_i]</code> and <code>[x_c, y_c]</code>
+ * have <code>(0,0)</code> at the lens optical center <code>[c_x, c_y]</code>, and
+ * the range of the coordinates depends on the focal length
+ * terms of the intrinsic calibration.</p>
+ * <p>Finally, <code>r</code> represents the radial distance from the
+ * optical center, <code>r^2 = x_i^2 + y_i^2</code>.</p>
+ * <p>The distortion model used is the Brown-Conrady model.</p>
+ * <p><b>Units</b>:
+ * Unitless coefficients.</p>
+ * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ *
+ * @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
+ * @see CameraCharacteristics#LENS_RADIAL_DISTORTION
+ */
+ @PublicKey
+ public static final Key<float[]> LENS_DISTORTION =
+ new Key<float[]>("android.lens.distortion", float[].class);
+
+ /**
* <p>Mode of operation for the noise reduction algorithm.</p>
* <p>The noise reduction algorithm attempts to improve image quality by removing
* excessive noise added by the capture process, especially in dark conditions.</p>
@@ -2981,6 +3028,8 @@
* Optional. Default value is FINAL.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
* @deprecated
+ * <p>Not used in HALv3 or newer</p>
+
* @hide
*/
@Deprecated
@@ -2997,6 +3046,8 @@
* > 0</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
* @deprecated
+ * <p>Not used in HALv3 or newer</p>
+
* @hide
*/
@Deprecated
@@ -3777,6 +3828,8 @@
*
* @see CaptureRequest#COLOR_CORRECTION_GAINS
* @deprecated
+ * <p>Never fully implemented or specified; do not use</p>
+
* @hide
*/
@Deprecated
@@ -3801,6 +3854,8 @@
* regardless of the android.control.* current values.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
* @deprecated
+ * <p>Never fully implemented or specified; do not use</p>
+
* @hide
*/
@Deprecated
@@ -3919,8 +3974,10 @@
* <li>{@link #STATISTICS_OIS_DATA_MODE_ON ON}</li>
* </ul></p>
* <p><b>Available values for this device:</b><br>
- * android.Statistics.info.availableOisDataModes</p>
+ * {@link CameraCharacteristics#STATISTICS_INFO_AVAILABLE_OIS_DATA_MODES android.statistics.info.availableOisDataModes}</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ *
+ * @see CameraCharacteristics#STATISTICS_INFO_AVAILABLE_OIS_DATA_MODES
* @see #STATISTICS_OIS_DATA_MODE_OFF
* @see #STATISTICS_OIS_DATA_MODE_ON
*/
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index b02d48d..c3f23a1 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -225,7 +225,7 @@
* Indicates the Secure Element on which the transaction occurred.
* eSE1...eSEn for Embedded Secure Elements, SIM1...SIMn for UICC, etc.
*/
- public static final String EXTRA_SE_NAME = "android.nfc.extra.SE_NAME";
+ public static final String EXTRA_SECURE_ELEMENT_NAME = "android.nfc.extra.SECURE_ELEMENT_NAME";
public static final int STATE_OFF = 1;
public static final int STATE_TURNING_ON = 2;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 79b6ea6..2fe211a 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -83,7 +83,6 @@
import android.util.ArraySet;
import android.util.Log;
import android.util.MemoryIntArray;
-import android.util.StatsLog;
import android.view.textservice.TextServicesManager;
import com.android.internal.annotations.GuardedBy;
@@ -1942,11 +1941,7 @@
arg.putBoolean(CALL_METHOD_MAKE_DEFAULT_KEY, true);
}
IContentProvider cp = mProviderHolder.getProvider(cr);
- String prevValue = getStringForUser(cr, name, userHandle);
cp.call(cr.getPackageName(), mCallSetCommand, name, arg);
- String newValue = getStringForUser(cr, name, userHandle);
- StatsLog.write(StatsLog.SETTING_CHANGED, name, value, newValue, prevValue, tag,
- makeDefault, userHandle);
} catch (RemoteException e) {
Log.w(TAG, "Can't set key " + name + " in " + mUri, e);
return false;
@@ -9541,6 +9536,12 @@
public static final String BLE_SCAN_LOW_LATENCY_INTERVAL_MS =
"ble_scan_low_latency_interval_ms";
+ /**
+ * The mode that BLE scanning clients will be moved to when in the background.
+ * @hide
+ */
+ public static final String BLE_SCAN_BACKGROUND_MODE = "ble_scan_background_mode";
+
/**
* Used to save the Wifi_ON state prior to tethering.
* This state will be checked to restore Wifi after
@@ -12326,6 +12327,16 @@
"zram_enabled";
/**
+ * Whether we have enable CPU frequency scaling for this device.
+ * For Wear, default is disable.
+ *
+ * The value is "1" for enable, "0" for disable.
+ * @hide
+ */
+ public static final String CPU_SCALING_ENABLED =
+ "cpu_frequency_scaling_enabled";
+
+ /**
* Configuration flags for smart replies in notifications.
* This is encoded as a key=value list, separated by commas. Ex:
*
diff --git a/core/java/android/security/keystore/recovery/KeyDerivationParams.java b/core/java/android/security/keystore/recovery/KeyDerivationParams.java
index ef5e90c..428eaaa 100644
--- a/core/java/android/security/keystore/recovery/KeyDerivationParams.java
+++ b/core/java/android/security/keystore/recovery/KeyDerivationParams.java
@@ -37,25 +37,26 @@
@SystemApi
public final class KeyDerivationParams implements Parcelable {
private final int mAlgorithm;
- private byte[] mSalt;
+ private final byte[] mSalt;
+ private final int mDifficulty;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = {"ALGORITHM_"}, value = {ALGORITHM_SHA256, ALGORITHM_ARGON2ID})
+ @IntDef(prefix = {"ALGORITHM_"}, value = {ALGORITHM_SHA256, ALGORITHM_SCRYPT})
public @interface KeyDerivationAlgorithm {
}
/**
- * Salted SHA256
+ * Salted SHA256.
*/
public static final int ALGORITHM_SHA256 = 1;
/**
- * Argon2ID
+ * SCRYPT.
+ *
* @hide
*/
- // TODO: add Argon2ID support.
- public static final int ALGORITHM_ARGON2ID = 2;
+ public static final int ALGORITHM_SCRYPT = 2;
/**
* Creates instance of the class to to derive key using salted SHA256 hash.
@@ -65,12 +66,30 @@
}
/**
+ * Creates instance of the class to to derive key using the password hashing algorithm SCRYPT.
+ *
+ * @hide
+ */
+ public static KeyDerivationParams createScryptParams(@NonNull byte[] salt, int difficulty) {
+ return new KeyDerivationParams(ALGORITHM_SCRYPT, salt, difficulty);
+ }
+
+ /**
* @hide
*/
// TODO: Make private once legacy API is removed
public KeyDerivationParams(@KeyDerivationAlgorithm int algorithm, @NonNull byte[] salt) {
+ this(algorithm, salt, /*difficulty=*/ 0);
+ }
+
+ /**
+ * @hide
+ */
+ KeyDerivationParams(@KeyDerivationAlgorithm int algorithm, @NonNull byte[] salt,
+ int difficulty) {
mAlgorithm = algorithm;
mSalt = Preconditions.checkNotNull(salt);
+ mDifficulty = difficulty;
}
/**
@@ -87,6 +106,15 @@
return mSalt;
}
+ /**
+ * Gets hashing difficulty.
+ *
+ * @hide
+ */
+ public int getDifficulty() {
+ return mDifficulty;
+ }
+
public static final Parcelable.Creator<KeyDerivationParams> CREATOR =
new Parcelable.Creator<KeyDerivationParams>() {
public KeyDerivationParams createFromParcel(Parcel in) {
@@ -102,6 +130,7 @@
public void writeToParcel(Parcel out, int flags) {
out.writeInt(mAlgorithm);
out.writeByteArray(mSalt);
+ out.writeInt(mDifficulty);
}
/**
@@ -110,6 +139,7 @@
protected KeyDerivationParams(Parcel in) {
mAlgorithm = in.readInt();
mSalt = in.createByteArray();
+ mDifficulty = in.readInt();
}
@Override
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 740a387..3830b7a 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -97,7 +97,7 @@
private static final int DEFAULT_SUPPRESSED_VISUAL_EFFECTS =
Policy.getAllSuppressedVisualEffects();
- public static final int XML_VERSION = 5;
+ public static final int XML_VERSION = 6;
public static final String ZEN_TAG = "zen";
private static final String ZEN_ATT_VERSION = "version";
private static final String ZEN_ATT_USER = "user";
@@ -516,11 +516,17 @@
throw new IllegalStateException("Failed to reach END_DOCUMENT");
}
- public void writeXml(XmlSerializer out) throws IOException {
+ /**
+ * Writes XML of current ZenModeConfig
+ * @param out serializer
+ * @param version uses XML_VERSION if version is null
+ * @throws IOException
+ */
+ public void writeXml(XmlSerializer out, Integer version) throws IOException {
out.startTag(null, ZEN_TAG);
- out.attribute(null, ZEN_ATT_VERSION, Integer.toString(XML_VERSION));
+ out.attribute(null, ZEN_ATT_VERSION, version == null
+ ? Integer.toString(XML_VERSION) : Integer.toString(version));
out.attribute(null, ZEN_ATT_USER, Integer.toString(user));
-
out.startTag(null, ALLOW_TAG);
out.attribute(null, ALLOW_ATT_CALLS, Boolean.toString(allowCalls));
out.attribute(null, ALLOW_ATT_REPEAT_CALLERS, Boolean.toString(allowRepeatCallers));
diff --git a/core/java/android/util/DebugUtils.java b/core/java/android/util/DebugUtils.java
index c44f42b..46e3169 100644
--- a/core/java/android/util/DebugUtils.java
+++ b/core/java/android/util/DebugUtils.java
@@ -219,7 +219,7 @@
&& field.getType().equals(int.class) && field.getName().startsWith(prefix)) {
try {
if (value == field.getInt(null)) {
- return field.getName().substring(prefix.length());
+ return constNameWithoutPrefix(prefix, field);
}
} catch (IllegalAccessException ignored) {
}
@@ -236,6 +236,7 @@
*/
public static String flagsToString(Class<?> clazz, String prefix, int flags) {
final StringBuilder res = new StringBuilder();
+ boolean flagsWasZero = flags == 0;
for (Field field : clazz.getDeclaredFields()) {
final int modifiers = field.getModifiers();
@@ -243,9 +244,12 @@
&& field.getType().equals(int.class) && field.getName().startsWith(prefix)) {
try {
final int value = field.getInt(null);
+ if (value == 0 && flagsWasZero) {
+ return constNameWithoutPrefix(prefix, field);
+ }
if ((flags & value) != 0) {
flags &= ~value;
- res.append(field.getName().substring(prefix.length())).append('|');
+ res.append(constNameWithoutPrefix(prefix, field)).append('|');
}
} catch (IllegalAccessException ignored) {
}
@@ -258,4 +262,8 @@
}
return res.toString();
}
+
+ private static String constNameWithoutPrefix(String prefix, Field field) {
+ return field.getName().substring(prefix.length());
+ }
}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 613e6d8..6486230 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -428,4 +428,14 @@
* on the next user activity.
*/
void requestUserActivityNotification();
+
+ /**
+ * Notify WindowManager that it should not override the info in DisplayManager for the specified
+ * display. This can disable letter- or pillar-boxing applied in DisplayManager when the metrics
+ * of the logical display reported from WindowManager do not correspond to the metrics of the
+ * physical display it is based on.
+ *
+ * @param displayId The id of the display.
+ */
+ void dontOverrideDisplayInfo(int displayId);
}
diff --git a/core/java/com/android/internal/util/FunctionalUtils.java b/core/java/com/android/internal/util/FunctionalUtils.java
index 82ac241..d53090b 100644
--- a/core/java/com/android/internal/util/FunctionalUtils.java
+++ b/core/java/com/android/internal/util/FunctionalUtils.java
@@ -17,6 +17,7 @@
package com.android.internal.util;
import android.os.RemoteException;
+import android.util.ExceptionUtils;
import java.util.function.Consumer;
import java.util.function.Supplier;
@@ -36,21 +37,45 @@
}
/**
- *
+ * Wraps a given {@code action} into one that ignores any {@link RemoteException}s
*/
public static <T> Consumer<T> ignoreRemoteException(RemoteExceptionIgnoringConsumer<T> action) {
return action;
}
/**
+ * Wraps the given {@link ThrowingRunnable} into one that handles any exceptions using the
+ * provided {@code handler}
+ */
+ public static Runnable handleExceptions(ThrowingRunnable r, Consumer<Throwable> handler) {
+ return () -> {
+ try {
+ r.run();
+ } catch (Throwable t) {
+ handler.accept(t);
+ }
+ };
+ }
+
+ /**
* An equivalent of {@link Runnable} that allows throwing checked exceptions
*
* This can be used to specify a lambda argument without forcing all the checked exceptions
* to be handled within it
*/
@FunctionalInterface
- public interface ThrowingRunnable {
+ @SuppressWarnings("FunctionalInterfaceMethodChanged")
+ public interface ThrowingRunnable extends Runnable {
void runOrThrow() throws Exception;
+
+ @Override
+ default void run() {
+ try {
+ runOrThrow();
+ } catch (Exception ex) {
+ throw ExceptionUtils.propagate(ex);
+ }
+ }
}
/**
@@ -80,7 +105,7 @@
try {
acceptOrThrow(t);
} catch (Exception ex) {
- throw new RuntimeException(ex);
+ throw ExceptionUtils.propagate(ex);
}
}
}
diff --git a/core/jni/android/graphics/pdf/PdfRenderer.cpp b/core/jni/android/graphics/pdf/PdfRenderer.cpp
index d20c7ef..32ac30f 100644
--- a/core/jni/android/graphics/pdf/PdfRenderer.cpp
+++ b/core/jni/android/graphics/pdf/PdfRenderer.cpp
@@ -92,20 +92,7 @@
renderFlags |= FPDF_PRINTING;
}
- // PDF's coordinate system origin is left-bottom while in graphics it
- // is the top-left. So, translate the PDF coordinates to ours.
- SkMatrix reflectOnX = SkMatrix::MakeScale(1, -1);
- SkMatrix moveUp = SkMatrix::MakeTrans(0, FPDF_GetPageHeight(page));
- SkMatrix coordinateChange = SkMatrix::Concat(moveUp, reflectOnX);
-
- // Apply the transformation
- SkMatrix matrix;
- if (transformPtr == 0) {
- matrix = coordinateChange;
- } else {
- matrix = SkMatrix::Concat(*reinterpret_cast<SkMatrix*>(transformPtr), coordinateChange);
- }
-
+ SkMatrix matrix = *reinterpret_cast<SkMatrix*>(transformPtr);
SkScalar transformValues[6];
if (!matrix.asAffine(transformValues)) {
jniThrowException(env, "java/lang/IllegalArgumentException",
diff --git a/core/proto/android/service/graphicsstats.proto b/core/proto/android/service/graphicsstats.proto
index f422065..c2fedf5 100644
--- a/core/proto/android/service/graphicsstats.proto
+++ b/core/proto/android/service/graphicsstats.proto
@@ -56,7 +56,7 @@
// Number of "missed vsync" events.
optional int32 missed_vsync_count = 3;
- // Number of "high input latency" events.
+ // Number of frames in triple-buffering scenario (high input latency)
optional int32 high_input_latency_count = 4;
// Number of "slow UI thread" events.
@@ -67,6 +67,9 @@
// Number of "slow draw" events.
optional int32 slow_draw_count = 7;
+
+ // Number of frames that missed their deadline (aka, visibly janked)
+ optional int32 missed_deadline_count = 8;
}
message GraphicsStatsHistogramBucketProto {
diff --git a/core/proto/android/service/notification.proto b/core/proto/android/service/notification.proto
index 5c40e5f..cccd2fe 100644
--- a/core/proto/android/service/notification.proto
+++ b/core/proto/android/service/notification.proto
@@ -93,7 +93,8 @@
message ServiceProto {
option (android.msg_privacy).dest = DEST_AUTOMATIC;
- repeated string name = 1 [ (.android.privacy).dest = DEST_EXPLICIT ];
+ // Package or component name.
+ repeated string name = 1;
optional int32 user_id = 2;
optional bool is_primary = 3;
}
@@ -169,16 +170,16 @@
message ZenRuleProto {
option (android.msg_privacy).dest = DEST_EXPLICIT;
- // Required for automatic (unique).
+ // Required for automatic ZenRules (unique).
optional string id = 1;
- // Required for automatic.
+ // Required for automatic ZenRules.
optional string name = 2;
- // Required for automatic.
+ // Required for automatic ZenRules.
optional int64 creation_time_ms = 3 [
(android.privacy).dest = DEST_AUTOMATIC
];
optional bool enabled = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
- // Package name, only used for manual rules.
+ // Package name, only used for manual ZenRules.
optional string enabler = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
// User manually disabled this instance.
optional bool is_snoozing = 6 [
@@ -188,7 +189,7 @@
(android.privacy).dest = DEST_AUTOMATIC
];
- // Required for automatic.
+ // Required for automatic ZenRules.
optional string condition_id = 8;
optional ConditionProto condition = 9;
optional android.content.ComponentNameProto component = 10;
diff --git a/core/res/res/layout/shutdown_dialog.xml b/core/res/res/layout/shutdown_dialog.xml
index 398bfb1..2d214b3 100644
--- a/core/res/res/layout/shutdown_dialog.xml
+++ b/core/res/res/layout/shutdown_dialog.xml
@@ -29,7 +29,7 @@
<TextView
android:id="@id/text1"
android:layout_width="wrap_content"
- android:layout_height="32dp"
+ android:layout_height="32sp"
android:text="@string/shutdown_progress"
android:textDirection="locale"
android:textSize="24sp"
diff --git a/core/res/res/xml/default_zen_mode_config.xml b/core/res/res/xml/default_zen_mode_config.xml
index 2d3cd1c..f1b61a7 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="5">
+<zen version="6">
<allow alarms="true" media="true" system="false" calls="false" messages="false" reminders="false"
events="false" />
<!-- all visual effects that exist as of P -->
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index 4628aa9..a99e139 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -22,6 +22,7 @@
import android.app.servertransaction.ClientTransaction;
import android.app.servertransaction.ClientTransactionItem;
import android.app.servertransaction.ResumeActivityItem;
+import android.app.servertransaction.StopActivityItem;
import android.content.Intent;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.MediumTest;
@@ -34,6 +35,8 @@
/**
* Test for verifying {@link android.app.ActivityThread} class.
+ * Build/Install/Run:
+ * atest FrameworksCoreTests:android.app.activity.ActivityThreadTest
*/
@RunWith(AndroidJUnit4.class)
@MediumTest
@@ -63,15 +66,23 @@
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
+ @Test
+ public void testSleepAndStop() throws Exception {
+ final Activity activity = mActivityTestRule.launchActivity(new Intent());
+ final IApplicationThread appThread = activity.getActivityThread().getApplicationThread();
+
+ appThread.scheduleSleeping(activity.getActivityToken(), true /* sleeping */);
+ appThread.scheduleTransaction(newStopTransaction(activity));
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ }
+
private static ClientTransaction newRelaunchResumeTransaction(Activity activity) {
final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(null,
- null, 0, new MergedConfiguration(),
- false /* preserveWindow */);
+ null, 0, new MergedConfiguration(), false /* preserveWindow */);
final ResumeActivityItem resumeStateRequest =
ResumeActivityItem.obtain(true /* isForward */);
- final IApplicationThread appThread = activity.getActivityThread().getApplicationThread();
- final ClientTransaction transaction =
- ClientTransaction.obtain(appThread, activity.getActivityToken());
+
+ final ClientTransaction transaction = newTransaction(activity);
transaction.addCallback(callbackItem);
transaction.setLifecycleStateRequest(resumeStateRequest);
@@ -81,14 +92,28 @@
private static ClientTransaction newResumeTransaction(Activity activity) {
final ResumeActivityItem resumeStateRequest =
ResumeActivityItem.obtain(true /* isForward */);
- final IApplicationThread appThread = activity.getActivityThread().getApplicationThread();
- final ClientTransaction transaction =
- ClientTransaction.obtain(appThread, activity.getActivityToken());
+
+ final ClientTransaction transaction = newTransaction(activity);
transaction.setLifecycleStateRequest(resumeStateRequest);
return transaction;
}
+ private static ClientTransaction newStopTransaction(Activity activity) {
+ final StopActivityItem stopStateRequest =
+ StopActivityItem.obtain(false /* showWindow */, 0 /* configChanges */);
+
+ final ClientTransaction transaction = newTransaction(activity);
+ transaction.setLifecycleStateRequest(stopStateRequest);
+
+ return transaction;
+ }
+
+ private static ClientTransaction newTransaction(Activity activity) {
+ final IApplicationThread appThread = activity.getActivityThread().getApplicationThread();
+ return ClientTransaction.obtain(appThread, activity.getActivityToken());
+ }
+
// Test activity
public static class TestActivity extends Activity {
}
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index cc36b96..38716f4 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -129,6 +129,7 @@
Settings.Global.BLE_SCAN_BALANCED_INTERVAL_MS,
Settings.Global.BLE_SCAN_LOW_LATENCY_WINDOW_MS,
Settings.Global.BLE_SCAN_LOW_LATENCY_INTERVAL_MS,
+ Settings.Global.BLE_SCAN_BACKGROUND_MODE,
Settings.Global.BLUETOOTH_A2DP_SINK_PRIORITY_PREFIX,
Settings.Global.BLUETOOTH_A2DP_SRC_PRIORITY_PREFIX,
Settings.Global.BLUETOOTH_A2DP_SUPPORTS_OPTIONAL_CODECS_PREFIX,
@@ -169,6 +170,7 @@
Settings.Global.CONNECTIVITY_SAMPLING_INTERVAL_IN_SECONDS,
Settings.Global.CONTACT_METADATA_SYNC_ENABLED,
Settings.Global.CONTACTS_DATABASE_WAL_ENABLED,
+ Settings.Global.CPU_SCALING_ENABLED,
Settings.Global.DATA_ACTIVITY_TIMEOUT_MOBILE,
Settings.Global.DATA_ACTIVITY_TIMEOUT_WIFI,
Settings.Global.DATABASE_CREATION_BUILDID,
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index b455419..c6a6113 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -325,6 +325,7 @@
<permission name="android.permission.SET_TIME"/>
<permission name="android.permission.SET_TIME_ZONE"/>
<permission name="android.permission.SIGNAL_PERSISTENT_PROCESSES"/>
+ <permission name="android.permission.START_TASKS_FROM_RECENTS" />
<permission name="android.permission.STOP_APP_SWITCHES"/>
<permission name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"/>
<permission name="android.permission.UPDATE_APP_OPS_STATS"/>
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index cf29e43..81a7980 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -38,16 +38,27 @@
namespace uirenderer {
struct Comparison {
+ JankType type;
+ std::function<int64_t(nsecs_t)> computeThreadshold;
FrameInfoIndex start;
FrameInfoIndex end;
};
-static const Comparison COMPARISONS[] = {
- {FrameInfoIndex::IntendedVsync, FrameInfoIndex::Vsync},
- {FrameInfoIndex::OldestInputEvent, FrameInfoIndex::Vsync},
- {FrameInfoIndex::Vsync, FrameInfoIndex::SyncStart},
- {FrameInfoIndex::SyncStart, FrameInfoIndex::IssueDrawCommandsStart},
- {FrameInfoIndex::IssueDrawCommandsStart, FrameInfoIndex::FrameCompleted},
+static const std::array<Comparison, 4> COMPARISONS{
+ Comparison{JankType::kMissedVsync, [](nsecs_t) { return 1; }, FrameInfoIndex::IntendedVsync,
+ FrameInfoIndex::Vsync},
+
+ Comparison{JankType::kSlowUI,
+ [](nsecs_t frameInterval) { return static_cast<int64_t>(.5 * frameInterval); },
+ FrameInfoIndex::Vsync, FrameInfoIndex::SyncStart},
+
+ Comparison{JankType::kSlowSync,
+ [](nsecs_t frameInterval) { return static_cast<int64_t>(.2 * frameInterval); },
+ FrameInfoIndex::SyncStart, FrameInfoIndex::IssueDrawCommandsStart},
+
+ Comparison{JankType::kSlowRT,
+ [](nsecs_t frameInterval) { return static_cast<int64_t>(.75 * frameInterval); },
+ FrameInfoIndex::IssueDrawCommandsStart, FrameInfoIndex::FrameCompleted},
};
// If the event exceeds 10 seconds throw it away, this isn't a jank event
@@ -91,24 +102,10 @@
void JankTracker::setFrameInterval(nsecs_t frameInterval) {
mFrameInterval = frameInterval;
- mThresholds[kMissedVsync] = 1;
- /*
- * Due to interpolation and sample rate differences between the touch
- * panel and the display (example, 85hz touch panel driving a 60hz display)
- * we call high latency 1.5 * frameinterval
- *
- * NOTE: Be careful when tuning this! A theoretical 1,000hz touch panel
- * on a 60hz display will show kOldestInputEvent - kIntendedVsync of being 15ms
- * Thus this must always be larger than frameInterval, or it will fail
- */
- mThresholds[kHighInputLatency] = static_cast<int64_t>(1.5 * frameInterval);
- // Note that these do not add up to 1. This is intentional. It's to deal
- // with variance in values, and should be sort of an upper-bound on what
- // is reasonable to expect.
- mThresholds[kSlowUI] = static_cast<int64_t>(.5 * frameInterval);
- mThresholds[kSlowSync] = static_cast<int64_t>(.2 * frameInterval);
- mThresholds[kSlowRT] = static_cast<int64_t>(.75 * frameInterval);
+ for (auto& comparison : COMPARISONS) {
+ mThresholds[comparison.type] = comparison.computeThreadshold(frameInterval);
+ }
}
void JankTracker::finishFrame(const FrameInfo& frame) {
@@ -129,28 +126,48 @@
totalDuration -= forgiveAmount;
}
}
+
LOG_ALWAYS_FATAL_IF(totalDuration <= 0, "Impossible totalDuration %" PRId64, totalDuration);
mData->reportFrame(totalDuration);
(*mGlobalData)->reportFrame(totalDuration);
- // Keep the fast path as fast as possible.
- if (CC_LIKELY(totalDuration < mFrameInterval)) {
- return;
- }
-
// Only things like Surface.lockHardwareCanvas() are exempt from tracking
- if (frame[FrameInfoIndex::Flags] & EXEMPT_FRAMES_FLAGS) {
+ if (CC_UNLIKELY(frame[FrameInfoIndex::Flags] & EXEMPT_FRAMES_FLAGS)) {
return;
}
- mData->reportJank();
- (*mGlobalData)->reportJank();
+ if (totalDuration > mFrameInterval) {
+ mData->reportJank();
+ (*mGlobalData)->reportJank();
+ }
- for (int i = 0; i < NUM_BUCKETS; i++) {
- int64_t delta = frame.duration(COMPARISONS[i].start, COMPARISONS[i].end);
- if (delta >= mThresholds[i] && delta < IGNORE_EXCEEDING) {
- mData->reportJankType((JankType)i);
- (*mGlobalData)->reportJankType((JankType)i);
+ bool isTripleBuffered = mSwapDeadline > frame[FrameInfoIndex::IntendedVsync];
+
+ mSwapDeadline = std::max(mSwapDeadline + mFrameInterval,
+ frame[FrameInfoIndex::IntendedVsync] + mFrameInterval);
+
+ // If we hit the deadline, cool!
+ if (frame[FrameInfoIndex::FrameCompleted] < mSwapDeadline) {
+ if (isTripleBuffered) {
+ mData->reportJankType(JankType::kHighInputLatency);
+ (*mGlobalData)->reportJankType(JankType::kHighInputLatency);
+ }
+ return;
+ }
+
+ mData->reportJankType(JankType::kMissedDeadline);
+ (*mGlobalData)->reportJankType(JankType::kMissedDeadline);
+
+ // Janked, reset the swap deadline
+ nsecs_t jitterNanos = frame[FrameInfoIndex::FrameCompleted] - frame[FrameInfoIndex::Vsync];
+ nsecs_t lastFrameOffset = jitterNanos % mFrameInterval;
+ mSwapDeadline = frame[FrameInfoIndex::FrameCompleted] - lastFrameOffset + mFrameInterval;
+
+ for (auto& comparison : COMPARISONS) {
+ int64_t delta = frame.duration(comparison.start, comparison.end);
+ if (delta >= mThresholds[comparison.type] && delta < IGNORE_EXCEEDING) {
+ mData->reportJankType(comparison.type);
+ (*mGlobalData)->reportJankType(comparison.type);
}
}
diff --git a/libs/hwui/JankTracker.h b/libs/hwui/JankTracker.h
index dc6a7ff..110211e 100644
--- a/libs/hwui/JankTracker.h
+++ b/libs/hwui/JankTracker.h
@@ -75,6 +75,7 @@
std::array<int64_t, NUM_BUCKETS> mThresholds;
int64_t mFrameInterval;
+ nsecs_t mSwapDeadline;
// The amount of time we will erase from the total duration to account
// for SF vsync offsets with HWC2 blocking dequeueBuffers.
// (Vsync + mDequeueBlockTolerance) is the point at which we expect
diff --git a/libs/hwui/ProfileData.cpp b/libs/hwui/ProfileData.cpp
index b392ecd..f9cf549 100644
--- a/libs/hwui/ProfileData.cpp
+++ b/libs/hwui/ProfileData.cpp
@@ -23,8 +23,7 @@
static const char* JANK_TYPE_NAMES[] = {
"Missed Vsync", "High input latency", "Slow UI thread",
- "Slow bitmap uploads", "Slow issue draw commands",
-};
+ "Slow bitmap uploads", "Slow issue draw commands", "Frame deadline missed"};
// The bucketing algorithm controls so to speak
// If a frame is <= to this it goes in bucket 0
diff --git a/libs/hwui/ProfileData.h b/libs/hwui/ProfileData.h
index 1e688ab..564920b 100644
--- a/libs/hwui/ProfileData.h
+++ b/libs/hwui/ProfileData.h
@@ -33,6 +33,7 @@
kSlowUI,
kSlowSync,
kSlowRT,
+ kMissedDeadline,
// must be last
NUM_BUCKETS,
diff --git a/libs/hwui/service/GraphicsStatsService.cpp b/libs/hwui/service/GraphicsStatsService.cpp
index e0303a8..599226b 100644
--- a/libs/hwui/service/GraphicsStatsService.cpp
+++ b/libs/hwui/service/GraphicsStatsService.cpp
@@ -176,6 +176,8 @@
summary->set_slow_bitmap_upload_count(summary->slow_bitmap_upload_count() +
data->jankTypeCount(kSlowSync));
summary->set_slow_draw_count(summary->slow_draw_count() + data->jankTypeCount(kSlowRT));
+ summary->set_missed_deadline_count(summary->missed_deadline_count()
+ + data->jankTypeCount(kMissedDeadline));
bool creatingHistogram = false;
if (proto->histogram_size() == 0) {
@@ -246,6 +248,7 @@
dprintf(fd, "\nNumber Slow UI thread: %d", summary.slow_ui_thread_count());
dprintf(fd, "\nNumber Slow bitmap uploads: %d", summary.slow_bitmap_upload_count());
dprintf(fd, "\nNumber Slow issue draw commands: %d", summary.slow_draw_count());
+ dprintf(fd, "\nNumber Frame deadline missed: %d", summary.missed_deadline_count());
dprintf(fd, "\nHISTOGRAM:");
for (const auto& it : proto->histogram()) {
dprintf(fd, " %dms=%d", it.render_millis(), it.frame_count());
diff --git a/libs/hwui/tests/common/scenes/JankyScene.cpp b/libs/hwui/tests/common/scenes/JankyScene.cpp
new file mode 100644
index 0000000..f5e6b31
--- /dev/null
+++ b/libs/hwui/tests/common/scenes/JankyScene.cpp
@@ -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.
+ */
+
+#include "TestSceneBase.h"
+
+#include <unistd.h>
+
+class JankyScene;
+
+static TestScene::Registrar _JankyScene(TestScene::Info{
+ "janky",
+ "A scene that intentionally janks just enough to stay in "
+ "triple buffering.",
+ TestScene::simpleCreateScene<JankyScene>});
+
+class JankyScene : public TestScene {
+public:
+ sp<RenderNode> card;
+
+ void createContent(int width, int height, Canvas& canvas) override {
+ card = TestUtils::createNode(0, 0, 200, 200, [](RenderProperties& props, Canvas& canvas) {
+ canvas.drawColor(0xFF0000FF, SkBlendMode::kSrcOver);
+ });
+ canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver); // background
+ canvas.drawRenderNode(card.get());
+ }
+
+ void doFrame(int frameNr) override {
+ int curFrame = frameNr % 150;
+ if (curFrame & 1) {
+ usleep(15000);
+ }
+ // we animate left and top coordinates, which in turn animates width and
+ // height (bottom/right coordinates are fixed)
+ card->mutateStagingProperties().setLeftTop(curFrame, curFrame);
+ card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
+ }
+};
\ No newline at end of file
diff --git a/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java b/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java
index 350b648..8473c06 100644
--- a/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java
@@ -20,6 +20,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.UserHandle;
@@ -50,6 +51,19 @@
return getEnabledServicesFromSettings(context, UserHandle.myUserId());
}
+ public static boolean hasServiceCrashed(String packageName, String serviceName,
+ List<AccessibilityServiceInfo> enabledServiceInfos) {
+ for (int i = 0; i < enabledServiceInfos.size(); i++) {
+ AccessibilityServiceInfo accessibilityServiceInfo = enabledServiceInfos.get(i);
+ final ServiceInfo serviceInfo = enabledServiceInfos.get(i).getResolveInfo().serviceInfo;
+ if (TextUtils.equals(serviceInfo.packageName, packageName)
+ && TextUtils.equals(serviceInfo.name, serviceName)) {
+ return accessibilityServiceInfo.crashed;
+ }
+ }
+ return false;
+ }
+
/**
* @return the set of enabled accessibility services for {@param userId}. If there are no
* services, it returns the unmodifiable {@link Collections#emptySet()}.
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index f6ec6a8..ec25d2d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -416,6 +416,29 @@
}
}
+ /**
+ * Set this device as active device
+ * @return true if at least one profile on this device is set to active, false otherwise
+ */
+ public boolean setActive() {
+ boolean result = false;
+ A2dpProfile a2dpProfile = mProfileManager.getA2dpProfile();
+ if (a2dpProfile != null && isConnectedProfile(a2dpProfile)) {
+ if (a2dpProfile.setActiveDevice(getDevice())) {
+ Log.i(TAG, "OnPreferenceClickListener: A2DP active device=" + this);
+ result = true;
+ }
+ }
+ HeadsetProfile headsetProfile = mProfileManager.getHeadsetProfile();
+ if ((headsetProfile != null) && isConnectedProfile(headsetProfile)) {
+ if (headsetProfile.setActiveDevice(getDevice())) {
+ Log.i(TAG, "OnPreferenceClickListener: Headset active device=" + this);
+ result = true;
+ }
+ }
+ return result;
+ }
+
void refreshName() {
fetchName();
dispatchAttributesChanged();
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 085e112..8f80527 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -176,33 +176,34 @@
@Deprecated
public WifiTracker(Context context, WifiListener wifiListener,
boolean includeSaved, boolean includeScans) {
- this(context, new WifiListenerExecutor(wifiListener),
+ this(context, wifiListener,
context.getSystemService(WifiManager.class),
context.getSystemService(ConnectivityManager.class),
context.getSystemService(NetworkScoreManager.class),
newIntentFilter());
}
- // TODO(Sghuman): Clean up includeSaved and includeScans from all constructors and linked
+ // TODO(sghuman): Clean up includeSaved and includeScans from all constructors and linked
// calling apps once IC window is complete
public WifiTracker(Context context, WifiListener wifiListener,
@NonNull Lifecycle lifecycle, boolean includeSaved, boolean includeScans) {
- this(context, new WifiListenerExecutor(wifiListener),
+ this(context, wifiListener,
context.getSystemService(WifiManager.class),
context.getSystemService(ConnectivityManager.class),
context.getSystemService(NetworkScoreManager.class),
newIntentFilter());
+
lifecycle.addObserver(this);
}
@VisibleForTesting
- WifiTracker(Context context, WifiListenerExecutor wifiListenerExecutor,
+ WifiTracker(Context context, WifiListener wifiListener,
WifiManager wifiManager, ConnectivityManager connectivityManager,
NetworkScoreManager networkScoreManager,
IntentFilter filter) {
mContext = context;
mWifiManager = wifiManager;
- mListener = wifiListenerExecutor;
+ mListener = new WifiListenerExecutor(wifiListener);
mConnectivityManager = connectivityManager;
// check if verbose logging developer option has been turned on or off
@@ -853,8 +854,7 @@
*
* <p>Also logs all callbacks invocations when verbose logging is enabled.
*/
- @VisibleForTesting
- public static class WifiListenerExecutor implements WifiListener {
+ @VisibleForTesting class WifiListenerExecutor implements WifiListener {
private final WifiListener mDelegatee;
@@ -864,27 +864,29 @@
@Override
public void onWifiStateChanged(int state) {
- if (isVerboseLoggingEnabled()) {
- Log.i(TAG,
- String.format("Invoking onWifiStateChanged callback with state %d", state));
- }
- ThreadUtils.postOnMainThread(() -> mDelegatee.onWifiStateChanged(state));
+ runAndLog(() -> mDelegatee.onWifiStateChanged(state),
+ String.format("Invoking onWifiStateChanged callback with state %d", state));
}
@Override
public void onConnectedChanged() {
- if (isVerboseLoggingEnabled()) {
- Log.i(TAG, "Invoking onConnectedChanged callback");
- }
- ThreadUtils.postOnMainThread(() -> mDelegatee.onConnectedChanged());
+ runAndLog(mDelegatee::onConnectedChanged, "Invoking onConnectedChanged callback");
}
@Override
public void onAccessPointsChanged() {
- if (isVerboseLoggingEnabled()) {
- Log.i(TAG, "Invoking onAccessPointsChanged callback");
- }
- ThreadUtils.postOnMainThread(() -> mDelegatee.onAccessPointsChanged());
+ runAndLog(mDelegatee::onAccessPointsChanged, "Invoking onAccessPointsChanged callback");
+ }
+
+ private void runAndLog(Runnable r, String verboseLog) {
+ ThreadUtils.postOnMainThread(() -> {
+ if (mRegistered) {
+ if (isVerboseLoggingEnabled()) {
+ Log.i(TAG, verboseLog);
+ }
+ r.run();
+ }
+ });
}
}
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 7fb4dc5..517db78 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
@@ -58,6 +58,8 @@
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+import com.android.settingslib.utils.ThreadUtils;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -135,7 +137,7 @@
@Mock private RssiCurve mockBadgeCurve1;
@Mock private RssiCurve mockBadgeCurve2;
@Mock private WifiManager mockWifiManager;
- @Mock private WifiTracker.WifiListenerExecutor mockWifiListenerExecutor;
+ @Mock private WifiTracker.WifiListener mockWifiListener;
private final List<NetworkKey> mRequestedKeys = new ArrayList<>();
@@ -205,7 +207,7 @@
mAccessPointsChangedLatch.countDown();
}
return null;
- }).when(mockWifiListenerExecutor).onAccessPointsChanged();
+ }).when(mockWifiListener).onAccessPointsChanged();
// Turn on Scoring UI features
mOriginalScoringUiSettingValue = Settings.Global.getInt(
@@ -271,7 +273,7 @@
private WifiTracker createMockedWifiTracker() {
final WifiTracker wifiTracker = new WifiTracker(
mContext,
- mockWifiListenerExecutor,
+ mockWifiListener,
mockWifiManager,
mockConnectivityManager,
mockNetworkScoreManager,
@@ -690,7 +692,7 @@
verify(mockConnectivityManager).getNetworkInfo(any(Network.class));
// mStaleAccessPoints is true
- verify(mockWifiListenerExecutor, never()).onAccessPointsChanged();
+ verify(mockWifiListener, never()).onAccessPointsChanged();
assertThat(tracker.getAccessPoints().size()).isEqualTo(2);
assertThat(tracker.getAccessPoints().get(0).isActive()).isTrue();
}
@@ -719,7 +721,7 @@
verify(mockConnectivityManager).getNetworkInfo(any(Network.class));
// mStaleAccessPoints is true
- verify(mockWifiListenerExecutor, never()).onAccessPointsChanged();
+ verify(mockWifiListener, never()).onAccessPointsChanged();
assertThat(tracker.getAccessPoints()).hasSize(1);
assertThat(tracker.getAccessPoints().get(0).isActive()).isTrue();
@@ -762,6 +764,41 @@
}
@Test
+ public void stopTrackingShouldPreventCallbacksFromOngoingWork() throws Exception {
+ WifiTracker tracker = createMockedWifiTracker();
+ startTracking(tracker);
+
+ final CountDownLatch ready = new CountDownLatch(1);
+ final CountDownLatch latch = new CountDownLatch(1);
+ final CountDownLatch lock = new CountDownLatch(1);
+ tracker.mWorkHandler.post(() -> {
+ try {
+ ready.countDown();
+ lock.await();
+
+ tracker.mReceiver.onReceive(
+ mContext, new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION));
+
+ latch.countDown();
+ } catch (InterruptedException e) {
+ fail("Interrupted Exception while awaiting lock release: " + e);
+ }
+ });
+
+ ready.await(); // Make sure we have entered the first message handler
+ tracker.onStop();
+ lock.countDown();
+ assertTrue("Latch timed out", latch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
+
+ // Wait for main thread
+ final CountDownLatch latch2 = new CountDownLatch(1);
+ ThreadUtils.postOnMainThread(latch2::countDown);
+ latch2.await();
+
+ verify(mockWifiListener, never()).onWifiStateChanged(anyInt());
+ }
+
+ @Test
public void stopTrackingShouldSetStaleBitWhichPreventsCallbacksUntilNextScanResult()
throws Exception {
WifiTracker tracker = createMockedWifiTracker();
@@ -778,7 +815,7 @@
mContext, new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION));
- verify(mockWifiListenerExecutor, never()).onAccessPointsChanged();
+ verify(mockWifiListener, never()).onAccessPointsChanged();
sendScanResults(tracker); // verifies onAccessPointsChanged is invoked
}
@@ -795,7 +832,7 @@
tracker.mReceiver.onReceive(
mContext, new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION));
- verify(mockWifiListenerExecutor, never()).onAccessPointsChanged();
+ verify(mockWifiListener, never()).onAccessPointsChanged();
sendScanResults(tracker); // verifies onAccessPointsChanged is invoked
}
@@ -816,7 +853,7 @@
@Test
public void onConnectedChangedCallback_shouldNotBeInvokedWhenNoStateChange() throws Exception {
WifiTracker tracker = createTrackerWithScanResultsAndAccessPoint1Connected();
- verify(mockWifiListenerExecutor, times(1)).onConnectedChanged();
+ verify(mockWifiListener, times(1)).onConnectedChanged();
NetworkInfo networkInfo = new NetworkInfo(
ConnectivityManager.TYPE_WIFI, 0, "Type Wifi", "subtype");
@@ -826,13 +863,13 @@
intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, networkInfo);
tracker.mReceiver.onReceive(mContext, intent);
- verify(mockWifiListenerExecutor, times(1)).onConnectedChanged();
+ verify(mockWifiListener, times(1)).onConnectedChanged();
}
@Test
public void onConnectedChangedCallback_shouldBeInvokedWhenStateChanges() throws Exception {
WifiTracker tracker = createTrackerWithScanResultsAndAccessPoint1Connected();
- verify(mockWifiListenerExecutor, times(1)).onConnectedChanged();
+ verify(mockWifiListener, times(1)).onConnectedChanged();
NetworkInfo networkInfo = new NetworkInfo(
ConnectivityManager.TYPE_WIFI, 0, "Type Wifi", "subtype");
@@ -844,7 +881,7 @@
tracker.mReceiver.onReceive(mContext, intent);
assertThat(tracker.isConnected()).isFalse();
- verify(mockWifiListenerExecutor, times(2)).onConnectedChanged();
+ verify(mockWifiListener, times(2)).onConnectedChanged();
}
@Test
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 0775727..632b014 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
@@ -294,4 +294,24 @@
// Verify new alias is returned on getName
assertThat(cachedBluetoothDevice.getName()).isEqualTo(DEVICE_ALIAS_NEW);
}
+
+ @Test
+ public void testSetActive() {
+ when(mProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile);
+ when(mProfileManager.getHeadsetProfile()).thenReturn(mHfpProfile);
+ when(mA2dpProfile.setActiveDevice(any(BluetoothDevice.class))).thenReturn(true);
+ when(mHfpProfile.setActiveDevice(any(BluetoothDevice.class))).thenReturn(true);
+
+ assertThat(mCachedDevice.setActive()).isFalse();
+
+ mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+ assertThat(mCachedDevice.setActive()).isTrue();
+
+ mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
+ mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+ assertThat(mCachedDevice.setActive()).isTrue();
+
+ mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
+ assertThat(mCachedDevice.setActive()).isFalse();
+ }
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 5102cbd..7de54db 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -2938,7 +2938,7 @@
}
private final class UpgradeController {
- private static final int SETTINGS_VERSION = 159;
+ private static final int SETTINGS_VERSION = 160;
private final int mUserId;
@@ -3646,6 +3646,28 @@
currentVersion = 159;
}
+ if (currentVersion == 159) {
+ // Version 160: Hiding notifications from the lockscreen is only available as
+ // primary user option, profiles can only make them redacted. If a profile was
+ // configured to not show lockscreen notifications, ensure that at the very
+ // least these will be come hidden.
+ if (mUserManager.isManagedProfile(userId)) {
+ final SettingsState secureSettings = getSecureSettingsLocked(userId);
+ Setting showNotifications = secureSettings.getSettingLocked(
+ Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS);
+ // The default value is "1", check if user has turned it off.
+ if ("0".equals(showNotifications.getValue())) {
+ secureSettings.insertSettingLocked(
+ Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, "0",
+ null /* tag */, false /* makeDefault */,
+ SettingsState.SYSTEM_PACKAGE_NAME);
+ }
+ // The setting is no longer valid for managed profiles, it should be
+ // treated as if it was set to "1".
+ secureSettings.deleteSettingLocked(Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS);
+ }
+ currentVersion = 160;
+ }
// vXXX: Add new settings above this point.
if (currentVersion != newVersion) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index 6d341c5..449946d 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -42,6 +42,7 @@
import android.util.Base64;
import android.util.Slog;
import android.util.SparseIntArray;
+import android.util.StatsLog;
import android.util.TimeUtils;
import android.util.Xml;
import android.util.proto.ProtoOutputStream;
@@ -386,6 +387,9 @@
mSettings.put(name, newState);
}
+ StatsLog.write(StatsLog.SETTING_CHANGED, name, value, newState.value, oldValue, tag,
+ makeDefault, getUserIdFromKey(mKey), StatsLog.SETTING_CHANGED__REASON__UPDATED);
+
addHistoricalOperationLocked(HISTORICAL_OPERATION_UPDATE, newState);
updateMemoryUsagePerPackageLocked(packageName, oldValue, value,
@@ -410,6 +414,10 @@
Setting oldState = mSettings.remove(name);
+ StatsLog.write(StatsLog.SETTING_CHANGED, name, /* value= */ "", /* newValue= */ "",
+ oldState.value, /* tag */ "", false, getUserIdFromKey(mKey),
+ StatsLog.SETTING_CHANGED__REASON__DELETED);
+
updateMemoryUsagePerPackageLocked(oldState.packageName, oldState.value,
null, oldState.defaultValue, null);
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 589ae2a..b49f1ac 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -121,6 +121,7 @@
<uses-permission android:name="android.permission.MANAGE_APP_OPS_MODES" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
+ <uses-permission android:name="android.permission.START_TASKS_FROM_RECENTS" />
<uses-permission android:name="android.permission.ACTIVITY_EMBEDDING" />
<uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
<uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
diff --git a/packages/SystemUI/res/drawable/ic_lock_lockdown.xml b/packages/SystemUI/res/drawable/ic_lock_lockdown.xml
index b517fc8..65b9813 100644
--- a/packages/SystemUI/res/drawable/ic_lock_lockdown.xml
+++ b/packages/SystemUI/res/drawable/ic_lock_lockdown.xml
@@ -20,6 +20,7 @@
android:viewportHeight="24.0">
<path
- android:fillColor="#757575"
+ android:fillColor="#000000"
+ android:alpha="0.87"
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/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index bf3fa29..c5b3222 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -365,9 +365,6 @@
<!-- Content description of the data connection type GPRS. [CHAR LIMIT=NONE] -->
<string name="data_connection_gprs">GPRS</string>
- <!-- Content description of the data connection type 1x. [CHAR LIMIT=NONE] -->
- <string name="data_connection_1x">1 X</string>
-
<!-- Content description of the data connection type HSPA and its variants. [CHAR LIMIT=NONE] -->
<string name="data_connection_hspa">HSPA</string>
@@ -1853,6 +1850,9 @@
<!-- Label for area where tiles can be dragged in to [CHAR LIMIT=60] -->
<string name="drag_to_remove_tiles">Drag here to remove</string>
+ <!-- Label to indicate to users that additional tiles cannot be removed. [CHAR LIMIT=60] -->
+ <string name="drag_to_remove_disabled">You need at least 6 tiles</string>
+
<!-- Button to edit the tile ordering of quick settings [CHAR LIMIT=60] -->
<string name="qs_edit">Edit</string>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
index 940c9ef..5fa6c79 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
@@ -29,6 +29,8 @@
private IRecentsAnimationController mAnimationController;
+ public RecentsAnimationControllerCompat() { }
+
public RecentsAnimationControllerCompat(IRecentsAnimationController animationController) {
mAnimationController = animationController;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index bdc5e7d..3ba5fe6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -42,19 +42,19 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
import com.android.systemui.R;
-import com.android.systemui.qs.tileimpl.QSIconViewImpl;
+import com.android.systemui.qs.QSTileHost;
import com.android.systemui.qs.customize.TileAdapter.Holder;
import com.android.systemui.qs.customize.TileQueryHelper.TileInfo;
import com.android.systemui.qs.customize.TileQueryHelper.TileStateListener;
import com.android.systemui.qs.external.CustomTile;
-import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.tileimpl.QSIconViewImpl;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import java.util.ArrayList;
import java.util.List;
public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileStateListener {
-
+ private static final int MIN_NUM_TILES = 6;
private static final long DRAG_LENGTH = 100;
private static final float DRAG_SCALE = 1.2f;
public static final long MOVE_DURATION = 150;
@@ -219,9 +219,15 @@
return;
}
if (holder.getItemViewType() == TYPE_EDIT) {
- ((TextView) holder.itemView.findViewById(android.R.id.title)).setText(
- mCurrentDrag != null ? R.string.drag_to_remove_tiles
- : R.string.drag_to_add_tiles);
+ final int titleResId;
+ if (mCurrentDrag == null) {
+ titleResId = R.string.drag_to_add_tiles;
+ } else if (!canRemoveTiles() && mCurrentDrag.getAdapterPosition() < mEditIndex) {
+ titleResId = R.string.drag_to_remove_disabled;
+ } else {
+ titleResId = R.string.drag_to_remove_tiles;
+ }
+ ((TextView) holder.itemView.findViewById(android.R.id.title)).setText(titleResId);
return;
}
if (holder.getItemViewType() == TYPE_ACCESSIBLE_DROP) {
@@ -286,7 +292,7 @@
if (mAccessibilityMoving) {
selectPosition(position, v);
} else {
- if (position < mEditIndex) {
+ if (position < mEditIndex && canRemoveTiles()) {
showAccessibilityDialog(position, v);
} else {
startAccessibleDrag(position);
@@ -297,6 +303,10 @@
}
}
}
+
+ private boolean canRemoveTiles() {
+ return mCurrentSpecs.size() > MIN_NUM_TILES;
+ }
private void selectPosition(int position, View v) {
// Remove the placeholder.
@@ -507,7 +517,7 @@
break;
}
}
- };
+ }
private final ItemTouchHelper.Callback mCallbacks = new ItemTouchHelper.Callback() {
@@ -551,6 +561,9 @@
@Override
public boolean canDropOver(RecyclerView recyclerView, ViewHolder current,
ViewHolder target) {
+ if (!canRemoveTiles() && current.getAdapterPosition() < mEditIndex) {
+ return target.getAdapterPosition() < mEditIndex;
+ }
return target.getAdapterPosition() <= mEditIndex + 1;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
index cc584e7e..ccabb79 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
@@ -389,7 +389,7 @@
* "public" (secure & locked) mode?
*/
private boolean userAllowsNotificationsInPublic(int userHandle) {
- if (userHandle == UserHandle.USER_ALL) {
+ if (isCurrentProfile(userHandle)) {
return true;
}
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 ae55ae8e..739d8d5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -158,6 +158,7 @@
private final WakeLock mWakeLock;
private boolean mWakeLockHeld;
+ private boolean mKeyguardOccluded;
public ScrimController(LightBarController lightBarController, ScrimView scrimBehind,
ScrimView scrimInFront, View headsUpScrim, Consumer<Integer> scrimVisibleListener,
@@ -268,12 +269,13 @@
// AOD wallpapers should fade away after a while
if (mWallpaperSupportsAmbientMode && mDozeParameters.getAlwaysOn()
- && (mState == ScrimState.AOD || mState == ScrimState.PULSING)) {
+ && mState == ScrimState.AOD) {
if (!mWallpaperVisibilityTimedOut) {
mTimeTicker.schedule(mDozeParameters.getWallpaperAodDuration(),
AlarmTimeout.MODE_IGNORE_IF_SCHEDULED);
}
- } else {
+ // Do not re-schedule timeout when pulsing, let's save some extra battery.
+ } else if (mState != ScrimState.PULSING) {
mTimeTicker.cancel();
mWallpaperVisibilityTimedOut = false;
}
@@ -317,7 +319,7 @@
@VisibleForTesting
protected void onHideWallpaperTimeout() {
- if (mState != ScrimState.AOD && mState != ScrimState.PULSING) {
+ if (mState != ScrimState.AOD) {
return;
}
@@ -478,11 +480,13 @@
mLightBarController.setScrimColor(mScrimInFront.getColors());
}
- // We want to override the back scrim opacity for AOD and PULSING
+ // We want to override the back scrim opacity for the AOD state
// when it's time to fade the wallpaper away.
- boolean overrideBackScrimAlpha = (mState == ScrimState.PULSING || mState == ScrimState.AOD)
- && mWallpaperVisibilityTimedOut;
- if (overrideBackScrimAlpha) {
+ boolean aodWallpaperTimeout = mState == ScrimState.AOD && mWallpaperVisibilityTimedOut;
+ // We also want to hide FLAG_SHOW_WHEN_LOCKED activities under the scrim.
+ boolean occludedKeyguard = (mState == ScrimState.PULSING || mState == ScrimState.AOD)
+ && mKeyguardOccluded;
+ if (aodWallpaperTimeout || occludedKeyguard) {
mCurrentBehindAlpha = 1;
}
@@ -926,6 +930,10 @@
mExpansionAffectsAlpha = expansionAffectsAlpha;
}
+ public void setKeyguardOccluded(boolean keyguardOccluded) {
+ mKeyguardOccluded = keyguardOccluded;
+ }
+
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 c92f300..7422a43 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -2040,6 +2040,7 @@
public void setOccluded(boolean occluded) {
mIsOccluded = occluded;
+ mScrimController.setKeyguardOccluded(occluded);
updateHideIconsForBouncer(false /* animate */);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index f088c0b..d32c9a8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -475,6 +475,19 @@
Assert.assertTrue("Should be focusable on keyguard", mScrimInFront.isFocusable());
}
+ @Test
+ public void testHidesShowWhenLockedActivity() {
+ mScrimController.setWallpaperSupportsAmbientMode(true);
+ mScrimController.setKeyguardOccluded(true);
+ mScrimController.transitionTo(ScrimState.AOD);
+ mScrimController.finishAnimationsImmediately();
+ assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_OPAQUE);
+
+ mScrimController.transitionTo(ScrimState.PULSING);
+ mScrimController.finishAnimationsImmediately();
+ assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_OPAQUE);
+ }
+
/**
* Conserves old notification density after leaving state and coming back.
*
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 14baaeb..f13fa4e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -30,6 +30,7 @@
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -547,6 +548,16 @@
verify(mScrimController).transitionTo(eq(ScrimState.UNLOCKED), any());
}
+ @Test
+ public void testSetOccluded_propagatesToScrimController() {
+ mStatusBar.setOccluded(true);
+ verify(mScrimController).setKeyguardOccluded(eq(true));
+
+ reset(mScrimController);
+ mStatusBar.setOccluded(false);
+ verify(mScrimController).setKeyguardOccluded(eq(false));
+ }
+
static class TestableStatusBar extends StatusBar {
public TestableStatusBar(StatusBarKeyguardViewManager man,
UnlockMethodCache unlock, KeyguardIndicationController key,
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index ed068b9..5c5978a 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -88,7 +88,7 @@
final int mId;
- final AccessibilityServiceInfo mAccessibilityServiceInfo;
+ protected final AccessibilityServiceInfo mAccessibilityServiceInfo;
// Lock must match the one used by AccessibilityManagerService
protected final Object mLock;
@@ -340,6 +340,10 @@
}
}
+ public int getCapabilities() {
+ return mAccessibilityServiceInfo.getCapabilities();
+ }
+
int getRelevantEventTypes() {
return (mUsesAccessibilityCache ? AccessibilityCache.CACHE_CRITICAL_EVENTS_MASK : 0)
| mEventTypes;
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index ecd47e8..8941b49 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -621,7 +621,7 @@
for (int i = 0; i < serviceCount; ++i) {
final AccessibilityServiceConnection service = services.get(i);
if ((service.mFeedbackType & feedbackType) != 0) {
- result.add(service.mAccessibilityServiceInfo);
+ result.add(service.getServiceInfo());
}
}
return result;
@@ -1874,7 +1874,7 @@
final int serviceCount = userState.mBoundServices.size();
for (int i = 0; i < serviceCount; i++) {
AccessibilityServiceConnection service = userState.mBoundServices.get(i);
- if ((service.mAccessibilityServiceInfo.getCapabilities()
+ if ((service.getCapabilities()
& AccessibilityServiceInfo.CAPABILITY_CAN_PERFORM_GESTURES) != 0) {
userState.mIsPerformGesturesEnabled = true;
return;
@@ -1888,7 +1888,7 @@
for (int i = 0; i < serviceCount; i++) {
AccessibilityServiceConnection service = userState.mBoundServices.get(i);
if (service.mRequestFilterKeyEvents
- && (service.mAccessibilityServiceInfo.getCapabilities()
+ && (service.getCapabilities()
& AccessibilityServiceInfo
.CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS) != 0) {
userState.mIsFilterKeyEventsEnabled = true;
@@ -2124,7 +2124,7 @@
// Starting in JB-MR2 we request an accessibility service to declare
// certain capabilities in its meta-data to allow it to enable the
// corresponding features.
- if ((service.mAccessibilityServiceInfo.getCapabilities()
+ if ((service.getCapabilities()
& AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION) != 0) {
return true;
}
@@ -3446,22 +3446,22 @@
}
public boolean canRetrieveWindowContentLocked(AbstractAccessibilityServiceConnection service) {
- return (service.mAccessibilityServiceInfo.getCapabilities()
+ return (service.getCapabilities()
& AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT) != 0;
}
public boolean canControlMagnification(AbstractAccessibilityServiceConnection service) {
- return (service.mAccessibilityServiceInfo.getCapabilities()
+ return (service.getCapabilities()
& AccessibilityServiceInfo.CAPABILITY_CAN_CONTROL_MAGNIFICATION) != 0;
}
public boolean canPerformGestures(AccessibilityServiceConnection service) {
- return (service.mAccessibilityServiceInfo.getCapabilities()
+ return (service.getCapabilities()
& AccessibilityServiceInfo.CAPABILITY_CAN_PERFORM_GESTURES) != 0;
}
public boolean canCaptureFingerprintGestures(AccessibilityServiceConnection service) {
- return (service.mAccessibilityServiceInfo.getCapabilities()
+ return (service.getCapabilities()
& AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES) != 0;
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
index 89bf82d..eb18f06 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
@@ -165,7 +165,14 @@
}
}
- public void initializeService() {
+ @Override
+ public AccessibilityServiceInfo getServiceInfo() {
+ // Update crashed data
+ mAccessibilityServiceInfo.crashed = mWasConnectedAndDied;
+ return mAccessibilityServiceInfo;
+ }
+
+ private void initializeService() {
IAccessibilityServiceClient serviceInterface = null;
synchronized (mLock) {
UserState userState = mUserStateWeakReference.get();
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
index 5b5d18f..9f44197 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
@@ -55,7 +55,7 @@
* magnification region. If a value is out of bounds, it will be adjusted to guarantee these
* constraints.
*/
-class MagnificationController implements Handler.Callback {
+public class MagnificationController implements Handler.Callback {
private static final boolean DEBUG = false;
private static final String LOG_TAG = "MagnificationController";
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 755fc54..7f57615 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -1438,11 +1438,25 @@
final AutofillValue filledValue = viewState.getAutofilledValue();
if (!value.equals(filledValue)) {
- if (sDebug) {
- Slog.d(TAG, "found a change on required " + id + ": " + filledValue
- + " => " + value);
+ boolean changed = true;
+ if (filledValue == null) {
+ // Dataset was not autofilled, make sure initial value didn't change.
+ final AutofillValue initialValue = getValueFromContextsLocked(id);
+ if (initialValue != null && initialValue.equals(value)) {
+ if (sDebug) {
+ Slog.d(TAG, "id " + id + " is part of dataset but initial value "
+ + "didn't change: " + value);
+ }
+ changed = false;
+ }
}
- atLeastOneChanged = true;
+ if (changed) {
+ if (sDebug) {
+ Slog.d(TAG, "found a change on required " + id + ": " + filledValue
+ + " => " + value);
+ }
+ atLeastOneChanged = true;
+ }
}
}
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 9ef84d2..c036549 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1649,16 +1649,7 @@
// Check if volume update should be send to Hearing Aid
if ((device & AudioSystem.DEVICE_OUT_HEARING_AID) != 0) {
- synchronized (mHearingAidLock) {
- if (mHearingAid != null) {
- //hearing aid expect volume value in range -128dB to 0dB
- int gainDB = (int)AudioSystem.getStreamVolumeDB(streamType, newIndex/10,
- AudioSystem.DEVICE_OUT_HEARING_AID);
- if (gainDB < BT_HEARING_AID_GAIN_MIN)
- gainDB = BT_HEARING_AID_GAIN_MIN;
- mHearingAid.setVolume(gainDB);
- }
- }
+ setHearingAidVolume(newIndex);
}
// Check if volume update should be sent to Hdmi system audio.
@@ -1907,16 +1898,7 @@
}
if ((device & AudioSystem.DEVICE_OUT_HEARING_AID) != 0) {
- synchronized (mHearingAidLock) {
- if (mHearingAid != null) {
- //hearing aid expect volume value in range -128dB to 0dB
- int gainDB = (int)AudioSystem.getStreamVolumeDB(streamType, index/10, AudioSystem.DEVICE_OUT_HEARING_AID);
- if (gainDB < BT_HEARING_AID_GAIN_MIN)
- gainDB = BT_HEARING_AID_GAIN_MIN;
- mHearingAid.setVolume(gainDB);
-
- }
- }
+ setHearingAidVolume(index);
}
if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
@@ -5624,8 +5606,24 @@
makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address));
}
+ private void setHearingAidVolume(int index) {
+ synchronized (mHearingAidLock) {
+ if (mHearingAid != null) {
+ //hearing aid expect volume value in range -128dB to 0dB
+ int gainDB = (int)AudioSystem.getStreamVolumeDB(AudioSystem.STREAM_MUSIC, index/10,
+ AudioSystem.DEVICE_OUT_HEARING_AID);
+ if (gainDB < BT_HEARING_AID_GAIN_MIN)
+ gainDB = BT_HEARING_AID_GAIN_MIN;
+ mHearingAid.setVolume(gainDB);
+ }
+ }
+ }
+
// must be called synchronized on mConnectedDevices
private void makeHearingAidDeviceAvailable(String address, String name, String eventSource) {
+ int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(AudioSystem.DEVICE_OUT_HEARING_AID);
+ setHearingAidVolume(index);
+
AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_HEARING_AID,
AudioSystem.DEVICE_STATE_AVAILABLE, address, name);
mConnectedDevices.put(
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java
index 8983ec3..bda2ed3 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java
@@ -175,7 +175,7 @@
/**
* The algorithm used to derive cryptographic material from the key and salt. One of
* {@link android.security.keystore.recovery.KeyDerivationParams#ALGORITHM_SHA256} or
- * {@link android.security.keystore.recovery.KeyDerivationParams#ALGORITHM_ARGON2ID}.
+ * {@link android.security.keystore.recovery.KeyDerivationParams#ALGORITHM_SCRYPT}.
*/
static final String COLUMN_NAME_KEY_DERIVATION_ALGORITHM = "key_derivation_algorithm";
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index b911c7b..cd19eb8 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -593,7 +593,7 @@
out.startDocument(null, true);
out.startTag(null, TAG_NOTIFICATION_POLICY);
out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
- mZenModeHelper.writeXml(out, forBackup);
+ mZenModeHelper.writeXml(out, forBackup, null);
mRankingHelper.writeXml(out, forBackup);
mListeners.writeXml(out, forBackup);
mAssistants.writeXml(out, forBackup);
@@ -1294,7 +1294,8 @@
NotificationAssistants notificationAssistants, ConditionProviders conditionProviders,
ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper,
NotificationUsageStats usageStats, AtomicFile policyFile,
- ActivityManager activityManager, GroupHelper groupHelper, IActivityManager am) {
+ ActivityManager activityManager, GroupHelper groupHelper, IActivityManager am,
+ UsageStatsManagerInternal appUsageStats) {
Resources resources = getContext().getResources();
mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
@@ -1307,7 +1308,7 @@
mPackageManagerClient = packageManagerClient;
mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
- mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
+ mAppUsageStats = appUsageStats;
mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
mCompanionManager = companionManager;
mActivityManager = activityManager;
@@ -1449,7 +1450,8 @@
null, snoozeHelper, new NotificationUsageStats(getContext()),
new AtomicFile(new File(systemDir, "notification_policy.xml"), "notification-policy"),
(ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE),
- getGroupHelper(), ActivityManager.getService());
+ getGroupHelper(), ActivityManager.getService(),
+ LocalServices.getService(UsageStatsManagerInternal.class));
// register for various Intents
IntentFilter filter = new IntentFilter();
@@ -4300,6 +4302,7 @@
if (index < 0) {
mNotificationList.add(r);
mUsageStats.registerPostedByApp(r);
+ r.setInterruptive(true);
} else {
old = mNotificationList.get(index);
mNotificationList.set(index, r);
@@ -4310,6 +4313,7 @@
// revoke uri permissions for changed uris
revokeUriPermissions(r, old);
r.isUpdate = true;
+ r.setInterruptive(isVisuallyInterruptive(old, r));
}
mNotificationsByKey.put(n.getKey(), r);
@@ -4376,6 +4380,52 @@
}
/**
+ * If the notification differs enough visually, consider it a new interruptive notification.
+ */
+ @GuardedBy("mNotificationLock")
+ @VisibleForTesting
+ protected boolean isVisuallyInterruptive(NotificationRecord old, NotificationRecord r) {
+ Notification oldN = old.sbn.getNotification();
+ Notification newN = r.sbn.getNotification();
+ if (oldN.extras == null || newN.extras == null) {
+ return false;
+ }
+ if (!Objects.equals(oldN.extras.get(Notification.EXTRA_TITLE),
+ newN.extras.get(Notification.EXTRA_TITLE))) {
+ return true;
+ }
+ if (!Objects.equals(oldN.extras.get(Notification.EXTRA_TEXT),
+ newN.extras.get(Notification.EXTRA_TEXT))) {
+ return true;
+ }
+ if (oldN.extras.containsKey(Notification.EXTRA_PROGRESS) && newN.hasCompletedProgress()) {
+ return true;
+ }
+ // Actions
+ if (Notification.areActionsVisiblyDifferent(oldN, newN)) {
+ return true;
+ }
+
+ try {
+ Notification.Builder oldB = Notification.Builder.recoverBuilder(getContext(), oldN);
+ Notification.Builder newB = Notification.Builder.recoverBuilder(getContext(), newN);
+
+ // Style based comparisons
+ if (Notification.areStyledNotificationsVisiblyDifferent(oldB, newB)) {
+ return true;
+ }
+
+ // Remote views
+ if (Notification.areRemoteViewsChanged(oldB, newB)) {
+ return true;
+ }
+ } catch (Exception e) {
+ Slog.w(TAG, "error recovering builder", e);
+ }
+ return false;
+ }
+
+ /**
* Keeps the last 5 packages that have notified, by user.
*/
@GuardedBy("mNotificationLock")
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index e862530..5c82343 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -56,6 +56,7 @@
import android.service.notification.ZenModeConfig.ZenRule;
import android.service.notification.ZenModeProto;
import android.util.AndroidRuntimeException;
+import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
@@ -234,25 +235,12 @@
config = mDefaultConfig.copy();
config.user = user;
}
- enforceDefaultRulesExist(config);
synchronized (mConfig) {
setConfigLocked(config, reason);
}
cleanUpZenRules();
}
- private void enforceDefaultRulesExist(ZenModeConfig config) {
- for (String id : ZenModeConfig.DEFAULT_RULE_IDS) {
- if (!config.automaticRules.containsKey(id)) {
- if (id.equals(ZenModeConfig.EVENTS_DEFAULT_RULE_ID)) {
- appendDefaultEventRules(config);
- } else if (id.equals(ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID)) {
- appendDefaultEveryNightRule(config);
- }
- }
- }
- }
-
public int getZenModeListenerInterruptionFilter() {
return NotificationManager.zenModeToInterruptionFilter(mZenMode);
}
@@ -623,43 +611,59 @@
public void readXml(XmlPullParser parser, boolean forRestore)
throws XmlPullParserException, IOException {
- final ZenModeConfig config = ZenModeConfig.readXml(parser);
+ ZenModeConfig config = ZenModeConfig.readXml(parser);
+ String reason = "readXml";
+
if (config != null) {
- if (config.version < ZenModeConfig.XML_VERSION || forRestore) {
- Settings.Global.putInt(mContext.getContentResolver(),
- Global.SHOW_ZEN_UPGRADE_NOTIFICATION, 1);
- }
if (forRestore) {
//TODO: http://b/22388012
if (config.user != UserHandle.USER_SYSTEM) {
return;
}
config.manualRule = null; // don't restore the manual rule
- long time = System.currentTimeMillis();
- if (config.automaticRules != null) {
- for (ZenRule automaticRule : config.automaticRules.values()) {
+ }
+
+ boolean resetToDefaultRules = true;
+ long time = System.currentTimeMillis();
+ if (config.automaticRules != null && config.automaticRules.size() > 0) {
+ for (ZenRule automaticRule : config.automaticRules.values()) {
+ if (forRestore) {
// don't restore transient state from restored automatic rules
automaticRule.snoozing = false;
automaticRule.condition = null;
automaticRule.creationTime = time;
}
+ resetToDefaultRules &= !automaticRule.enabled;
}
}
- if (DEBUG) Log.d(TAG, "readXml");
+
+ if (config.version < ZenModeConfig.XML_VERSION || forRestore) {
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Global.SHOW_ZEN_UPGRADE_NOTIFICATION, 1);
+
+ // resets zen automatic rules to default
+ // if all prev auto rules were disabled on update
+ if (resetToDefaultRules) {
+ config.automaticRules = new ArrayMap<>();
+ appendDefaultRules(config);
+ reason += ", reset to default rules";
+ }
+ }
+ if (DEBUG) Log.d(TAG, reason);
synchronized (mConfig) {
- setConfigLocked(config, "readXml");
+ setConfigLocked(config, reason);
}
}
}
- public void writeXml(XmlSerializer out, boolean forBackup) throws IOException {
+ public void writeXml(XmlSerializer out, boolean forBackup, Integer version) throws IOException {
final int N = mConfigs.size();
for (int i = 0; i < N; i++) {
//TODO: http://b/22388012
if (forBackup && mConfigs.keyAt(i) != UserHandle.USER_SYSTEM) {
continue;
}
- mConfigs.valueAt(i).writeXml(out);
+ mConfigs.valueAt(i).writeXml(out, version);
}
}
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index bf85f30..83fe1c9 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -55,6 +55,7 @@
import android.security.Credentials;
import android.service.textclassifier.TextClassifierService;
import android.telephony.TelephonyManager;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
@@ -829,13 +830,11 @@
}
// TextClassifier Service
- ComponentName textClassifierComponent =
- TextClassifierService.getServiceComponentName(mContext);
- if (textClassifierComponent != null) {
- Intent textClassifierServiceIntent = new Intent(TextClassifierService.SERVICE_INTERFACE)
- .setComponent(textClassifierComponent);
+ String textClassifierPackageName =
+ mContext.getPackageManager().getSystemTextClassifierPackageName();
+ if (!TextUtils.isEmpty(textClassifierPackageName)) {
PackageParser.Package textClassifierPackage =
- getDefaultSystemHandlerServicePackage(textClassifierServiceIntent, userId);
+ getSystemPackage(textClassifierPackageName);
if (textClassifierPackage != null
&& doesPackageSupportRuntimePermissions(textClassifierPackage)) {
grantRuntimePermissions(textClassifierPackage, PHONE_PERMISSIONS, true, userId);
diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
index 6053512..6df7092 100644
--- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
+++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
@@ -16,7 +16,9 @@
package com.android.server.textclassifier;
+import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -25,12 +27,14 @@
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
-import android.util.Slog;
-import android.service.textclassifier.ITextClassifierService;
+import android.os.UserHandle;
import android.service.textclassifier.ITextClassificationCallback;
+import android.service.textclassifier.ITextClassifierService;
import android.service.textclassifier.ITextLinksCallback;
import android.service.textclassifier.ITextSelectionCallback;
import android.service.textclassifier.TextClassifierService;
+import android.util.Slog;
+import android.util.SparseArray;
import android.view.textclassifier.SelectionEvent;
import android.view.textclassifier.TextClassification;
import android.view.textclassifier.TextClassifier;
@@ -38,12 +42,13 @@
import android.view.textclassifier.TextSelection;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.FunctionalUtils;
+import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
import com.android.internal.util.Preconditions;
import com.android.server.SystemService;
-import java.util.LinkedList;
+import java.util.ArrayDeque;
import java.util.Queue;
-import java.util.concurrent.Callable;
/**
* A manager for TextClassifier services.
@@ -73,58 +78,44 @@
Slog.e(LOG_TAG, "Could not start the TextClassificationManagerService.", t);
}
}
+
+ @Override
+ public void onStartUser(int userId) {
+ processAnyPendingWork(userId);
+ }
+
+ @Override
+ public void onUnlockUser(int userId) {
+ // Rebind if we failed earlier due to locked encrypted user
+ processAnyPendingWork(userId);
+ }
+
+ private void processAnyPendingWork(int userId) {
+ synchronized (mManagerService.mLock) {
+ mManagerService.getUserStateLocked(userId).bindIfHasPendingRequestsLocked();
+ }
+ }
+
+ @Override
+ public void onStopUser(int userId) {
+ synchronized (mManagerService.mLock) {
+ UserState userState = mManagerService.peekUserStateLocked(userId);
+ if (userState != null) {
+ userState.mConnection.cleanupService();
+ mManagerService.mUserStates.remove(userId);
+ }
+ }
+ }
+
}
private final Context mContext;
- private final Intent mServiceIntent;
- private final ServiceConnection mConnection;
private final Object mLock;
@GuardedBy("mLock")
- private final Queue<PendingRequest> mPendingRequests;
-
- @GuardedBy("mLock")
- private ITextClassifierService mService;
- @GuardedBy("mLock")
- private boolean mBinding;
+ final SparseArray<UserState> mUserStates = new SparseArray<>();
private TextClassificationManagerService(Context context) {
mContext = Preconditions.checkNotNull(context);
- mServiceIntent = new Intent(TextClassifierService.SERVICE_INTERFACE)
- .setComponent(TextClassifierService.getServiceComponentName(mContext));
- mConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- synchronized (mLock) {
- mService = ITextClassifierService.Stub.asInterface(service);
- setBindingLocked(false);
- handlePendingRequestsLocked();
- }
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- cleanupService();
- }
-
- @Override
- public void onBindingDied(ComponentName name) {
- cleanupService();
- }
-
- @Override
- public void onNullBinding(ComponentName name) {
- cleanupService();
- }
-
- private void cleanupService() {
- synchronized (mLock) {
- mService = null;
- setBindingLocked(false);
- handlePendingRequestsLocked();
- }
- }
- };
- mPendingRequests = new LinkedList<>();
mLock = new Object();
}
@@ -133,30 +124,20 @@
CharSequence text, int selectionStartIndex, int selectionEndIndex,
TextSelection.Options options, ITextSelectionCallback callback)
throws RemoteException {
- // TODO(b/72481438): All remote calls need to take userId.
validateInput(text, selectionStartIndex, selectionEndIndex, callback);
- if (!bind()) {
- callback.onFailure();
- return;
- }
-
synchronized (mLock) {
- if (isBoundLocked()) {
- mService.onSuggestSelection(
+ UserState userState = getCallingUserStateLocked();
+ if (!userState.bindLocked()) {
+ callback.onFailure();
+ } else if (userState.isBoundLocked()) {
+ userState.mService.onSuggestSelection(
text, selectionStartIndex, selectionEndIndex, options, callback);
} else {
- final Callable<Void> request = () -> {
- onSuggestSelection(
- text, selectionStartIndex, selectionEndIndex,
- options, callback);
- return null;
- };
- final Callable<Void> onServiceFailure = () -> {
- callback.onFailure();
- return null;
- };
- enqueueRequestLocked(request, onServiceFailure, callback.asBinder());
+ userState.mPendingRequests.add(new PendingRequest(
+ () -> onSuggestSelection(
+ text, selectionStartIndex, selectionEndIndex, options, callback),
+ callback::onFailure, callback.asBinder(), this, userState));
}
}
}
@@ -168,24 +149,16 @@
throws RemoteException {
validateInput(text, startIndex, endIndex, callback);
- if (!bind()) {
- callback.onFailure();
- return;
- }
-
synchronized (mLock) {
- if (isBoundLocked()) {
- mService.onClassifyText(text, startIndex, endIndex, options, callback);
+ UserState userState = getCallingUserStateLocked();
+ if (!userState.bindLocked()) {
+ callback.onFailure();
+ } else if (userState.isBoundLocked()) {
+ userState.mService.onClassifyText(text, startIndex, endIndex, options, callback);
} else {
- final Callable<Void> request = () -> {
- onClassifyText(text, startIndex, endIndex, options, callback);
- return null;
- };
- final Callable<Void> onServiceFailure = () -> {
- callback.onFailure();
- return null;
- };
- enqueueRequestLocked(request, onServiceFailure, callback.asBinder());
+ userState.mPendingRequests.add(new PendingRequest(
+ () -> onClassifyText(text, startIndex, endIndex, options, callback),
+ callback::onFailure, callback.asBinder(), this, userState));
}
}
}
@@ -196,24 +169,16 @@
throws RemoteException {
validateInput(text, callback);
- if (!bind()) {
- callback.onFailure();
- return;
- }
-
synchronized (mLock) {
- if (isBoundLocked()) {
- mService.onGenerateLinks(text, options, callback);
+ UserState userState = getCallingUserStateLocked();
+ if (!userState.bindLocked()) {
+ callback.onFailure();
+ } else if (userState.isBoundLocked()) {
+ userState.mService.onGenerateLinks(text, options, callback);
} else {
- final Callable<Void> request = () -> {
- onGenerateLinks(text, options, callback);
- return null;
- };
- final Callable<Void> onServiceFailure = () -> {
- callback.onFailure();
- return null;
- };
- enqueueRequestLocked(request, onServiceFailure, callback.asBinder());
+ userState.mPendingRequests.add(new PendingRequest(
+ () -> onGenerateLinks(text, options, callback),
+ callback::onFailure, callback.asBinder(), this, userState));
}
}
}
@@ -223,99 +188,63 @@
validateInput(event, mContext);
synchronized (mLock) {
- if (isBoundLocked()) {
- mService.onSelectionEvent(event);
+ UserState userState = getCallingUserStateLocked();
+ if (userState.isBoundLocked()) {
+ userState.mService.onSelectionEvent(event);
} else {
- final Callable<Void> request = () -> {
- onSelectionEvent(event);
- return null;
- };
- enqueueRequestLocked(request, null /* onServiceFailure */, null /* binder */);
+ userState.mPendingRequests.add(new PendingRequest(
+ () -> onSelectionEvent(event),
+ null /* onServiceFailure */, null /* binder */, this, userState));
}
}
}
- /**
- * @return true if the service is bound or in the process of being bound.
- * Returns false otherwise.
- */
- private boolean bind() {
- synchronized (mLock) {
- if (isBoundLocked() || isBindingLocked()) {
- return true;
- }
+ private UserState getCallingUserStateLocked() {
+ return getUserStateLocked(UserHandle.getCallingUserId());
+ }
- // TODO: Handle bind timeout.
- final boolean willBind;
- final long identity = Binder.clearCallingIdentity();
- try {
- Slog.d(LOG_TAG, "Binding to " + mServiceIntent.getComponent());
- willBind = mContext.bindServiceAsUser(
- mServiceIntent, mConnection,
- Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
- Binder.getCallingUserHandle());
- setBindingLocked(willBind);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- return willBind;
+ private UserState getUserStateLocked(int userId) {
+ UserState result = mUserStates.get(userId);
+ if (result == null) {
+ result = new UserState(userId, mContext, mLock);
+ mUserStates.put(userId, result);
}
+ return result;
}
- @GuardedBy("mLock")
- private boolean isBoundLocked() {
- return mService != null;
+ UserState peekUserStateLocked(int userId) {
+ return mUserStates.get(userId);
}
- @GuardedBy("mLock")
- private boolean isBindingLocked() {
- return mBinding;
- }
+ private static final class PendingRequest implements IBinder.DeathRecipient {
- @GuardedBy("mLock")
- private void setBindingLocked(boolean binding) {
- mBinding = binding;
- }
-
- @GuardedBy("mLock")
- private void enqueueRequestLocked(
- Callable<Void> request, Callable<Void> onServiceFailure, IBinder binder) {
- mPendingRequests.add(new PendingRequest(request, onServiceFailure, binder));
- }
-
- @GuardedBy("mLock")
- private void handlePendingRequestsLocked() {
- // TODO(b/72481146): Implement PendingRequest similar to that in RemoteFillService.
- final PendingRequest[] pendingRequests =
- mPendingRequests.toArray(new PendingRequest[mPendingRequests.size()]);
- for (PendingRequest pendingRequest : pendingRequests) {
- if (isBoundLocked()) {
- pendingRequest.executeLocked();
- } else {
- pendingRequest.notifyServiceFailureLocked();
- }
- }
- }
-
- private final class PendingRequest implements IBinder.DeathRecipient {
-
- private final Callable<Void> mRequest;
- @Nullable private final Callable<Void> mOnServiceFailure;
@Nullable private final IBinder mBinder;
+ @NonNull private final Runnable mRequest;
+ @Nullable private final Runnable mOnServiceFailure;
+ @GuardedBy("mLock")
+ @NonNull private final UserState mOwningUser;
+ @NonNull private final TextClassificationManagerService mService;
/**
* Initializes a new pending request.
- *
* @param request action to perform when the service is bound
* @param onServiceFailure action to perform when the service dies or disconnects
* @param binder binder to the process that made this pending request
+ * @param service
+ * @param owningUser
*/
PendingRequest(
- Callable<Void> request, @Nullable Callable<Void> onServiceFailure,
- @Nullable IBinder binder) {
- mRequest = Preconditions.checkNotNull(request);
- mOnServiceFailure = onServiceFailure;
+ @NonNull ThrowingRunnable request, @Nullable ThrowingRunnable onServiceFailure,
+ @Nullable IBinder binder,
+ TextClassificationManagerService service,
+ UserState owningUser) {
+ mRequest =
+ logOnFailure(Preconditions.checkNotNull(request), "handling pending request");
+ mOnServiceFailure =
+ logOnFailure(onServiceFailure, "notifying callback of service failure");
mBinder = binder;
+ mService = service;
+ mOwningUser = owningUser;
if (mBinder != null) {
try {
mBinder.linkToDeath(this, 0);
@@ -325,32 +254,9 @@
}
}
- @GuardedBy("mLock")
- void executeLocked() {
- removeLocked();
- try {
- mRequest.call();
- } catch (Exception e) {
- Slog.d(LOG_TAG, "Error handling pending request: " + e.getMessage());
- }
- }
-
- @GuardedBy("mLock")
- void notifyServiceFailureLocked() {
- removeLocked();
- if (mOnServiceFailure != null) {
- try {
- mOnServiceFailure.call();
- } catch (Exception e) {
- Slog.d(LOG_TAG, "Error notifying callback of service failure: "
- + e.getMessage());
- }
- }
- }
-
@Override
public void binderDied() {
- synchronized (mLock) {
+ synchronized (mService.mLock) {
// No need to handle this pending request anymore. Remove.
removeLocked();
}
@@ -358,13 +264,19 @@
@GuardedBy("mLock")
private void removeLocked() {
- mPendingRequests.remove(this);
+ mOwningUser.mPendingRequests.remove(this);
if (mBinder != null) {
mBinder.unlinkToDeath(this, 0);
}
}
}
+ private static Runnable logOnFailure(@Nullable ThrowingRunnable r, String opDesc) {
+ if (r == null) return null;
+ return FunctionalUtils.handleExceptions(r,
+ e -> Slog.d(LOG_TAG, "Error " + opDesc + ": " + e.getMessage()));
+ }
+
private static void validateInput(
CharSequence text, int startIndex, int endIndex, Object callback)
throws RemoteException {
@@ -396,4 +308,119 @@
throw new RemoteException(e.getMessage());
}
}
+
+ private static final class UserState {
+ @UserIdInt final int mUserId;
+ final TextClassifierServiceConnection mConnection = new TextClassifierServiceConnection();
+ @GuardedBy("mLock")
+ final Queue<PendingRequest> mPendingRequests = new ArrayDeque<>();
+ @GuardedBy("mLock")
+ ITextClassifierService mService;
+ @GuardedBy("mLock")
+ boolean mBinding;
+
+ private final Context mContext;
+ private final Object mLock;
+
+ private UserState(int userId, Context context, Object lock) {
+ mUserId = userId;
+ mContext = Preconditions.checkNotNull(context);
+ mLock = Preconditions.checkNotNull(lock);
+ }
+
+ @GuardedBy("mLock")
+ boolean isBoundLocked() {
+ return mService != null;
+ }
+
+ @GuardedBy("mLock")
+ private void handlePendingRequestsLocked() {
+ // TODO(b/72481146): Implement PendingRequest similar to that in RemoteFillService.
+ PendingRequest request;
+ while ((request = mPendingRequests.poll()) != null) {
+ if (isBoundLocked()) {
+ request.mRequest.run();
+ } else {
+ if (request.mOnServiceFailure != null) {
+ request.mOnServiceFailure.run();
+ }
+ }
+
+ if (request.mBinder != null) {
+ request.mBinder.unlinkToDeath(request, 0);
+ }
+ }
+ }
+
+ private boolean bindIfHasPendingRequestsLocked() {
+ return !mPendingRequests.isEmpty() && bindLocked();
+ }
+
+ /**
+ * @return true if the service is bound or in the process of being bound.
+ * Returns false otherwise.
+ */
+ private boolean bindLocked() {
+ if (isBoundLocked() || mBinding) {
+ return true;
+ }
+
+ // TODO: Handle bind timeout.
+ final boolean willBind;
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ ComponentName componentName =
+ TextClassifierService.getServiceComponentName(mContext);
+ if (componentName == null) {
+ // Might happen if the storage is encrypted and the user is not unlocked
+ return false;
+ }
+ Intent serviceIntent = new Intent(TextClassifierService.SERVICE_INTERFACE)
+ .setComponent(componentName);
+ Slog.d(LOG_TAG, "Binding to " + serviceIntent.getComponent());
+ willBind = mContext.bindServiceAsUser(
+ serviceIntent, mConnection,
+ Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
+ UserHandle.of(mUserId));
+ mBinding = willBind;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ return willBind;
+ }
+
+ private final class TextClassifierServiceConnection implements ServiceConnection {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ init(ITextClassifierService.Stub.asInterface(service));
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ cleanupService();
+ }
+
+ @Override
+ public void onBindingDied(ComponentName name) {
+ cleanupService();
+ }
+
+ @Override
+ public void onNullBinding(ComponentName name) {
+ cleanupService();
+ }
+
+ void cleanupService() {
+ init(null);
+ }
+
+ private void init(@Nullable ITextClassifierService service) {
+ synchronized (mLock) {
+ mService = service;
+ mBinding = false;
+ handlePendingRequestsLocked();
+ }
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index c31cdec..641a1ba 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -1096,10 +1096,7 @@
// Add windows of certain types not covered by modal windows.
if (isReportedWindowType(windowState.mAttrs.type)) {
// Add the window to the ones to be reported.
- WindowInfo window = obtainPopulatedWindowInfo(windowState, boundsInScreen);
- window.layer = addedWindows.size();
- addedWindows.add(window.token);
- windows.add(window);
+ addPopulatedWindowInfo(windowState, boundsInScreen, windows, addedWindows);
if (windowState.isFocused()) {
focusedWindowAdded = true;
}
@@ -1150,10 +1147,8 @@
computeWindowBoundsInScreen(windowState, boundsInScreen);
// Add the window to the ones to be reported.
- WindowInfo window = obtainPopulatedWindowInfo(windowState,
- boundsInScreen);
- addedWindows.add(window.token);
- windows.add(window);
+ addPopulatedWindowInfo(
+ windowState, boundsInScreen, windows, addedWindows);
break;
}
}
@@ -1244,11 +1239,14 @@
(int) windowFrame.right, (int) windowFrame.bottom);
}
- private static WindowInfo obtainPopulatedWindowInfo(
- WindowState windowState, Rect boundsInScreen) {
+ private static void addPopulatedWindowInfo(
+ WindowState windowState, Rect boundsInScreen,
+ List<WindowInfo> out, Set<IBinder> tokenOut) {
final WindowInfo window = windowState.getWindowInfo();
window.boundsInScreen.set(boundsInScreen);
- return window;
+ window.layer = tokenOut.size();
+ out.add(window);
+ tokenOut.add(window.token);
}
private void cacheWindows(List<WindowInfo> windows) {
diff --git a/services/core/java/com/android/server/wm/AnimatingAppWindowTokenRegistry.java b/services/core/java/com/android/server/wm/AnimatingAppWindowTokenRegistry.java
new file mode 100644
index 0000000..ae343da
--- /dev/null
+++ b/services/core/java/com/android/server/wm/AnimatingAppWindowTokenRegistry.java
@@ -0,0 +1,91 @@
+/*
+ * 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.wm;
+
+import android.util.ArrayMap;
+import android.util.ArraySet;
+
+import java.util.ArrayList;
+
+/**
+ * Keeps track of all {@link AppWindowToken} that are animating and makes sure all animations are
+ * finished at the same time such that we don't run into issues with z-ordering: An activity A
+ * that has a shorter animation that is above another activity B with a longer animation in the same
+ * task, the animation layer would put the B on top of A, but from the hierarchy, A needs to be on
+ * top of B. Thus, we defer reparenting A to the original hierarchy such that it stays on top of B
+ * until B finishes animating.
+ */
+class AnimatingAppWindowTokenRegistry {
+
+ private ArraySet<AppWindowToken> mAnimatingTokens = new ArraySet<>();
+ private ArrayMap<AppWindowToken, Runnable> mFinishedTokens = new ArrayMap<>();
+
+ private ArrayList<Runnable> mTmpRunnableList = new ArrayList<>();
+
+ /**
+ * Notifies that an {@link AppWindowToken} has started animating.
+ */
+ void notifyStarting(AppWindowToken token) {
+ mAnimatingTokens.add(token);
+ }
+
+ /**
+ * Notifies that an {@link AppWindowToken} has finished animating.
+ */
+ void notifyFinished(AppWindowToken token) {
+ mAnimatingTokens.remove(token);
+ mFinishedTokens.remove(token);
+ }
+
+ /**
+ * Called when an {@link AppWindowToken} is about to finish animating.
+ *
+ * @param endDeferFinishCallback Callback to run when defer finish should be ended.
+ * @return {@code true} if finishing the animation should be deferred, {@code false} otherwise.
+ */
+ boolean notifyAboutToFinish(AppWindowToken token, Runnable endDeferFinishCallback) {
+ final boolean removed = mAnimatingTokens.remove(token);
+ if (!removed) {
+ return false;
+ }
+
+ if (mAnimatingTokens.isEmpty()) {
+
+ // If no animations are animating anymore, finish all others.
+ endDeferringFinished();
+ return false;
+ } else {
+
+ // Otherwise let's put it into the pending list of to be finished animations.
+ mFinishedTokens.put(token, endDeferFinishCallback);
+ return true;
+ }
+ }
+
+ private void endDeferringFinished() {
+ // Copy it into a separate temp list to avoid modifying the collection while iterating as
+ // calling the callback may call back into notifyFinished.
+ for (int i = mFinishedTokens.size() - 1; i >= 0; i--) {
+ mTmpRunnableList.add(mFinishedTokens.valueAt(i));
+ }
+ mFinishedTokens.clear();
+ for (int i = mTmpRunnableList.size() - 1; i >= 0; i--) {
+ mTmpRunnableList.get(i).run();
+ }
+ mTmpRunnableList.clear();
+ }
+}
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index d2ddf55..f8a4540 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -251,6 +251,7 @@
private final Point mTmpPoint = new Point();
private final Rect mTmpRect = new Rect();
private RemoteAnimationDefinition mRemoteAnimationDefinition;
+ private AnimatingAppWindowTokenRegistry mAnimatingAppWindowTokenRegistry;
AppWindowToken(WindowManagerService service, IApplicationToken token, boolean voiceInteraction,
DisplayContent dc, long inputDispatchingTimeoutNanos, boolean fullscreen,
@@ -780,6 +781,16 @@
task.mStack.mExitingAppTokens.remove(this);
}
}
+ final TaskStack stack = getStack();
+
+ // If we reparent, make sure to remove ourselves from the old animation registry.
+ if (mAnimatingAppWindowTokenRegistry != null) {
+ mAnimatingAppWindowTokenRegistry.notifyFinished(this);
+ }
+ mAnimatingAppWindowTokenRegistry = stack != null
+ ? stack.getAnimatingAppWindowTokenRegistry()
+ : null;
+
mLastParent = task;
}
@@ -1784,6 +1795,21 @@
}
@Override
+ public boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) {
+ return mAnimatingAppWindowTokenRegistry != null
+ && mAnimatingAppWindowTokenRegistry.notifyAboutToFinish(
+ this, endDeferFinishCallback);
+ }
+
+ @Override
+ public void onAnimationLeashDestroyed(Transaction t) {
+ super.onAnimationLeashDestroyed(t);
+ if (mAnimatingAppWindowTokenRegistry != null) {
+ mAnimatingAppWindowTokenRegistry.notifyFinished(this);
+ }
+ }
+
+ @Override
protected void setLayer(Transaction t, int layer) {
if (!mSurfaceAnimator.hasLeash()) {
t.setLayer(mSurfaceControl, layer);
@@ -1825,6 +1851,9 @@
final DisplayContent dc = getDisplayContent();
dc.assignStackOrdering(t);
+ if (mAnimatingAppWindowTokenRegistry != null) {
+ mAnimatingAppWindowTokenRegistry.notifyStarting(this);
+ }
}
/**
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index c35c05d..e2e1690 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -305,6 +305,11 @@
int pendingLayoutChanges;
// TODO(multi-display): remove some of the usages.
boolean isDefaultDisplay;
+ /**
+ * Flag indicating whether WindowManager should override info for this display in
+ * DisplayManager.
+ */
+ boolean mShouldOverrideDisplayConfiguration = true;
/** Window tokens that are in the process of exiting, but still on screen for animations. */
final ArrayList<WindowToken> mExitingTokens = new ArrayList<>();
@@ -1177,8 +1182,14 @@
mDisplayInfo.flags &= ~Display.FLAG_SCALING_DISABLED;
}
+ // We usually set the override info in DisplayManager so that we get consistent display
+ // metrics values when displays are changing and don't send out new values until WM is aware
+ // of them. However, we don't do this for displays that serve as containers for ActivityView
+ // because we don't want letter-/pillar-boxing during resize.
+ final DisplayInfo overrideDisplayInfo = mShouldOverrideDisplayConfiguration
+ ? mDisplayInfo : null;
mService.mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager(mDisplayId,
- mDisplayInfo);
+ overrideDisplayInfo);
mBaseDisplayRect.set(0, 0, dw, dh);
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index ad2fabb..235f63e 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -29,6 +29,7 @@
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.Rect;
+import android.os.IBinder;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import android.view.Display;
@@ -268,15 +269,23 @@
.build();
// capture a screenshot into the surface we just created
- Surface sur = new Surface();
- sur.copyFrom(mSurfaceControl);
// TODO(multidisplay): we should use the proper display
- SurfaceControl.screenshot(SurfaceControl.getBuiltInDisplay(
- SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN), sur);
- t.setLayer(mSurfaceControl, SCREEN_FREEZE_LAYER_SCREENSHOT);
- t.setAlpha(mSurfaceControl, 0);
- t.show(mSurfaceControl);
- sur.destroy();
+ final int displayId = SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN;
+ final IBinder displayHandle = SurfaceControl.getBuiltInDisplay(displayId);
+ // This null check below is to guard a race condition where WMS didn't have a chance to
+ // respond to display disconnection before handling rotation , that surfaceflinger may
+ // return a null handle here because it doesn't think that display is valid anymore.
+ if (displayHandle != null) {
+ Surface sur = new Surface();
+ sur.copyFrom(mSurfaceControl);
+ SurfaceControl.screenshot(displayHandle, sur);
+ t.setLayer(mSurfaceControl, SCREEN_FREEZE_LAYER_SCREENSHOT);
+ t.setAlpha(mSurfaceControl, 0);
+ t.show(mSurfaceControl);
+ sur.destroy();
+ } else {
+ Slog.w(TAG, "Built-in display " + displayId + " is null.");
+ }
} catch (OutOfResourcesException e) {
Slog.w(TAG, "Unable to allocate freeze surface", e);
}
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index c06caaf..f10ff8c 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -81,9 +81,14 @@
if (anim != mAnimation) {
return;
}
- reset(mAnimatable.getPendingTransaction(), true /* destroyLeash */);
- if (animationFinishedCallback != null) {
- animationFinishedCallback.run();
+ final Runnable resetAndInvokeFinish = () -> {
+ reset(mAnimatable.getPendingTransaction(), true /* destroyLeash */);
+ if (animationFinishedCallback != null) {
+ animationFinishedCallback.run();
+ }
+ };
+ if (!mAnimatable.shouldDeferAnimationFinish(resetAndInvokeFinish)) {
+ resetAndInvokeFinish.run();
}
}
};
@@ -407,5 +412,17 @@
* @return The height of the surface to be animated.
*/
int getSurfaceHeight();
+
+ /**
+ * Gets called when the animation is about to finish and gives the client the opportunity to
+ * defer finishing the animation, i.e. it keeps the leash around until the client calls
+ * {@link #cancelAnimation}.
+ *
+ * @param endDeferFinishCallback The callback to call when defer finishing should be ended.
+ * @return Whether the client would like to defer the animation finish.
+ */
+ default boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) {
+ return false;
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index b5d00a7..460edec 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -155,6 +155,9 @@
final Rect mTmpDimBoundsRect = new Rect();
private final Point mLastSurfaceSize = new Point();
+ private final AnimatingAppWindowTokenRegistry mAnimatingAppWindowTokenRegistry =
+ new AnimatingAppWindowTokenRegistry();
+
TaskStack(WindowManagerService service, int stackId, StackWindowController controller) {
super(service);
mStackId = stackId;
@@ -1782,4 +1785,8 @@
outPos.x -= outset;
outPos.y -= outset;
}
+
+ AnimatingAppWindowTokenRegistry getAnimatingAppWindowTokenRegistry() {
+ return mAnimatingAppWindowTokenRegistry;
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 9f8de58b..5f0769d 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1117,17 +1117,7 @@
throw new IllegalStateException("Display has not been initialialized");
}
- DisplayContent displayContent = mRoot.getDisplayContent(displayId);
-
- // Adding a window is an exception where the WindowManagerService can create the
- // display instead of waiting for the ActivityManagerService to drive creation.
- if (displayContent == null) {
- final Display display = mDisplayManager.getDisplay(displayId);
-
- if (display != null) {
- displayContent = mRoot.createDisplayContent(display, null /* controller */);
- }
- }
+ final DisplayContent displayContent = getDisplayContentOrCreate(displayId);
if (displayContent == null) {
Slog.w(TAG_WM, "Attempted to add window to a display that does not exist: "
@@ -1493,6 +1483,32 @@
return res;
}
+ /**
+ * Get existing {@link DisplayContent} or create a new one if the display is registered in
+ * DisplayManager.
+ *
+ * NOTE: This should only be used in cases when there is a chance that a {@link DisplayContent}
+ * that corresponds to a display just added to DisplayManager has not yet been created. This
+ * usually means that the call of this method was initiated from outside of Activity or Window
+ * Manager. In most cases the regular getter should be used.
+ * @see RootWindowContainer#getDisplayContent(int)
+ */
+ private DisplayContent getDisplayContentOrCreate(int displayId) {
+ DisplayContent displayContent = mRoot.getDisplayContent(displayId);
+
+ // Create an instance if possible instead of waiting for the ActivityManagerService to drive
+ // the creation.
+ if (displayContent == null) {
+ final Display display = mDisplayManager.getDisplay(displayId);
+
+ if (display != null) {
+ displayContent = mRoot.createDisplayContent(display, null /* controller */);
+ }
+ }
+
+ return displayContent;
+ }
+
private boolean doesAddToastWindowRequireToken(String packageName, int callingUid,
WindowState attachedWindow) {
// Try using the target SDK of the root window
@@ -6987,6 +7003,24 @@
}
@Override
+ public void dontOverrideDisplayInfo(int displayId) {
+ synchronized (mWindowMap) {
+ final DisplayContent dc = getDisplayContentOrCreate(displayId);
+ if (dc == null) {
+ throw new IllegalArgumentException(
+ "Trying to register a non existent display.");
+ }
+ // We usually set the override info in DisplayManager so that we get consistent
+ // values when displays are changing. However, we don't do this for displays that
+ // serve as containers for ActivityViews because we don't want letter-/pillar-boxing
+ // during resize.
+ dc.mShouldOverrideDisplayConfiguration = false;
+ mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager(displayId,
+ null /* info */);
+ }
+ }
+
+ @Override
public void registerShortcutKey(long shortcutCode, IShortcutService shortcutKeyReceiver)
throws RemoteException {
if (!checkCallingPermission(REGISTER_WINDOW_MANAGER_LISTENERS, "registerShortcutKey")) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index c100511..52e4866 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -4525,8 +4525,7 @@
mAttrs.type == TYPE_NAVIGATION_BAR ||
// It's tempting to wonder: Have we forgotten the rounded corners overlay?
// worry not: it's a fake TYPE_NAVIGATION_BAR_PANEL
- mAttrs.type == TYPE_NAVIGATION_BAR_PANEL ||
- mAttrs.type == TYPE_STATUS_BAR) {
+ mAttrs.type == TYPE_NAVIGATION_BAR_PANEL) {
return false;
}
return true;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 70abf80..d165a45 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -196,6 +196,8 @@
"com.android.server.search.SearchManagerService$Lifecycle";
private static final String THERMAL_OBSERVER_CLASS =
"com.google.android.clockwork.ThermalObserver";
+ private static final String WEAR_CONFIG_SERVICE_CLASS =
+ "com.google.android.clockwork.WearConfigManagerService";
private static final String WEAR_CONNECTIVITY_SERVICE_CLASS =
"com.android.clockwork.connectivity.WearConnectivityService";
private static final String WEAR_SIDEKICK_SERVICE_CLASS =
@@ -1543,6 +1545,10 @@
}
if (isWatch) {
+ traceBeginAndSlog("StartWearConfigService");
+ mSystemServiceManager.startService(WEAR_CONFIG_SERVICE_CLASS);
+ traceEnd();
+
traceBeginAndSlog("StartWearConnectivityService");
mSystemServiceManager.startService(WEAR_CONNECTIVITY_SERVICE_CLASS);
traceEnd();
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
index 0462b14..e5c6c6e 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
@@ -16,6 +16,9 @@
package com.android.server.accessibility;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
@@ -57,6 +60,7 @@
static final int SERVICE_ID = 42;
AccessibilityServiceConnection mConnection;
+
@Mock AccessibilityManagerService.UserState mMockUserState;
@Mock Context mMockContext;
@Mock AccessibilityServiceInfo mMockServiceInfo;
@@ -66,7 +70,9 @@
@Mock WindowManagerInternal mMockWindowManagerInternal;
@Mock GlobalActionPerformer mMockGlobalActionPerformer;
@Mock KeyEventDispatcher mMockKeyEventDispatcher;
+ @Mock MagnificationController mMockMagnificationController;
+ MessageCapturingHandler mHandler = new MessageCapturingHandler(null);
@BeforeClass
public static void oneTimeInitialization() {
@@ -79,12 +85,15 @@
public void setup() {
MockitoAnnotations.initMocks(this);
when(mMockSystemSupport.getKeyEventDispatcher()).thenReturn(mMockKeyEventDispatcher);
+ when(mMockSystemSupport.getMagnificationController())
+ .thenReturn(mMockMagnificationController);
+
when(mMockServiceInfo.getResolveInfo()).thenReturn(mMockResolveInfo);
mMockResolveInfo.serviceInfo = mock(ServiceInfo.class);
mMockResolveInfo.serviceInfo.applicationInfo = mock(ApplicationInfo.class);
mConnection = new AccessibilityServiceConnection(mMockUserState, mMockContext,
- COMPONENT_NAME, mMockServiceInfo, SERVICE_ID, new Handler(), new Object(),
+ COMPONENT_NAME, mMockServiceInfo, SERVICE_ID, mHandler, new Object(),
mMockSecurityPolicy, mMockSystemSupport, mMockWindowManagerInternal,
mMockGlobalActionPerformer);
}
@@ -106,12 +115,30 @@
@Test
public void bindConnectUnbind_linksAndUnlinksToServiceDeath() throws RemoteException {
IBinder mockBinder = mock(IBinder.class);
- when(mMockUserState.getBindingServicesLocked())
- .thenReturn(new HashSet<>(Arrays.asList(COMPONENT_NAME)));
+ setServiceBinding(COMPONENT_NAME);
mConnection.bindLocked();
mConnection.onServiceConnected(COMPONENT_NAME, mockBinder);
verify(mockBinder).linkToDeath(eq(mConnection), anyInt());
mConnection.unbindLocked();
verify(mockBinder).unlinkToDeath(eq(mConnection), anyInt());
}
+
+ @Test
+ public void connectedServiceCrashedAndRestarted_crashReportedInServiceInfo() {
+ IBinder mockBinder = mock(IBinder.class);
+ setServiceBinding(COMPONENT_NAME);
+ mConnection.bindLocked();
+ mConnection.onServiceConnected(COMPONENT_NAME, mockBinder);
+ assertFalse(mConnection.getServiceInfo().crashed);
+ mConnection.binderDied();
+ assertTrue(mConnection.getServiceInfo().crashed);
+ mConnection.onServiceConnected(COMPONENT_NAME, mockBinder);
+ mHandler.sendAllMessages();
+ assertFalse(mConnection.getServiceInfo().crashed);
+ }
+
+ private void setServiceBinding(ComponentName componentName) {
+ when(mMockUserState.getBindingServicesLocked())
+ .thenReturn(new HashSet<>(Arrays.asList(componentName)));
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java b/services/tests/servicestests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java
new file mode 100644
index 0000000..8b78f10
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.wm;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.mockito.ArgumentMatchers.any;
+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 com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests for the {@link TaskStack} class.
+ *
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:com.android.server.wm.AnimatingAppWindowTokenRegistryTest
+ */
+@SmallTest
+@Presubmit
+@FlakyTest(detail = "Promote once confirmed non-flaky")
+@RunWith(AndroidJUnit4.class)
+public class AnimatingAppWindowTokenRegistryTest extends WindowTestsBase {
+
+ @Mock
+ AnimationAdapter mAdapter;
+
+ @Mock
+ Runnable mMockEndDeferFinishCallback1;
+ @Mock
+ Runnable mMockEndDeferFinishCallback2;
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @Test
+ public void testDeferring() throws Exception {
+ final AppWindowToken window1 = createAppWindowToken(mDisplayContent,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ final AppWindowToken window2 = createAppWindow(window1.getTask(), ACTIVITY_TYPE_STANDARD,
+ "window2").mAppToken;
+ final AnimatingAppWindowTokenRegistry registry =
+ window1.getStack().getAnimatingAppWindowTokenRegistry();
+
+ window1.startAnimation(window1.getPendingTransaction(), mAdapter, false /* hidden */);
+ window2.startAnimation(window1.getPendingTransaction(), mAdapter, false /* hidden */);
+ assertTrue(window1.isSelfAnimating());
+ assertTrue(window2.isSelfAnimating());
+
+ // Make sure that first animation finish is deferred, second one is not deferred, and first
+ // one gets cancelled.
+ assertTrue(registry.notifyAboutToFinish(window1, mMockEndDeferFinishCallback1));
+ assertFalse(registry.notifyAboutToFinish(window2, mMockEndDeferFinishCallback2));
+ verify(mMockEndDeferFinishCallback1).run();
+ verifyZeroInteractions(mMockEndDeferFinishCallback2);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
index 4f49a4a..b645700 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -31,7 +31,10 @@
import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -457,6 +460,18 @@
SCREEN_ORIENTATION_LANDSCAPE, dc.getOrientation());
}
+ @Test
+ public void testDisableDisplayInfoOverrideFromWindowManager() {
+ final DisplayContent dc = createNewDisplay();
+
+ assertTrue(dc.mShouldOverrideDisplayConfiguration);
+ sWm.dontOverrideDisplayInfo(dc.getDisplayId());
+
+ assertFalse(dc.mShouldOverrideDisplayConfiguration);
+ verify(sWm.mDisplayManagerInternal, times(1))
+ .setDisplayInfoOverrideFromWindowManager(dc.getDisplayId(), null);
+ }
+
private static void verifySizes(DisplayContent displayContent, int expectedBaseWidth,
int expectedBaseHeight, int expectedBaseDensity) {
assertEquals(displayContent.mBaseDisplayWidth, expectedBaseWidth);
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 a120eba..6506872 100644
--- a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
@@ -28,6 +28,7 @@
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;
@@ -64,6 +65,7 @@
private SurfaceSession mSession = new SurfaceSession();
private MyAnimatable mAnimatable;
private MyAnimatable mAnimatable2;
+ private DeferFinishAnimatable mDeferFinishAnimatable;
@Before
public void setUp() throws Exception {
@@ -71,6 +73,7 @@
MockitoAnnotations.initMocks(this);
mAnimatable = new MyAnimatable();
mAnimatable2 = new MyAnimatable();
+ mDeferFinishAnimatable = new DeferFinishAnimatable();
}
@Test
@@ -166,6 +169,29 @@
verify(mTransaction).destroy(eq(leash));
}
+ @Test
+ @FlakyTest(detail = "Promote once confirmed non-flaky")
+ public void testDeferFinish() throws Exception {
+
+ // Start animation
+ mDeferFinishAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec,
+ true /* hidden */);
+ final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass(
+ OnAnimationFinishedCallback.class);
+ assertAnimating(mDeferFinishAnimatable);
+ verify(mSpec).startAnimation(any(), any(), callbackCaptor.capture());
+
+ // Finish the animation but then make sure we are deferring.
+ callbackCaptor.getValue().onAnimationFinished(mSpec);
+ assertAnimating(mDeferFinishAnimatable);
+
+ // Now end defer finishing.
+ mDeferFinishAnimatable.endDeferFinishCallback.run();
+ assertNotAnimating(mAnimatable2);
+ assertTrue(mDeferFinishAnimatable.mFinishedCallbackCalled);
+ verify(mTransaction).destroy(eq(mDeferFinishAnimatable.mLeash));
+ }
+
private void assertAnimating(MyAnimatable animatable) {
assertTrue(animatable.mSurfaceAnimator.isAnimating());
assertNotNull(animatable.mSurfaceAnimator.getAnimation());
@@ -254,4 +280,15 @@
private final Runnable mFinishedCallback = () -> mFinishedCallbackCalled = true;
}
+
+ private class DeferFinishAnimatable extends MyAnimatable {
+
+ Runnable endDeferFinishCallback;
+
+ @Override
+ public boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) {
+ this.endDeferFinishCallback = endDeferFinishCallback;
+ return true;
+ }
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 4fe54b9..9afaa24 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -68,6 +68,7 @@
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
import android.app.NotificationManager;
+import android.app.usage.UsageStatsManagerInternal;
import android.companion.ICompanionDeviceManager;
import android.content.ComponentName;
import android.content.Context;
@@ -264,7 +265,7 @@
mPackageManager, mPackageManagerClient, mockLightsManager,
mListeners, mAssistants, mConditionProviders,
mCompanionMgr, mSnoozeHelper, mUsageStats, mPolicyFile, mActivityManager,
- mGroupHelper, mAm);
+ mGroupHelper, mAm, mock(UsageStatsManagerInternal.class));
} catch (SecurityException e) {
if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
throw e;
@@ -2662,4 +2663,80 @@
assertEquals(expected, actual);
}
+
+ @Test
+ public void testVisualDifference_diffTitle() {
+ Notification.Builder nb1 = new Notification.Builder(mContext, "")
+ .setContentTitle("foo");
+ StatusBarNotification sbn1 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
+ nb1.build(), new UserHandle(mUid), null, 0);
+ NotificationRecord r1 =
+ new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
+
+ Notification.Builder nb2 = new Notification.Builder(mContext, "")
+ .setContentTitle("bar");
+ StatusBarNotification sbn2 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
+ nb2.build(), new UserHandle(mUid), null, 0);
+ NotificationRecord r2 =
+ new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
+
+ assertTrue(mService.isVisuallyInterruptive(r1, r2));
+ }
+
+ @Test
+ public void testVisualDifference_diffText() {
+ Notification.Builder nb1 = new Notification.Builder(mContext, "")
+ .setContentText("foo");
+ StatusBarNotification sbn1 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
+ nb1.build(), new UserHandle(mUid), null, 0);
+ NotificationRecord r1 =
+ new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
+
+ Notification.Builder nb2 = new Notification.Builder(mContext, "")
+ .setContentText("bar");
+ StatusBarNotification sbn2 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
+ nb2.build(), new UserHandle(mUid), null, 0);
+ NotificationRecord r2 =
+ new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
+
+ assertTrue(mService.isVisuallyInterruptive(r1, r2));
+ }
+
+ @Test
+ public void testVisualDifference_diffProgress() {
+ Notification.Builder nb1 = new Notification.Builder(mContext, "")
+ .setProgress(100, 90, false);
+ StatusBarNotification sbn1 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
+ nb1.build(), new UserHandle(mUid), null, 0);
+ NotificationRecord r1 =
+ new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
+
+ Notification.Builder nb2 = new Notification.Builder(mContext, "")
+ .setProgress(100, 100, false);
+ StatusBarNotification sbn2 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
+ nb2.build(), new UserHandle(mUid), null, 0);
+ NotificationRecord r2 =
+ new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
+
+ assertTrue(mService.isVisuallyInterruptive(r1, r2));
+ }
+
+ @Test
+ public void testVisualDifference_diffProgressNotDone() {
+ Notification.Builder nb1 = new Notification.Builder(mContext, "")
+ .setProgress(100, 90, false);
+ StatusBarNotification sbn1 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
+ nb1.build(), new UserHandle(mUid), null, 0);
+ NotificationRecord r1 =
+ new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
+
+ Notification.Builder nb2 = new Notification.Builder(mContext, "")
+ .setProgress(100, 91, false);
+ StatusBarNotification sbn2 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
+ nb2.build(), new UserHandle(mUid), null, 0);
+ NotificationRecord r2 =
+ new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
+
+ assertFalse(mService.isVisuallyInterruptive(r1, r2));
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java
index 4bfb236..c4a688b 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java
@@ -20,18 +20,27 @@
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.app.ActivityManager;
import android.app.Notification;
+import android.app.Notification.Person;
+import android.app.PendingIntent;
+import android.app.RemoteInput;
import android.content.Context;
import android.content.pm.ApplicationInfo;
+import android.graphics.Bitmap;
import android.graphics.Color;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
import android.os.Build;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+import android.widget.RemoteViews;
import com.android.server.UiServiceTestCase;
@@ -112,5 +121,272 @@
assertEquals(Color.RED, new Notification.CarExtender(before).getColor());
assertEquals("dismiss", new Notification.WearableExtender(before).getDismissalId());
}
+
+ @Test
+ public void testStyleChangeVisiblyDifferent_noStyles() {
+ Notification.Builder n1 = new Notification.Builder(mContext, "test");
+ Notification.Builder n2 = new Notification.Builder(mContext, "test");
+
+ assertFalse(Notification.areStyledNotificationsVisiblyDifferent(n1, n2));
+ }
+
+ @Test
+ public void testStyleChangeVisiblyDifferent_noStyleToStyle() {
+ Notification.Builder n1 = new Notification.Builder(mContext, "test");
+ Notification.Builder n2 = new Notification.Builder(mContext, "test")
+ .setStyle(new Notification.BigTextStyle());
+
+ assertTrue(Notification.areStyledNotificationsVisiblyDifferent(n1, n2));
+ }
+
+ @Test
+ public void testStyleChangeVisiblyDifferent_styleToNoStyle() {
+ Notification.Builder n2 = new Notification.Builder(mContext, "test");
+ Notification.Builder n1 = new Notification.Builder(mContext, "test")
+ .setStyle(new Notification.BigTextStyle());
+
+ assertTrue(Notification.areStyledNotificationsVisiblyDifferent(n1, n2));
+ }
+
+ @Test
+ public void testStyleChangeVisiblyDifferent_changeStyle() {
+ Notification.Builder n1 = new Notification.Builder(mContext, "test")
+ .setStyle(new Notification.InboxStyle());
+ Notification.Builder n2 = new Notification.Builder(mContext, "test")
+ .setStyle(new Notification.BigTextStyle());
+
+ assertTrue(Notification.areStyledNotificationsVisiblyDifferent(n1, n2));
+ }
+
+ @Test
+ public void testInboxTextChange() {
+ Notification.Builder nInbox1 = new Notification.Builder(mContext, "test")
+ .setStyle(new Notification.InboxStyle().addLine("a").addLine("b"));
+ Notification.Builder nInbox2 = new Notification.Builder(mContext, "test")
+ .setStyle(new Notification.InboxStyle().addLine("b").addLine("c"));
+
+ assertTrue(Notification.areStyledNotificationsVisiblyDifferent(nInbox1, nInbox2));
+ }
+
+ @Test
+ public void testBigTextTextChange() {
+ Notification.Builder nBigText1 = new Notification.Builder(mContext, "test")
+ .setStyle(new Notification.BigTextStyle().bigText("something"));
+ Notification.Builder nBigText2 = new Notification.Builder(mContext, "test")
+ .setStyle(new Notification.BigTextStyle().bigText("else"));
+
+ assertTrue(Notification.areStyledNotificationsVisiblyDifferent(nBigText1, nBigText2));
+ }
+
+ @Test
+ public void testBigPictureChange() {
+ Notification.Builder nBigPic1 = new Notification.Builder(mContext, "test")
+ .setStyle(new Notification.BigPictureStyle().bigPicture(mock(Bitmap.class)));
+ Notification.Builder nBigPic2 = new Notification.Builder(mContext, "test")
+ .setStyle(new Notification.BigPictureStyle().bigPicture(mock(Bitmap.class)));
+
+ assertTrue(Notification.areStyledNotificationsVisiblyDifferent(nBigPic1, nBigPic2));
+ }
+
+ @Test
+ public void testMessagingChange_text() {
+ Notification.Builder nM1 = new Notification.Builder(mContext, "test")
+ .setStyle(new Notification.MessagingStyle("")
+ .addMessage(new Notification.MessagingStyle.Message(
+ "a", 100, mock(Notification.Person.class))));
+ Notification.Builder nM2 = new Notification.Builder(mContext, "test")
+ .setStyle(new Notification.MessagingStyle("")
+ .addMessage(new Notification.MessagingStyle.Message(
+ "a", 100, mock(Notification.Person.class)))
+ .addMessage(new Notification.MessagingStyle.Message(
+ "b", 100, mock(Notification.Person.class)))
+ );
+
+ assertTrue(Notification.areStyledNotificationsVisiblyDifferent(nM1, nM2));
+ }
+
+ @Test
+ public void testMessagingChange_data() {
+ Notification.Builder nM1 = new Notification.Builder(mContext, "test")
+ .setStyle(new Notification.MessagingStyle("")
+ .addMessage(new Notification.MessagingStyle.Message(
+ "a", 100, mock(Person.class))
+ .setData("text", mock(Uri.class))));
+ Notification.Builder nM2 = new Notification.Builder(mContext, "test")
+ .setStyle(new Notification.MessagingStyle("")
+ .addMessage(new Notification.MessagingStyle.Message(
+ "a", 100, mock(Person.class))));
+
+ assertTrue(Notification.areStyledNotificationsVisiblyDifferent(nM1, nM2));
+ }
+
+ @Test
+ public void testMessagingChange_sender() {
+ Person a = mock(Person.class);
+ when(a.getName()).thenReturn("A");
+ Person b = mock(Person.class);
+ when(b.getName()).thenReturn("b");
+ Notification.Builder nM1 = new Notification.Builder(mContext, "test")
+ .setStyle(new Notification.MessagingStyle("")
+ .addMessage(new Notification.MessagingStyle.Message("a", 100, b)));
+ Notification.Builder nM2 = new Notification.Builder(mContext, "test")
+ .setStyle(new Notification.MessagingStyle("")
+ .addMessage(new Notification.MessagingStyle.Message("a", 100, a)));
+
+ assertTrue(Notification.areStyledNotificationsVisiblyDifferent(nM1, nM2));
+ }
+
+ @Test
+ public void testMessagingChange_key() {
+ Person a = mock(Person.class);
+ when(a.getKey()).thenReturn("A");
+ Person b = mock(Person.class);
+ when(b.getKey()).thenReturn("b");
+ Notification.Builder nM1 = new Notification.Builder(mContext, "test")
+ .setStyle(new Notification.MessagingStyle("")
+ .addMessage(new Notification.MessagingStyle.Message("a", 100, a)));
+ Notification.Builder nM2 = new Notification.Builder(mContext, "test")
+ .setStyle(new Notification.MessagingStyle("")
+ .addMessage(new Notification.MessagingStyle.Message("a", 100, b)));
+
+ assertTrue(Notification.areStyledNotificationsVisiblyDifferent(nM1, nM2));
+ }
+
+ @Test
+ public void testMessagingChange_ignoreTimeChange() {
+ Notification.Builder nM1 = new Notification.Builder(mContext, "test")
+ .setStyle(new Notification.MessagingStyle("")
+ .addMessage(new Notification.MessagingStyle.Message(
+ "a", 100, mock(Notification.Person.class))));
+ Notification.Builder nM2 = new Notification.Builder(mContext, "test")
+ .setStyle(new Notification.MessagingStyle("")
+ .addMessage(new Notification.MessagingStyle.Message(
+ "a", 1000, mock(Notification.Person.class)))
+ );
+
+ assertFalse(Notification.areStyledNotificationsVisiblyDifferent(nM1, nM2));
+ }
+
+ @Test
+ public void testRemoteViews_nullChange() {
+ Notification.Builder n1 = new Notification.Builder(mContext, "test")
+ .setContent(mock(RemoteViews.class));
+ Notification.Builder n2 = new Notification.Builder(mContext, "test");
+ assertTrue(Notification.areRemoteViewsChanged(n1, n2));
+
+ n1 = new Notification.Builder(mContext, "test");
+ n2 = new Notification.Builder(mContext, "test")
+ .setContent(mock(RemoteViews.class));
+ assertTrue(Notification.areRemoteViewsChanged(n1, n2));
+
+ n1 = new Notification.Builder(mContext, "test")
+ .setCustomBigContentView(mock(RemoteViews.class));
+ n2 = new Notification.Builder(mContext, "test");
+ assertTrue(Notification.areRemoteViewsChanged(n1, n2));
+
+ n1 = new Notification.Builder(mContext, "test");
+ n2 = new Notification.Builder(mContext, "test")
+ .setCustomBigContentView(mock(RemoteViews.class));
+ assertTrue(Notification.areRemoteViewsChanged(n1, n2));
+
+ n1 = new Notification.Builder(mContext, "test");
+ n2 = new Notification.Builder(mContext, "test");
+ assertFalse(Notification.areRemoteViewsChanged(n1, n2));
+ }
+
+ @Test
+ public void testActionsDifferent_null() {
+ Notification n1 = new Notification.Builder(mContext, "test")
+ .build();
+ Notification n2 = new Notification.Builder(mContext, "test")
+ .build();
+
+ assertFalse(Notification.areActionsVisiblyDifferent(n1, n2));
+ }
+
+ @Test
+ public void testActionsDifferentSame() {
+ PendingIntent intent = mock(PendingIntent.class);
+ Icon icon = mock(Icon.class);
+
+ Notification n1 = new Notification.Builder(mContext, "test")
+ .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent).build())
+ .build();
+ Notification n2 = new Notification.Builder(mContext, "test")
+ .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent).build())
+ .build();
+
+ assertFalse(Notification.areActionsVisiblyDifferent(n1, n2));
+ }
+
+ @Test
+ public void testActionsDifferentText() {
+ PendingIntent intent = mock(PendingIntent.class);
+ Icon icon = mock(Icon.class);
+
+ Notification n1 = new Notification.Builder(mContext, "test")
+ .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent).build())
+ .build();
+ Notification n2 = new Notification.Builder(mContext, "test")
+ .addAction(new Notification.Action.Builder(icon, "TEXT 2", intent).build())
+ .build();
+
+ assertTrue(Notification.areActionsVisiblyDifferent(n1, n2));
+ }
+
+ @Test
+ public void testActionsDifferentNumber() {
+ PendingIntent intent = mock(PendingIntent.class);
+ Icon icon = mock(Icon.class);
+
+ Notification n1 = new Notification.Builder(mContext, "test")
+ .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent).build())
+ .build();
+ Notification n2 = new Notification.Builder(mContext, "test")
+ .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent).build())
+ .addAction(new Notification.Action.Builder(icon, "TEXT 2", intent).build())
+ .build();
+
+ assertTrue(Notification.areActionsVisiblyDifferent(n1, n2));
+ }
+
+ @Test
+ public void testActionsDifferentIntent() {
+ PendingIntent intent1 = mock(PendingIntent.class);
+ PendingIntent intent2 = mock(PendingIntent.class);
+ Icon icon = mock(Icon.class);
+
+ Notification n1 = new Notification.Builder(mContext, "test")
+ .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent1).build())
+ .build();
+ Notification n2 = new Notification.Builder(mContext, "test")
+ .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent2).build())
+ .build();
+
+ assertFalse(Notification.areActionsVisiblyDifferent(n1, n2));
+ }
+
+ @Test
+ public void testActionsDifferentRemoteInputs() {
+ PendingIntent intent = mock(PendingIntent.class);
+ Icon icon = mock(Icon.class);
+
+ Notification n1 = new Notification.Builder(mContext, "test")
+ .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent)
+ .addRemoteInput(new RemoteInput.Builder("a")
+ .setChoices(new CharSequence[] {"i", "m"})
+ .build())
+ .build())
+ .build();
+ Notification n2 = new Notification.Builder(mContext, "test")
+ .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent)
+ .addRemoteInput(new RemoteInput.Builder("a")
+ .setChoices(new CharSequence[] {"t", "m"})
+ .build())
+ .build())
+ .build();
+
+ assertTrue(Notification.areActionsVisiblyDifferent(n1, n2));
+ }
}
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 be58fd2..381e04c 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -49,9 +49,11 @@
import android.provider.Settings;
import android.provider.Settings.Global;
import android.service.notification.ZenModeConfig;
+import android.service.notification.ZenModeConfig.ScheduleInfo;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.util.ArrayMap;
import android.util.Xml;
import com.android.internal.R;
@@ -102,13 +104,13 @@
mConditionProviders));
}
- private ByteArrayOutputStream writeXmlAndPurge(boolean forBackup)
+ private ByteArrayOutputStream writeXmlAndPurge(boolean forBackup, Integer version)
throws Exception {
XmlSerializer serializer = new FastXmlSerializer();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
serializer.startDocument(null, true);
- mZenModeHelperSpy.writeXml(serializer, forBackup);
+ mZenModeHelperSpy.writeXml(serializer, forBackup, version);
serializer.endDocument();
serializer.flush();
mZenModeHelperSpy.setConfig(new ZenModeConfig(), "writing xml");
@@ -603,7 +605,7 @@
ZenModeConfig expected = mZenModeHelperSpy.mConfig.copy();
- ByteArrayOutputStream baos = writeXmlAndPurge(false);
+ ByteArrayOutputStream baos = writeXmlAndPurge(false, null);
XmlPullParser parser = Xml.newPullParser();
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(baos.toByteArray())), null);
@@ -614,6 +616,96 @@
}
@Test
+ public void testReadXml() throws Exception {
+ setupZenConfig();
+
+ // automatic zen rule is enabled on upgrade so rules should not be overriden by default
+ ArrayMap<String, ZenModeConfig.ZenRule> enabledAutoRule = new ArrayMap<>();
+ ZenModeConfig.ZenRule customRule = new ZenModeConfig.ZenRule();
+ final ScheduleInfo weeknights = new ScheduleInfo();
+ customRule.enabled = true;
+ customRule.name = "Custom Rule";
+ customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ customRule.conditionId = ZenModeConfig.toScheduleConditionId(weeknights);
+ enabledAutoRule.put("customRule", customRule);
+ mZenModeHelperSpy.mConfig.automaticRules = enabledAutoRule;
+
+ ZenModeConfig expected = mZenModeHelperSpy.mConfig.copy();
+
+ // set previous version
+ ByteArrayOutputStream baos = writeXmlAndPurge(false, 5);
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(new BufferedInputStream(
+ new ByteArrayInputStream(baos.toByteArray())), null);
+ parser.nextTag();
+ mZenModeHelperSpy.readXml(parser, false);
+
+ assertTrue(mZenModeHelperSpy.mConfig.automaticRules.containsKey("customRule"));
+ setupZenConfigMaintained();
+ }
+
+ @Test
+ public void testReadXmlResetDefaultRules() throws Exception {
+ setupZenConfig();
+
+ // no enabled automatic zen rule, so rules should be overriden by default rules
+ mZenModeHelperSpy.mConfig.automaticRules = new ArrayMap<>();
+
+ // set previous version
+ ByteArrayOutputStream baos = writeXmlAndPurge(false, 5);
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(new BufferedInputStream(
+ new ByteArrayInputStream(baos.toByteArray())), null);
+ parser.nextTag();
+ mZenModeHelperSpy.readXml(parser, false);
+
+ // check default rules
+ ArrayMap<String, ZenModeConfig.ZenRule> rules = mZenModeHelperSpy.mConfig.automaticRules;
+ assertTrue(rules.size() != 0);
+ for (String defaultId : ZenModeConfig.DEFAULT_RULE_IDS) {
+ assertTrue(rules.containsKey(defaultId));
+ }
+
+ setupZenConfigMaintained();
+ }
+
+
+ @Test
+ public void testReadXmlAllDisabledRulesResetDefaultRules() throws Exception {
+ setupZenConfig();
+
+ // all automatic zen rules are diabled on upgrade so rules should be overriden by default
+ // rules
+ ArrayMap<String, ZenModeConfig.ZenRule> enabledAutoRule = new ArrayMap<>();
+ ZenModeConfig.ZenRule customRule = new ZenModeConfig.ZenRule();
+ final ScheduleInfo weeknights = new ScheduleInfo();
+ customRule.enabled = false;
+ customRule.name = "Custom Rule";
+ customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ customRule.conditionId = ZenModeConfig.toScheduleConditionId(weeknights);
+ enabledAutoRule.put("customRule", customRule);
+ mZenModeHelperSpy.mConfig.automaticRules = enabledAutoRule;
+
+ // set previous version
+ ByteArrayOutputStream baos = writeXmlAndPurge(false, 5);
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(new BufferedInputStream(
+ new ByteArrayInputStream(baos.toByteArray())), null);
+ parser.nextTag();
+ mZenModeHelperSpy.readXml(parser, false);
+
+ // check default rules
+ ArrayMap<String, ZenModeConfig.ZenRule> rules = mZenModeHelperSpy.mConfig.automaticRules;
+ assertTrue(rules.size() != 0);
+ for (String defaultId : ZenModeConfig.DEFAULT_RULE_IDS) {
+ assertTrue(rules.containsKey(defaultId));
+ }
+ assertFalse(rules.containsKey("customRule"));
+
+ setupZenConfigMaintained();
+ }
+
+ @Test
public void testPolicyReadsSuppressedEffects() {
mZenModeHelperSpy.mConfig.allowWhenScreenOff = true;
mZenModeHelperSpy.mConfig.allowWhenScreenOn = true;
@@ -622,4 +714,40 @@
NotificationManager.Policy policy = mZenModeHelperSpy.getNotificationPolicy();
assertEquals(SUPPRESSED_EFFECT_BADGE, policy.suppressedVisualEffects);
}
+
+ private void setupZenConfig() {
+ mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ mZenModeHelperSpy.mConfig.allowAlarms = false;
+ mZenModeHelperSpy.mConfig.allowMedia = false;
+ mZenModeHelperSpy.mConfig.allowSystem = false;
+ mZenModeHelperSpy.mConfig.allowReminders = true;
+ mZenModeHelperSpy.mConfig.allowCalls = true;
+ mZenModeHelperSpy.mConfig.allowMessages = true;
+ mZenModeHelperSpy.mConfig.allowEvents = true;
+ mZenModeHelperSpy.mConfig.allowRepeatCallers= true;
+ mZenModeHelperSpy.mConfig.allowWhenScreenOff = true;
+ mZenModeHelperSpy.mConfig.allowWhenScreenOn = true;
+ mZenModeHelperSpy.mConfig.suppressedVisualEffects = SUPPRESSED_EFFECT_BADGE;
+ mZenModeHelperSpy.mConfig.manualRule = new ZenModeConfig.ZenRule();
+ mZenModeHelperSpy.mConfig.manualRule.zenMode =
+ Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ mZenModeHelperSpy.mConfig.manualRule.component = new ComponentName("a", "a");
+ mZenModeHelperSpy.mConfig.manualRule.enabled = true;
+ mZenModeHelperSpy.mConfig.manualRule.snoozing = true;
+ }
+
+ private void setupZenConfigMaintained() {
+ // config is still the same as when it was setup (setupZenConfig)
+ assertFalse(mZenModeHelperSpy.mConfig.allowAlarms);
+ assertFalse(mZenModeHelperSpy.mConfig.allowMedia);
+ assertFalse(mZenModeHelperSpy.mConfig.allowSystem);
+ assertTrue(mZenModeHelperSpy.mConfig.allowReminders);
+ assertTrue(mZenModeHelperSpy.mConfig.allowCalls);
+ assertTrue(mZenModeHelperSpy.mConfig.allowMessages);
+ assertTrue(mZenModeHelperSpy.mConfig.allowEvents);
+ assertTrue(mZenModeHelperSpy.mConfig.allowRepeatCallers);
+ assertTrue(mZenModeHelperSpy.mConfig.allowWhenScreenOff);
+ assertTrue(mZenModeHelperSpy.mConfig.allowWhenScreenOn);
+ assertEquals(SUPPRESSED_EFFECT_BADGE, mZenModeHelperSpy.mConfig.suppressedVisualEffects);
+ }
}
diff --git a/telephony/java/android/telephony/CellIdentityCdma.java b/telephony/java/android/telephony/CellIdentityCdma.java
index 105ddb0..713ac00 100644
--- a/telephony/java/android/telephony/CellIdentityCdma.java
+++ b/telephony/java/android/telephony/CellIdentityCdma.java
@@ -16,6 +16,7 @@
package android.telephony;
+import android.annotation.Nullable;
import android.os.Parcel;
import android.text.TextUtils;
@@ -181,6 +182,7 @@
* @return The long alpha tag associated with the current scan result (may be the operator
* name string or extended operator name string). May be null if unknown.
*/
+ @Nullable
public CharSequence getOperatorAlphaLong() {
return mAlphaLong;
}
@@ -189,6 +191,7 @@
* @return The short alpha tag associated with the current scan result (may be the operator
* name string or extended operator name string). May be null if unknown.
*/
+ @Nullable
public CharSequence getOperatorAlphaShort() {
return mAlphaShort;
}
diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java
index 52944a8..aae7929 100644
--- a/telephony/java/android/telephony/CellIdentityGsm.java
+++ b/telephony/java/android/telephony/CellIdentityGsm.java
@@ -16,6 +16,7 @@
package android.telephony;
+import android.annotation.Nullable;
import android.os.Parcel;
import android.text.TextUtils;
@@ -191,6 +192,7 @@
* @return The long alpha tag associated with the current scan result (may be the operator
* name string or extended operator name string). May be null if unknown.
*/
+ @Nullable
public CharSequence getOperatorAlphaLong() {
return mAlphaLong;
}
@@ -199,6 +201,7 @@
* @return The short alpha tag associated with the current scan result (may be the operator
* name string or extended operator name string). May be null if unknown.
*/
+ @Nullable
public CharSequence getOperatorAlphaShort() {
return mAlphaShort;
}
diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java
index 37fb075..9b3ef56 100644
--- a/telephony/java/android/telephony/CellIdentityLte.java
+++ b/telephony/java/android/telephony/CellIdentityLte.java
@@ -16,6 +16,7 @@
package android.telephony;
+import android.annotation.Nullable;
import android.os.Parcel;
import android.text.TextUtils;
@@ -201,6 +202,7 @@
* @return The long alpha tag associated with the current scan result (may be the operator
* name string or extended operator name string). May be null if unknown.
*/
+ @Nullable
public CharSequence getOperatorAlphaLong() {
return mAlphaLong;
}
@@ -209,6 +211,7 @@
* @return The short alpha tag associated with the current scan result (may be the operator
* name string or extended operator name string). May be null if unknown.
*/
+ @Nullable
public CharSequence getOperatorAlphaShort() {
return mAlphaShort;
}
diff --git a/telephony/java/android/telephony/CellIdentityTdscdma.java b/telephony/java/android/telephony/CellIdentityTdscdma.java
index 992545d..7475c74 100644
--- a/telephony/java/android/telephony/CellIdentityTdscdma.java
+++ b/telephony/java/android/telephony/CellIdentityTdscdma.java
@@ -16,6 +16,7 @@
package android.telephony;
+import android.annotation.Nullable;
import android.os.Parcel;
import android.text.TextUtils;
@@ -34,6 +35,10 @@
private final int mCid;
// 8-bit Cell Parameters ID described in TS 25.331, 0..127, INT_MAX if unknown.
private final int mCpid;
+ // long alpha Operator Name String or Enhanced Operator Name String
+ private final String mAlphaLong;
+ // short alpha Operator Name String or Enhanced Operator Name String
+ private final String mAlphaShort;
/**
* @hide
@@ -43,6 +48,8 @@
mLac = Integer.MAX_VALUE;
mCid = Integer.MAX_VALUE;
mCpid = Integer.MAX_VALUE;
+ mAlphaLong = null;
+ mAlphaShort = null;
}
/**
@@ -55,7 +62,7 @@
* @hide
*/
public CellIdentityTdscdma(int mcc, int mnc, int lac, int cid, int cpid) {
- this(String.valueOf(mcc), String.valueOf(mnc), lac, cid, cpid);
+ this(String.valueOf(mcc), String.valueOf(mnc), lac, cid, cpid, null, null);
}
/**
@@ -65,6 +72,7 @@
* @param cid 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455, INT_MAX if unknown
* @param cpid 8-bit Cell Parameters ID described in TS 25.331, 0..127, INT_MAX if unknown
*
+ * FIXME: This is a temporary constructor to facilitate migration.
* @hide
*/
public CellIdentityTdscdma(String mcc, String mnc, int lac, int cid, int cpid) {
@@ -72,10 +80,34 @@
mLac = lac;
mCid = cid;
mCpid = cpid;
+ mAlphaLong = null;
+ mAlphaShort = null;
+ }
+
+ /**
+ * @param mcc 3-digit Mobile Country Code in string format
+ * @param mnc 2 or 3-digit Mobile Network Code in string format
+ * @param lac 16-bit Location Area Code, 0..65535, INT_MAX if unknown
+ * @param cid 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455, INT_MAX if unknown
+ * @param cpid 8-bit Cell Parameters ID described in TS 25.331, 0..127, INT_MAX if unknown
+ * @param alphal long alpha Operator Name String or Enhanced Operator Name String
+ * @param alphas short alpha Operator Name String or Enhanced Operator Name String
+ *
+ * @hide
+ */
+ public CellIdentityTdscdma(String mcc, String mnc, int lac, int cid, int cpid,
+ String alphal, String alphas) {
+ super(TAG, TYPE_TDSCDMA, mcc, mnc);
+ mLac = lac;
+ mCid = cid;
+ mCpid = cpid;
+ mAlphaLong = alphal;
+ mAlphaShort = alphas;
}
private CellIdentityTdscdma(CellIdentityTdscdma cid) {
- this(cid.mMccStr, cid.mMncStr, cid.mLac, cid.mCid, cid.mCpid);
+ this(cid.mMccStr, cid.mMncStr, cid.mLac, cid.mCid,
+ cid.mCpid, cid.mAlphaLong, cid.mAlphaShort);
}
CellIdentityTdscdma copy() {
@@ -119,9 +151,31 @@
return mCpid;
}
+ /**
+ * @return The long alpha tag associated with the current scan result (may be the operator
+ * name string or extended operator name string). May be null if unknown.
+ *
+ * @hide
+ */
+ @Nullable
+ public CharSequence getOperatorAlphaLong() {
+ return mAlphaLong;
+ }
+
+ /**
+ * @return The short alpha tag associated with the current scan result (may be the operator
+ * name string or extended operator name string). May be null if unknown.
+ *
+ * @hide
+ */
+ @Nullable
+ public CharSequence getOperatorAlphaShort() {
+ return mAlphaShort;
+ }
+
@Override
public int hashCode() {
- return Objects.hash(mMccStr, mMncStr, mLac, mCid, mCpid);
+ return Objects.hash(mMccStr, mMncStr, mLac, mCid, mCpid, mAlphaLong, mAlphaShort);
}
@Override
@@ -139,7 +193,9 @@
&& TextUtils.equals(mMncStr, o.mMncStr)
&& mLac == o.mLac
&& mCid == o.mCid
- && mCpid == o.mCpid;
+ && mCpid == o.mCpid
+ && mAlphaLong == o.mAlphaLong
+ && mAlphaShort == o.mAlphaShort;
}
@Override
@@ -150,6 +206,8 @@
.append(" mLac=").append(mLac)
.append(" mCid=").append(mCid)
.append(" mCpid=").append(mCpid)
+ .append(" mAlphaLong=").append(mAlphaLong)
+ .append(" mAlphaShort=").append(mAlphaShort)
.append("}").toString();
}
@@ -161,6 +219,8 @@
dest.writeInt(mLac);
dest.writeInt(mCid);
dest.writeInt(mCpid);
+ dest.writeString(mAlphaLong);
+ dest.writeString(mAlphaShort);
}
/** Construct from Parcel, type has already been processed */
@@ -169,6 +229,8 @@
mLac = in.readInt();
mCid = in.readInt();
mCpid = in.readInt();
+ mAlphaLong = in.readString();
+ mAlphaShort = in.readString();
if (DBG) log(toString());
}
diff --git a/telephony/java/android/telephony/CellIdentityWcdma.java b/telephony/java/android/telephony/CellIdentityWcdma.java
index affa0c1..52fa54f 100644
--- a/telephony/java/android/telephony/CellIdentityWcdma.java
+++ b/telephony/java/android/telephony/CellIdentityWcdma.java
@@ -16,6 +16,7 @@
package android.telephony;
+import android.annotation.Nullable;
import android.os.Parcel;
import android.text.TextUtils;
@@ -182,6 +183,7 @@
* @return The long alpha tag associated with the current scan result (may be the operator
* name string or extended operator name string). May be null if unknown.
*/
+ @Nullable
public CharSequence getOperatorAlphaLong() {
return mAlphaLong;
}
@@ -190,6 +192,7 @@
* @return The short alpha tag associated with the current scan result (may be the operator
* name string or extended operator name string). May be null if unknown.
*/
+ @Nullable
public CharSequence getOperatorAlphaShort() {
return mAlphaShort;
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 7dff667..c1300b3 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1455,7 +1455,6 @@
* {@hide}
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public int getCurrentPhoneType() {
return getCurrentPhoneType(getSubId());
}
@@ -1471,17 +1470,7 @@
* @hide
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public int getCurrentPhoneType(int subId) {
- return getCurrentPhoneType(subId, false);
- }
-
- /**
- * getCurrentPhoneType() with optional check if device is voice capable.
- *
- * @hide
- */
- public int getCurrentPhoneType(int subId, boolean checkIsVoiceCapable) {
int phoneId;
if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
// if we don't have any sims, we don't have subscriptions, but we
@@ -1490,7 +1479,8 @@
} else {
phoneId = SubscriptionManager.getPhoneId(subId);
}
- return getCurrentPhoneTypeForSlot(phoneId, checkIsVoiceCapable);
+
+ return getCurrentPhoneTypeForSlot(phoneId);
}
/**
@@ -1498,15 +1488,11 @@
*
* @hide
*/
- public int getCurrentPhoneTypeForSlot(int slotIndex, boolean checkIsVoiceCapable) {
+ public int getCurrentPhoneTypeForSlot(int slotIndex) {
try{
ITelephony telephony = getITelephony();
if (telephony != null) {
- if (checkIsVoiceCapable) {
- return telephony.getVoiceCapableActivePhoneTypeForSlot(slotIndex);
- } else {
- return telephony.getActivePhoneTypeForSlot(slotIndex);
- }
+ return telephony.getActivePhoneTypeForSlot(slotIndex);
} else {
// This can happen when the ITelephony interface is not up yet.
return getPhoneTypeFromProperty(slotIndex);
@@ -1532,7 +1518,10 @@
* @see #PHONE_TYPE_SIP
*/
public int getPhoneType() {
- return getCurrentPhoneType(getSubId(), true);
+ if (!isVoiceCapable()) {
+ return PHONE_TYPE_NONE;
+ }
+ return getCurrentPhoneType();
}
private int getPhoneTypeFromProperty() {
@@ -5842,14 +5831,12 @@
/** @hide */
@SystemApi
- @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public List<String> getCarrierPackageNamesForIntent(Intent intent) {
return getCarrierPackageNamesForIntentAndPhone(intent, getPhoneId());
}
/** @hide */
@SystemApi
- @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public List<String> getCarrierPackageNamesForIntentAndPhone(Intent intent, int phoneId) {
try {
ITelephony telephony = getITelephony();
@@ -5959,11 +5946,7 @@
}
}
- /**
- * @deprecated Use {@link android.telecom.TelecomManager#isInCall} instead
- * @hide
- */
- @Deprecated
+ /** @hide */
@SystemApi
@RequiresPermission(anyOf = {
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
@@ -5980,11 +5963,7 @@
return false;
}
- /**
- * @deprecated Use {@link android.telecom.TelecomManager#isRinging} instead
- * @hide
- */
- @Deprecated
+ /** @hide */
@SystemApi
@RequiresPermission(anyOf = {
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
@@ -6001,11 +5980,7 @@
return false;
}
- /**
- * @deprecated Use {@link android.telecom.TelecomManager#isInCall} instead
- * @hide
- */
- @Deprecated
+ /** @hide */
@SystemApi
@RequiresPermission(anyOf = {
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
@@ -6022,11 +5997,7 @@
return true;
}
- /**
- * @deprecated Use {@link android.telephony.TelephonyManager#getServiceState} instead
- * @hide
- */
- @Deprecated
+ /** @hide */
@SystemApi
@RequiresPermission(anyOf = {
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
@@ -6317,7 +6288,6 @@
/** @hide */
@SystemApi
- @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public boolean isDataConnectivityPossible() {
try {
ITelephony telephony = getITelephony();
@@ -6332,7 +6302,6 @@
/** @hide */
@SystemApi
- @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public boolean needsOtaServiceProvisioning() {
try {
ITelephony telephony = getITelephony();
@@ -6435,7 +6404,10 @@
/** @hide */
@SystemApi
- @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ android.Manifest.permission.READ_PHONE_STATE
+ })
public boolean isVideoCallingEnabled() {
try {
ITelephony telephony = getITelephony();
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index 1637c55..dff1c6f 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -15,11 +15,12 @@
*/
package android.telephony.euicc;
+import android.Manifest;
import android.annotation.IntDef;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SystemApi;
-import android.annotation.TestApi;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.Context;
@@ -73,6 +74,7 @@
*/
@SystemApi
@SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
+ @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public static final String ACTION_OTA_STATUS_CHANGED =
"android.telephony.euicc.action.OTA_STATUS_CHANGED";
@@ -301,6 +303,7 @@
* @hide
*/
@SystemApi
+ @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public int getOtaStatus() {
if (!isEnabled()) {
return EUICC_OTA_STATUS_UNAVAILABLE;
@@ -325,6 +328,7 @@
* @param switchAfterDownload if true, the profile will be activated upon successful download.
* @param callbackIntent a PendingIntent to launch when the operation completes.
*/
+ @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void downloadSubscription(DownloadableSubscription subscription,
boolean switchAfterDownload, PendingIntent callbackIntent) {
if (!isEnabled()) {
@@ -387,6 +391,7 @@
* @hide
*/
@SystemApi
+ @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void continueOperation(Intent resolutionIntent, Bundle resolutionExtras) {
if (!isEnabled()) {
PendingIntent callbackIntent =
@@ -422,6 +427,7 @@
* @hide
*/
@SystemApi
+ @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void getDownloadableSubscriptionMetadata(
DownloadableSubscription subscription, PendingIntent callbackIntent) {
if (!isEnabled()) {
@@ -452,6 +458,7 @@
* @hide
*/
@SystemApi
+ @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void getDefaultDownloadableSubscriptionList(PendingIntent callbackIntent) {
if (!isEnabled()) {
sendUnavailableError(callbackIntent);
@@ -496,6 +503,7 @@
* @param subscriptionId the ID of the subscription to delete.
* @param callbackIntent a PendingIntent to launch when the operation completes.
*/
+ @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void deleteSubscription(int subscriptionId, PendingIntent callbackIntent) {
if (!isEnabled()) {
sendUnavailableError(callbackIntent);
@@ -523,6 +531,7 @@
* current profile without activating another profile to replace it.
* @param callbackIntent a PendingIntent to launch when the operation completes.
*/
+ @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void switchToSubscription(int subscriptionId, PendingIntent callbackIntent) {
if (!isEnabled()) {
sendUnavailableError(callbackIntent);
@@ -548,6 +557,7 @@
* @param callbackIntent a PendingIntent to launch when the operation completes.
* @hide
*/
+ @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void updateSubscriptionNickname(
int subscriptionId, String nickname, PendingIntent callbackIntent) {
if (!isEnabled()) {
@@ -566,12 +576,13 @@
* Erase all subscriptions and reset the eUICC.
*
* <p>Requires that the calling app has the
- * {@link android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission. This is for
- * internal system use only.
+ * {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission.
*
* @param callbackIntent a PendingIntent to launch when the operation completes.
* @hide
*/
+ @SystemApi
+ @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void eraseSubscriptions(PendingIntent callbackIntent) {
if (!isEnabled()) {
sendUnavailableError(callbackIntent);
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 23b4dc0..fbb69ad 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -375,8 +375,6 @@
/**
* Report whether data connectivity is possible.
- *
- * <p>Requires that the calling app has READ_PRIVILEGED_PHONE_STATE
*/
boolean isDataConnectivityPossible(int subId);
@@ -415,25 +413,11 @@
* Returns the current active phone type as integer for particular slot.
* Returns TelephonyManager.PHONE_TYPE_CDMA if RILConstants.CDMA_PHONE
* and TelephonyManager.PHONE_TYPE_GSM if RILConstants.GSM_PHONE
- *
- * <p>Requires that the calling app has READ_PRIVILEGED_PHONE_STATE
- *
* @param slotIndex - slot to query.
*/
int getActivePhoneTypeForSlot(int slotIndex);
/**
- * Returns the current active phone type as integer for particular slot.
- * Returns TelephonyManager.PHONE_TYPE_CDMA if RILConstants.CDMA_PHONE
- * and TelephonyManager.PHONE_TYPE_GSM if RILConstants.GSM_PHONE
- *
- * If the device is not voice-capable, return PHONE_TYPE_NONE
- *
- * @param slotIndex - slot to query.
- */
- int getVoiceCapableActivePhoneTypeForSlot(int slotIndex);
-
- /**
* Returns the CDMA ERI icon index to display
* @param callingPackage package making the call.
*/
@@ -480,8 +464,6 @@
* Returns true if OTA service provisioning needs to run.
* Only relevant on some technologies, others will always
* return false.
- *
- * <p>Requires that the calling app has READ_PRIVILEGED_PHONE_STATE
*/
boolean needsOtaServiceProvisioning();
@@ -994,8 +976,6 @@
* Returns list of the package names of the carrier apps that should handle the input intent
* and have carrier privileges for the given phoneId.
*
- * <p>Requires that the calling app has READ_PRIVILEGED_PHONE_STATE
- *
* @param intent Intent that will be sent.
* @param phoneId The phoneId on which the carrier app has carrier privileges.
* @return list of carrier app package names that can handle the intent on phoneId.
@@ -1120,8 +1100,6 @@
/**
* Whether video calling has been enabled by the user.
*
- * <p>Requires that the calling app has READ_PRIVILEGED_PHONE_STATE
- *
* @param callingPackage The package making the call.
* @return {@code true} if the user has enabled video calling, {@code false} otherwise.
*/
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
index 14c5f4b..964a313 100644
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -470,6 +470,9 @@
int bearerDataLength;
SmsEnvelope env = new SmsEnvelope();
CdmaSmsAddress addr = new CdmaSmsAddress();
+ // We currently do not parse subaddress in PDU, but it is required when determining
+ // fingerprint (see getIncomingSmsFingerprint()).
+ CdmaSmsSubaddress subaddr = new CdmaSmsSubaddress();
try {
env.messageType = dis.readInt();
@@ -520,6 +523,7 @@
// link the filled objects to this SMS
mOriginatingAddress = addr;
env.origAddress = addr;
+ env.origSubaddress = subaddr;
mEnvelope = env;
mPdu = pdu;
@@ -1009,8 +1013,11 @@
output.write(mEnvelope.teleService);
output.write(mEnvelope.origAddress.origBytes, 0, mEnvelope.origAddress.origBytes.length);
output.write(mEnvelope.bearerData, 0, mEnvelope.bearerData.length);
- output.write(mEnvelope.origSubaddress.origBytes, 0,
- mEnvelope.origSubaddress.origBytes.length);
+ // subaddress is not set when parsing some MT SMS.
+ if (mEnvelope.origSubaddress != null && mEnvelope.origSubaddress.origBytes != null) {
+ output.write(mEnvelope.origSubaddress.origBytes, 0,
+ mEnvelope.origSubaddress.origBytes.length);
+ }
return output.toByteArray();
}
diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp
index ab106d7..ebdcdfd 100644
--- a/tools/stats_log_api_gen/Collation.cpp
+++ b/tools/stats_log_api_gen/Collation.cpp
@@ -46,7 +46,8 @@
message(that.message),
fields(that.fields),
primaryFields(that.primaryFields),
- exclusiveField(that.exclusiveField) {}
+ exclusiveField(that.exclusiveField),
+ uidField(that.uidField) {}
AtomDecl::AtomDecl(int c, const string& n, const string& m)
:code(c),
@@ -262,6 +263,18 @@
errorCount++;
}
}
+
+ if (field->options().GetExtension(os::statsd::is_uid) == true) {
+ if (javaType != JAVA_TYPE_INT) {
+ errorCount++;
+ }
+
+ if (atomDecl->uidField == 0) {
+ atomDecl->uidField = it->first;
+ } else {
+ errorCount++;
+ }
+ }
}
return errorCount;
diff --git a/tools/stats_log_api_gen/Collation.h b/tools/stats_log_api_gen/Collation.h
index edba3e2..5d2c302 100644
--- a/tools/stats_log_api_gen/Collation.h
+++ b/tools/stats_log_api_gen/Collation.h
@@ -84,6 +84,8 @@
vector<int> primaryFields;
int exclusiveField = 0;
+ int uidField = 0;
+
AtomDecl();
AtomDecl(const AtomDecl& that);
AtomDecl(int code, const string& name, const string& message);
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index d58c223..300c701 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -113,6 +113,98 @@
fprintf(out, "// the single event tag id for all stats logs\n");
fprintf(out, "const static int kStatsEventTag = 1937006964;\n");
+ std::set<string> kTruncatingAtomNames = {"mobile_radio_power_state_changed",
+ "audio_state_changed",
+ "call_state_changed",
+ "phone_signal_strength_changed",
+ "mobile_bytes_transfer_by_fg_bg",
+ "mobile_bytes_transfer"};
+ fprintf(out,
+ "const std::set<int> "
+ "AtomsInfo::kNotTruncatingTimestampAtomWhiteList = {\n");
+ for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
+ atom != atoms.decls.end(); atom++) {
+ if (kTruncatingAtomNames.find(atom->name) ==
+ kTruncatingAtomNames.end()) {
+ string constant = make_constant_name(atom->name);
+ fprintf(out, " %s,\n", constant.c_str());
+ }
+ }
+ fprintf(out, "};\n");
+ fprintf(out, "\n");
+
+ fprintf(out,
+ "const std::set<int> AtomsInfo::kAtomsWithAttributionChain = {\n");
+ for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
+ atom != atoms.decls.end(); atom++) {
+ for (vector<AtomField>::const_iterator field = atom->fields.begin();
+ field != atom->fields.end(); field++) {
+ if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
+ string constant = make_constant_name(atom->name);
+ fprintf(out, " %s,\n", constant.c_str());
+ break;
+ }
+ }
+ }
+ fprintf(out, "};\n");
+ fprintf(out, "\n");
+
+ fprintf(out,
+ "static std::map<int, int> "
+ "getAtomUidField() {\n");
+ fprintf(out, " std::map<int, int> uidField;\n");
+ for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
+ atom != atoms.decls.end(); atom++) {
+ if (atom->uidField == 0) {
+ continue;
+ }
+ fprintf(out,
+ "\n // Adding uid field for atom "
+ "(%d)%s\n",
+ atom->code, atom->name.c_str());
+ fprintf(out, " uidField[static_cast<int>(%s)] = %d;\n",
+ make_constant_name(atom->name).c_str(), atom->uidField);
+ }
+
+ fprintf(out, " return uidField;\n");
+ fprintf(out, "};\n");
+
+ fprintf(out,
+ "const std::map<int, int> AtomsInfo::kAtomsWithUidField = "
+ "getAtomUidField();\n");
+
+ fprintf(out,
+ "static std::map<int, StateAtomFieldOptions> "
+ "getStateAtomFieldOptions() {\n");
+ fprintf(out, " std::map<int, StateAtomFieldOptions> options;\n");
+ fprintf(out, " StateAtomFieldOptions opt;\n");
+ for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
+ atom != atoms.decls.end(); atom++) {
+ if (atom->primaryFields.size() == 0 && atom->exclusiveField == 0) {
+ continue;
+ }
+ fprintf(out,
+ "\n // Adding primary and exclusive fields for atom "
+ "(%d)%s\n",
+ atom->code, atom->name.c_str());
+ fprintf(out, " opt.primaryFields.clear();\n");
+ for (const auto& field : atom->primaryFields) {
+ fprintf(out, " opt.primaryFields.push_back(%d);\n", field);
+ }
+
+ fprintf(out, " opt.exclusiveField = %d;\n", atom->exclusiveField);
+ fprintf(out, " options[static_cast<int>(%s)] = opt;\n",
+ make_constant_name(atom->name).c_str());
+ }
+
+ fprintf(out, " return options;\n");
+ fprintf(out, " }\n");
+
+ fprintf(out,
+ "const std::map<int, StateAtomFieldOptions> "
+ "AtomsInfo::kStateAtomsFieldOptions = "
+ "getStateAtomFieldOptions();\n");
+
// Print write methods
fprintf(out, "\n");
for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin();
@@ -366,89 +458,26 @@
fprintf(out, "};\n");
fprintf(out, "\n");
- std::set<string> kTruncatingAtomNames =
- { "mobile_radio_power_state_changed", "audio_state_changed", "call_state_changed",
- "phone_signal_strength_changed", "mobile_bytes_transfer_by_fg_bg",
- "mobile_bytes_transfer"};
- fprintf(out, "const static std::set<int> kNotTruncatingTimestampAtomWhiteList = {\n");
- for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
- atom != atoms.decls.end(); atom++) {
- if (kTruncatingAtomNames.find(atom->name) == kTruncatingAtomNames.end()) {
- string constant = make_constant_name(atom->name);
- fprintf(out, " %s,\n", constant.c_str());
- }
- }
- fprintf(out, "};\n");
- fprintf(out, "\n");
-
- fprintf(out, "const static std::set<int> kAtomsWithUidField = {\n");
- for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
- atom != atoms.decls.end(); atom++) {
- for (vector<AtomField>::const_iterator field = atom->fields.begin();
- field != atom->fields.end(); field++) {
- if (field->name == "uid") {
- string constant = make_constant_name(atom->name);
- fprintf(out, " %s,\n", constant.c_str());
- break;
- }
- }
- }
- fprintf(out, "};\n");
- fprintf(out, "\n");
-
- fprintf(out, "const static std::set<int> kAtomsWithAttributionChain = {\n");
- for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
- atom != atoms.decls.end(); atom++) {
- for (vector<AtomField>::const_iterator field = atom->fields.begin();
- field != atom->fields.end(); field++) {
- if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- string constant = make_constant_name(atom->name);
- fprintf(out, " %s,\n", constant.c_str());
- break;
- }
- }
- }
- fprintf(out, "};\n");
- fprintf(out, "\n");
-
- fprintf(out, "const static int kMaxPushedAtomId = %d;\n\n", maxPushedAtomId);
-
fprintf(out, "struct StateAtomFieldOptions {\n");
fprintf(out, " std::vector<int> primaryFields;\n");
fprintf(out, " int exclusiveField;\n");
+ fprintf(out, "};\n");
fprintf(out, "\n");
+
+ fprintf(out, "struct AtomsInfo {\n");
fprintf(out,
- " static std::map<int, StateAtomFieldOptions> "
- "getStateAtomFieldOptions() {\n");
- fprintf(out, " std::map<int, StateAtomFieldOptions> options;\n");
- fprintf(out, " StateAtomFieldOptions opt;\n");
- for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
- atom != atoms.decls.end(); atom++) {
- if (atom->primaryFields.size() == 0 && atom->exclusiveField == 0) {
- continue;
- }
- fprintf(out,
- "\n // Adding primary and exclusive fields for atom "
- "(%d)%s\n",
- atom->code, atom->name.c_str());
- fprintf(out, " opt.primaryFields.clear();\n");
- for (const auto& field : atom->primaryFields) {
- fprintf(out, " opt.primaryFields.push_back(%d);\n", field);
- }
-
- fprintf(out, " opt.exclusiveField = %d;\n", atom->exclusiveField);
- fprintf(out, " options[static_cast<int>(%s)] = opt;\n",
- make_constant_name(atom->name).c_str());
- }
-
- fprintf(out, " return options;\n");
- fprintf(out, " }\n");
+ " const static std::set<int> "
+ "kNotTruncatingTimestampAtomWhiteList;\n");
+ fprintf(out, " const static std::map<int, int> kAtomsWithUidField;\n");
+ fprintf(out,
+ " const static std::set<int> kAtomsWithAttributionChain;\n");
+ fprintf(out,
+ " const static std::map<int, StateAtomFieldOptions> "
+ "kStateAtomsFieldOptions;\n");
fprintf(out, "};\n");
- fprintf(out,
- "const static std::map<int, StateAtomFieldOptions> "
- "kStateAtomsFieldOptions = "
- "StateAtomFieldOptions::getStateAtomFieldOptions();\n");
+ fprintf(out, "const static int kMaxPushedAtomId = %d;\n\n",
+ maxPushedAtomId);
// Print write methods
fprintf(out, "//\n");
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 309bc80..2f7b50d 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -28,7 +28,6 @@
import android.net.wifi.ISoftApCallback;
import android.net.wifi.PasspointManagementObjectDefinition;
import android.net.wifi.ScanResult;
-import android.net.wifi.ScanSettings;
import android.net.wifi.WifiActivityEnergyInfo;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
@@ -86,7 +85,7 @@
boolean disableNetwork(int netId, String packageName);
- void startScan(in ScanSettings requested, in WorkSource ws, String packageName);
+ void startScan(String packageName);
List<ScanResult> getScanResults(String callingPackage);
diff --git a/wifi/java/android/net/wifi/ScanSettings.aidl b/wifi/java/android/net/wifi/ScanSettings.aidl
deleted file mode 100644
index ebd2a39..0000000
--- a/wifi/java/android/net/wifi/ScanSettings.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2014, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi;
-
-parcelable ScanSettings;
diff --git a/wifi/java/android/net/wifi/ScanSettings.java b/wifi/java/android/net/wifi/ScanSettings.java
deleted file mode 100644
index 094ce34..0000000
--- a/wifi/java/android/net/wifi/ScanSettings.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (c) 2014, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.ArrayList;
-import java.util.Collection;
-
-/**
- * Bundle of customized scan settings
- *
- * @see WifiManager#startCustomizedScan
- *
- * @hide
- */
-public class ScanSettings implements Parcelable {
-
- /** channel set to scan. this can be null or empty, indicating a full scan */
- public Collection<WifiChannel> channelSet;
-
- /** public constructor */
- public ScanSettings() { }
-
- /** copy constructor */
- public ScanSettings(ScanSettings source) {
- if (source.channelSet != null)
- channelSet = new ArrayList<WifiChannel>(source.channelSet);
- }
-
- /** check for validity */
- public boolean isValid() {
- for (WifiChannel channel : channelSet)
- if (!channel.isValid()) return false;
- return true;
- }
-
- /** implement Parcelable interface */
- @Override
- public int describeContents() {
- return 0;
- }
-
- /** implement Parcelable interface */
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeInt(channelSet == null ? 0 : channelSet.size());
- if (channelSet != null)
- for (WifiChannel channel : channelSet) channel.writeToParcel(out, flags);
- }
-
- /** implement Parcelable interface */
- public static final Parcelable.Creator<ScanSettings> CREATOR =
- new Parcelable.Creator<ScanSettings>() {
- @Override
- public ScanSettings createFromParcel(Parcel in) {
- ScanSettings settings = new ScanSettings();
- int size = in.readInt();
- if (size > 0) {
- settings.channelSet = new ArrayList<WifiChannel>(size);
- while (size-- > 0)
- settings.channelSet.add(WifiChannel.CREATOR.createFromParcel(in));
- }
- return settings;
- }
-
- @Override
- public ScanSettings[] newArray(int size) {
- return new ScanSettings[size];
- }
- };
-}
diff --git a/wifi/java/android/net/wifi/WifiChannel.java b/wifi/java/android/net/wifi/WifiChannel.java
deleted file mode 100644
index 640481e..0000000
--- a/wifi/java/android/net/wifi/WifiChannel.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (c) 2014, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Wifi Channel
- *
- * @see ScanSettings
- *
- * @hide
- */
-public class WifiChannel implements Parcelable {
-
- private static final int MIN_FREQ_MHZ = 2412;
- private static final int MAX_FREQ_MHZ = 5825;
-
- private static final int MIN_CHANNEL_NUM = 1;
- private static final int MAX_CHANNEL_NUM = 196;
-
- /** frequency */
- public int freqMHz;
-
- /** channel number */
- public int channelNum;
-
- /** is it a DFS channel? */
- public boolean isDFS;
-
- /** public constructor */
- public WifiChannel() { }
-
- /** check for validity */
- public boolean isValid() {
- if (freqMHz < MIN_FREQ_MHZ || freqMHz > MAX_FREQ_MHZ) return false;
- if (channelNum < MIN_CHANNEL_NUM || channelNum > MAX_CHANNEL_NUM) return false;
- return true;
- }
-
- /** implement Parcelable interface */
- @Override
- public int describeContents() {
- return 0;
- }
-
- /** implement Parcelable interface */
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeInt(freqMHz);
- out.writeInt(channelNum);
- out.writeInt(isDFS ? 1 : 0);
- }
-
- /** implement Parcelable interface */
- public static final Parcelable.Creator<WifiChannel> CREATOR =
- new Parcelable.Creator<WifiChannel>() {
- @Override
- public WifiChannel createFromParcel(Parcel in) {
- WifiChannel channel = new WifiChannel();
- channel.freqMHz = in.readInt();
- channel.channelNum = in.readInt();
- channel.isDFS = in.readInt() != 0;
- return channel;
- }
-
- @Override
- public WifiChannel[] newArray(int size) {
- return new WifiChannel[size];
- }
- };
-}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index d2cdf8d..c8df087 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1634,7 +1634,7 @@
public boolean startScan(WorkSource workSource) {
try {
String packageName = mContext.getOpPackageName();
- mService.startScan(null, workSource, packageName);
+ mService.startScan(packageName);
return true;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();