Merge "Fix crash in Permission Controller approving bug reports (incident reports were working fine)" into qt-dev
diff --git a/Android.bp b/Android.bp
index 0fcc0d5..abf95a8 100644
--- a/Android.bp
+++ b/Android.bp
@@ -687,6 +687,7 @@
"core/java/com/android/server/DropboxLogTags.logtags",
"core/java/org/chromium/arc/EventLogTags.logtags",
+ ":apex-properties",
":platform-properties",
":framework-statslog-gen",
@@ -1834,4 +1835,4 @@
name: "framework-aidl-mappings",
srcs: [":framework-defaults"],
output: "framework-aidl-mappings.txt"
-}
\ No newline at end of file
+}
diff --git a/api/current.txt b/api/current.txt
index ec7df66..8b24826 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -38820,8 +38820,7 @@
field @Deprecated public static final String LOCATION_MODE = "location_mode";
field @Deprecated public static final int LOCATION_MODE_BATTERY_SAVING = 2; // 0x2
field @Deprecated public static final int LOCATION_MODE_HIGH_ACCURACY = 3; // 0x3
- field @Deprecated public static final int LOCATION_MODE_OFF = 0; // 0x0
- field @Deprecated public static final int LOCATION_MODE_ON = 3; // 0x3
+ field public static final int LOCATION_MODE_OFF = 0; // 0x0
field @Deprecated public static final int LOCATION_MODE_SENSORS_ONLY = 1; // 0x1
field @Deprecated public static final String LOCATION_PROVIDERS_ALLOWED = "location_providers_allowed";
field @Deprecated public static final String LOCK_PATTERN_ENABLED = "lock_pattern_autolock";
diff --git a/api/system-current.txt b/api/system-current.txt
index 2ce1ee1..36680a1 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1635,7 +1635,7 @@
method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public java.util.List<android.content.pm.ResolveInfo> queryIntentServicesAsUser(@NonNull android.content.Intent, int, @NonNull android.os.UserHandle);
method public abstract void registerDexModule(@NonNull String, @Nullable android.content.pm.PackageManager.DexModuleRegisterCallback);
method @RequiresPermission("android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS") public abstract void removeOnPermissionsChangeListener(@NonNull android.content.pm.PackageManager.OnPermissionsChangedListener);
- method @Deprecated public void replacePreferredActivity(@NonNull android.content.IntentFilter, int, @NonNull java.util.List<android.content.ComponentName>, @NonNull android.content.ComponentName);
+ method public void replacePreferredActivity(@NonNull android.content.IntentFilter, int, @NonNull java.util.List<android.content.ComponentName>, @NonNull android.content.ComponentName);
method @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) public abstract void revokeRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
method public void sendDeviceCustomizationReadyBroadcast();
method @RequiresPermission(allOf={android.Manifest.permission.SET_PREFERRED_APPLICATIONS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public abstract boolean setDefaultBrowserPackageNameAsUser(@Nullable String, int);
@@ -6046,6 +6046,7 @@
field public static final String LAST_SETUP_SHOWN = "last_setup_shown";
field public static final String LOCATION_ACCESS_CHECK_DELAY_MILLIS = "location_access_check_delay_millis";
field public static final String LOCATION_ACCESS_CHECK_INTERVAL_MILLIS = "location_access_check_interval_millis";
+ field public static final int LOCATION_MODE_ON = 3; // 0x3
field public static final String LOCATION_PERMISSIONS_UPGRADE_TO_Q_MODE = "location_permissions_upgrade_to_q_mode";
field public static final String LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS = "lock_screen_allow_private_notifications";
field public static final String LOCK_SCREEN_SHOW_NOTIFICATIONS = "lock_screen_show_notifications";
diff --git a/api/test-current.txt b/api/test-current.txt
index 77c3a94..aacf2c1 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -3205,6 +3205,7 @@
method public default void setShouldShowIme(int, boolean);
method public default void setShouldShowSystemDecors(int, boolean);
method public default void setShouldShowWithInsecureKeyguard(int, boolean);
+ method public default boolean shouldShowIme(int);
method public default boolean shouldShowSystemDecors(int);
}
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index a9f5208e..ec02b12 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -68,12 +68,8 @@
const int FIELD_ID_DUMP_REPORT_REASON = 8;
const int FIELD_ID_STRINGS = 9;
-const int FIELD_ID_ACTIVE_CONFIG_LIST = 1;
-const int FIELD_ID_CONFIG_ID = 1;
-const int FIELD_ID_CONFIG_UID = 2;
-const int FIELD_ID_ACTIVE_METRIC = 3;
-const int FIELD_ID_METRIC_ID = 1;
-const int FIELD_ID_TIME_TO_LIVE_NANOS = 2;
+// for ActiveConfigList
+const int FIELD_ID_ACTIVE_CONFIG_LIST_CONFIG = 1;
#define NS_PER_HOUR 3600 * NS_PER_SEC
@@ -523,7 +519,7 @@
std::lock_guard<std::mutex> lock(mMetricsMutex);
auto it = mMetricsManagers.find(key);
if (it != mMetricsManagers.end()) {
- WriteDataToDiskLocked(key, getElapsedRealtimeNs(), CONFIG_REMOVED,
+ WriteDataToDiskLocked(key, getElapsedRealtimeNs(), CONFIG_REMOVED,
NO_TIME_CONSTRAINTS);
mMetricsManagers.erase(it);
mUidMap->OnConfigRemoved(key);
@@ -613,7 +609,7 @@
mOnDiskDataConfigs.insert(key);
}
-void StatsLogProcessor::WriteMetricsActivationToDisk(int64_t currentTimeNs) {
+void StatsLogProcessor::SaveActiveConfigsToDisk(int64_t currentTimeNs) {
std::lock_guard<std::mutex> lock(mMetricsMutex);
const int64_t timeNs = getElapsedRealtimeNs();
@@ -629,28 +625,12 @@
mLastActiveMetricsWriteNs = timeNs;
ProtoOutputStream proto;
-
for (const auto& pair : mMetricsManagers) {
- uint64_t activeConfigListToken = proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
- FIELD_ID_ACTIVE_CONFIG_LIST);
- proto.write(FIELD_TYPE_INT64 | FIELD_ID_CONFIG_ID, (long long)pair.first.GetId());
- proto.write(FIELD_TYPE_INT32 | FIELD_ID_CONFIG_UID, pair.first.GetUid());
-
- vector<MetricProducer*> activeMetrics;
- pair.second->prepForShutDown(currentTimeNs);
- pair.second->getActiveMetrics(activeMetrics);
- for (MetricProducer* metric : activeMetrics) {
- if (metric->isActive()) {
- uint64_t metricToken = proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
- FIELD_ID_ACTIVE_METRIC);
- proto.write(FIELD_TYPE_INT64 | FIELD_ID_METRIC_ID,
- (long long)metric->getMetricId());
- proto.write(FIELD_TYPE_INT64 | FIELD_ID_TIME_TO_LIVE_NANOS,
- (long long)metric->getRemainingTtlNs(currentTimeNs));
- proto.end(metricToken);
- }
- }
- proto.end(activeConfigListToken);
+ const sp<MetricsManager>& metricsManager = pair.second;
+ uint64_t configToken = proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
+ FIELD_ID_ACTIVE_CONFIG_LIST_CONFIG);
+ metricsManager->writeActiveConfigToProtoOutputStream(currentTimeNs, &proto);
+ proto.end(configToken);
}
string file_name = StringPrintf("%s/active_metrics", STATS_ACTIVE_METRIC_DIR);
@@ -664,30 +644,45 @@
proto.flush(fd.get());
}
-void StatsLogProcessor::LoadMetricsActivationFromDisk() {
+void StatsLogProcessor::LoadActiveConfigsFromDisk() {
+ std::lock_guard<std::mutex> lock(mMetricsMutex);
+
string file_name = StringPrintf("%s/active_metrics", STATS_ACTIVE_METRIC_DIR);
int fd = open(file_name.c_str(), O_RDONLY | O_CLOEXEC);
- if (fd != -1) {
- string content;
- if (android::base::ReadFdToString(fd, &content)) {
- ActiveConfigList activeConfigList;
- if (activeConfigList.ParseFromString(content)) {
- for (int i = 0; i < activeConfigList.active_config_size(); i++) {
- const auto& config = activeConfigList.active_config(i);
- ConfigKey key(config.uid(), config.config_id());
- auto it = mMetricsManagers.find(key);
- if (it == mMetricsManagers.end()) {
- ALOGE("No config found for config %s", key.ToString().c_str());
- continue;
- }
- VLOG("Setting active config %s", key.ToString().c_str());
- it->second->setActiveMetrics(config, mTimeBaseNs);
- }
- }
- VLOG("Successfully loaded %d active configs.", activeConfigList.active_config_size());
- }
- close(fd);
+ if (-1 == fd) {
+ VLOG("Attempt to read %s but failed", file_name.c_str());
+ StorageManager::deleteFile(file_name.c_str());
+ return;
}
+ string content;
+ if (!android::base::ReadFdToString(fd, &content)) {
+ ALOGE("Attempt to read %s but failed", file_name.c_str());
+ close(fd);
+ StorageManager::deleteFile(file_name.c_str());
+ return;
+ }
+
+ close(fd);
+
+ ActiveConfigList activeConfigList;
+ if (!activeConfigList.ParseFromString(content)) {
+ ALOGE("Attempt to read %s but failed; failed to load active configs", file_name.c_str());
+ StorageManager::deleteFile(file_name.c_str());
+ return;
+ }
+ for (int i = 0; i < activeConfigList.config_size(); i++) {
+ const auto& config = activeConfigList.config(i);
+ ConfigKey key(config.uid(), config.id());
+ auto it = mMetricsManagers.find(key);
+ if (it == mMetricsManagers.end()) {
+ ALOGE("No config found for config %s", key.ToString().c_str());
+ continue;
+ }
+ VLOG("Setting active config %s", key.ToString().c_str());
+ it->second->loadActiveConfig(config, mTimeBaseNs);
+ }
+ VLOG("Successfully loaded %d active configs.", activeConfigList.config_size());
+
StorageManager::deleteFile(file_name.c_str());
}
@@ -709,7 +704,7 @@
}
}
-void StatsLogProcessor::WriteDataToDisk(const DumpReportReason dumpReportReason,
+void StatsLogProcessor::WriteDataToDisk(const DumpReportReason dumpReportReason,
const DumpLatency dumpLatency) {
std::lock_guard<std::mutex> lock(mMetricsMutex);
WriteDataToDiskLocked(dumpReportReason, dumpLatency);
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 6178a4b..0dc597b 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -89,11 +89,11 @@
void WriteDataToDisk(const DumpReportReason dumpReportReason,
const DumpLatency dumpLatency);
- /* Persist metric activation status onto disk. */
- void WriteMetricsActivationToDisk(int64_t currentTimeNs);
+ /* Persist configs containing metrics with active activations to disk. */
+ void SaveActiveConfigsToDisk(int64_t currentTimeNs);
- /* Load metric activation status from disk. */
- void LoadMetricsActivationFromDisk();
+ /* Load configs containing metrics with active activations from disk. */
+ void LoadActiveConfigsFromDisk();
// Reset all configs.
void resetConfigs();
@@ -221,6 +221,9 @@
FRIEND_TEST(StatsLogProcessorTest, TestDropWhenByteSizeTooLarge);
FRIEND_TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead);
FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBoot);
+ FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivations);
+ FRIEND_TEST(StatsLogProcessorTest,
+ TestActivationOnBootMultipleActivationsDifferentActivationTypes);
FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration1);
FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration2);
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 1433252..623a1f2 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -28,6 +28,7 @@
#include <android-base/file.h>
#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/PermissionController.h>
@@ -394,6 +395,10 @@
return cmd_log_app_breadcrumb(out, args);
}
+ if (!args[0].compare(String8("log-binary-push"))) {
+ return cmd_log_binary_push(out, args);
+ }
+
if (!args[0].compare(String8("clear-puller-cache"))) {
return cmd_clear_puller_cache(out);
}
@@ -461,6 +466,21 @@
dprintf(out, " STATE Integer in [0, 3], as per atoms.proto.\n");
dprintf(out, "\n");
dprintf(out, "\n");
+ dprintf(out,
+ "usage: adb shell cmd stats log-binary-push NAME VERSION STAGING ROLLBACK_ENABLED "
+ "LOW_LATENCY STATE EXPERIMENT_IDS\n");
+ dprintf(out, " Log a binary push state changed event.\n");
+ dprintf(out, " NAME The train name.\n");
+ dprintf(out, " VERSION The train version code.\n");
+ dprintf(out, " STAGING If this train requires a restart.\n");
+ dprintf(out, " ROLLBACK_ENABLED If rollback should be enabled for this install.\n");
+ dprintf(out, " LOW_LATENCY If the train requires low latency monitoring.\n");
+ dprintf(out, " STATE The status of the train push.\n");
+ dprintf(out, " Integer value of the enum in atoms.proto.\n");
+ dprintf(out, " EXPERIMENT_IDS Comma separated list of experiment ids.\n");
+ dprintf(out, " Leave blank for none.\n");
+ dprintf(out, "\n");
+ dprintf(out, "\n");
dprintf(out, "usage: adb shell cmd stats config remove [UID] [NAME]\n");
dprintf(out, "usage: adb shell cmd stats config update [UID] NAME\n");
dprintf(out, "\n");
@@ -506,7 +526,6 @@
dprintf(out, " --configs Send the list of configs in the name list instead of\n");
dprintf(out, " the currently active configs\n");
dprintf(out, " NAME LIST List of configuration names to be included in the broadcast.\n");
-
dprintf(out, "\n");
dprintf(out, "\n");
dprintf(out, "usage: adb shell cmd stats print-stats\n");
@@ -821,6 +840,39 @@
return NO_ERROR;
}
+status_t StatsService::cmd_log_binary_push(int out, const Vector<String8>& args) {
+ // Security checks are done in the sendBinaryPushStateChanged atom.
+ const int argCount = args.size();
+ if (argCount != 7 && argCount != 8) {
+ dprintf(out, "Incorrect number of argument supplied\n");
+ return UNKNOWN_ERROR;
+ }
+ android::String16 trainName = android::String16(args[1].c_str());
+ int64_t trainVersion = strtoll(args[2].c_str(), nullptr, 10);
+ int options = 0;
+ if (args[3] == "1") {
+ options = options | IStatsManager::FLAG_REQUIRE_STAGING;
+ }
+ if (args[4] == "1") {
+ options = options | IStatsManager::FLAG_ROLLBACK_ENABLED;
+ }
+ if (args[5] == "1") {
+ options = options | IStatsManager::FLAG_REQUIRE_LOW_LATENCY_MONITOR;
+ }
+ int32_t state = atoi(args[6].c_str());
+ vector<int64_t> experimentIds;
+ if (argCount == 8) {
+ vector<string> experimentIdsString = android::base::Split(string(args[7].c_str()), ",");
+ for (string experimentIdString : experimentIdsString) {
+ int64_t experimentId = strtoll(experimentIdString.c_str(), nullptr, 10);
+ experimentIds.push_back(experimentId);
+ }
+ }
+ dprintf(out, "Logging BinaryPushStateChanged\n");
+ sendBinaryPushStateChangedAtom(trainName, trainVersion, options, state, experimentIds);
+ return NO_ERROR;
+}
+
status_t StatsService::cmd_print_pulled_metrics(int out, const Vector<String8>& args) {
int s = atoi(args[1].c_str());
vector<shared_ptr<LogEvent> > stats;
@@ -986,7 +1038,7 @@
ENFORCE_UID(AID_SYSTEM);
VLOG("StatsService::informDeviceShutdown");
mProcessor->WriteDataToDisk(DEVICE_SHUTDOWN, FAST);
- mProcessor->WriteMetricsActivationToDisk(getElapsedRealtimeNs());
+ mProcessor->SaveActiveConfigsToDisk(getElapsedRealtimeNs());
return Status::ok();
}
@@ -1021,14 +1073,14 @@
void StatsService::Startup() {
mConfigManager->Startup();
- mProcessor->LoadMetricsActivationFromDisk();
+ mProcessor->LoadActiveConfigsFromDisk();
}
void StatsService::Terminate() {
ALOGI("StatsService::Terminating");
if (mProcessor != nullptr) {
mProcessor->WriteDataToDisk(TERMINATION_SIGNAL_RECEIVED, FAST);
- mProcessor->WriteMetricsActivationToDisk(getElapsedRealtimeNs());
+ mProcessor->SaveActiveConfigsToDisk(getElapsedRealtimeNs());
}
}
@@ -1202,56 +1254,90 @@
return Status::ok();
}
-Status StatsService::sendBinaryPushStateChangedAtom(const android::String16& trainName,
- int64_t trainVersionCode, int options,
- int32_t state,
+Status StatsService::sendBinaryPushStateChangedAtom(const android::String16& trainNameIn,
+ const int64_t trainVersionCodeIn,
+ const int options,
+ const int32_t state,
const std::vector<int64_t>& experimentIdsIn) {
+ // Note: We skip the usage stats op check here since we do not have a package name.
+ // This is ok since we are overloading the usage_stats permission.
+ // This method only sends data, it does not receive it.
+ pid_t pid = IPCThreadState::self()->getCallingPid();
uid_t uid = IPCThreadState::self()->getCallingUid();
- // For testing
- if (uid == AID_ROOT || uid == AID_SYSTEM || uid == AID_SHELL) {
- return ok();
+ // Root, system, and shell always have access
+ if (uid != AID_ROOT && uid != AID_SYSTEM && uid != AID_SHELL) {
+ // Caller must be granted these permissions
+ if (!checkCallingPermission(String16(kPermissionDump))) {
+ return exception(binder::Status::EX_SECURITY,
+ StringPrintf("UID %d / PID %d lacks permission %s", uid, pid,
+ kPermissionDump));
+ }
+ if (!checkCallingPermission(String16(kPermissionUsage))) {
+ return exception(binder::Status::EX_SECURITY,
+ StringPrintf("UID %d / PID %d lacks permission %s", uid, pid,
+ kPermissionUsage));
+ }
}
- // Caller must be granted these permissions
- if (!checkCallingPermission(String16(kPermissionDump))) {
- return exception(binder::Status::EX_SECURITY,
- StringPrintf("UID %d lacks permission %s", uid, kPermissionDump));
- }
- if (!checkCallingPermission(String16(kPermissionUsage))) {
- return exception(binder::Status::EX_SECURITY,
- StringPrintf("UID %d lacks permission %s", uid, kPermissionUsage));
- }
- // TODO: add verifier permission
-
bool readTrainInfoSuccess = false;
- InstallTrainInfo trainInfo;
- if (trainVersionCode == -1 || experimentIdsIn.empty() || trainName.size() == 0) {
- readTrainInfoSuccess = StorageManager::readTrainInfo(trainInfo);
- }
+ InstallTrainInfo trainInfoOnDisk;
+ readTrainInfoSuccess = StorageManager::readTrainInfo(trainInfoOnDisk);
- if (trainVersionCode == -1 && readTrainInfoSuccess) {
- trainVersionCode = trainInfo.trainVersionCode;
+ bool resetExperimentIds = false;
+ int64_t trainVersionCode = trainVersionCodeIn;
+ std::string trainNameUtf8 = std::string(String8(trainNameIn).string());
+ if (readTrainInfoSuccess) {
+ // Keep the old train version if we received an empty version.
+ if (trainVersionCodeIn == -1) {
+ trainVersionCode = trainInfoOnDisk.trainVersionCode;
+ } else if (trainVersionCodeIn != trainInfoOnDisk.trainVersionCode) {
+ // Reset experiment ids if we receive a new non-empty train version.
+ resetExperimentIds = true;
+ }
+
+ // Keep the old train name if we received an empty train name.
+ if (trainNameUtf8.size() == 0) {
+ trainNameUtf8 = trainInfoOnDisk.trainName;
+ } else if (trainNameUtf8 != trainInfoOnDisk.trainName) {
+ // Reset experiment ids if we received a new valid train name.
+ resetExperimentIds = true;
+ }
+
+ // Reset if we received a different experiment id.
+ if (!experimentIdsIn.empty() &&
+ (trainInfoOnDisk.experimentIds.empty() ||
+ experimentIdsIn[0] != trainInfoOnDisk.experimentIds[0])) {
+ resetExperimentIds = true;
+ }
}
// Find the right experiment IDs
std::vector<int64_t> experimentIds;
- if (readTrainInfoSuccess && experimentIdsIn.empty()) {
- experimentIds = trainInfo.experimentIds;
- } else {
+ if (resetExperimentIds || !readTrainInfoSuccess) {
experimentIds = experimentIdsIn;
+ } else {
+ experimentIds = trainInfoOnDisk.experimentIds;
+ }
+
+ if (!experimentIds.empty()) {
+ int64_t firstId = experimentIds[0];
+ switch (state) {
+ case android::util::BINARY_PUSH_STATE_CHANGED__STATE__INSTALL_SUCCESS:
+ experimentIds.push_back(firstId + 1);
+ break;
+ case android::util::BINARY_PUSH_STATE_CHANGED__STATE__INSTALLER_ROLLBACK_INITIATED:
+ experimentIds.push_back(firstId + 2);
+ break;
+ case android::util::BINARY_PUSH_STATE_CHANGED__STATE__INSTALLER_ROLLBACK_SUCCESS:
+ experimentIds.push_back(firstId + 3);
+ break;
+ }
}
// Flatten the experiment IDs to proto
vector<uint8_t> experimentIdsProtoBuffer;
writeExperimentIdsToProto(experimentIds, &experimentIdsProtoBuffer);
-
- // Find the right train name
- std::string trainNameUtf8;
- if (readTrainInfoSuccess && trainName.size() == 0) {
- trainNameUtf8 = trainInfo.trainName;
- } else {
- trainNameUtf8 = std::string(String8(trainName).string());
- }
+ StorageManager::writeTrainInfo(trainVersionCode, trainNameUtf8, state, experimentIds);
userid_t userId = multiuser_get_user_id(uid);
bool requiresStaging = options & IStatsManager::FLAG_REQUIRE_STAGING;
@@ -1260,7 +1346,6 @@
LogEvent event(trainNameUtf8, trainVersionCode, requiresStaging, rollbackEnabled,
requiresLowLatencyMonitor, state, experimentIdsProtoBuffer, userId);
mProcessor->OnLogEvent(&event);
- StorageManager::writeTrainInfo(trainVersionCode, trainNameUtf8, state, experimentIds);
return Status::ok();
}
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 929d260..936f7db 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -189,8 +189,11 @@
* Binder call to log BinaryPushStateChanged atom.
*/
virtual Status sendBinaryPushStateChangedAtom(
- const android::String16& trainName, int64_t trainVersionCode, int options,
- int32_t state, const std::vector<int64_t>& experimentIds) override;
+ const android::String16& trainNameIn,
+ const int64_t trainVersionCodeIn,
+ const int options,
+ const int32_t state,
+ const std::vector<int64_t>& experimentIdsIn) override;
/**
* Binder call to get registered experiment IDs.
@@ -328,6 +331,11 @@
status_t cmd_log_app_breadcrumb(int outFd, const Vector<String8>& args);
/**
+ * Write an BinaryPushStateChanged event, as if calling StatsLog.logBinaryPushStateChanged().
+ */
+ status_t cmd_log_binary_push(int outFd, const Vector<String8>& args);
+
+ /**
* Print contents of a pulled metrics source.
*/
status_t cmd_print_pulled_metrics(int outFd, const Vector<String8>& args);
diff --git a/cmds/statsd/src/active_config_list.proto b/cmds/statsd/src/active_config_list.proto
index 0e9ee03..ef8e50b 100644
--- a/cmds/statsd/src/active_config_list.proto
+++ b/cmds/statsd/src/active_config_list.proto
@@ -21,23 +21,26 @@
option java_multiple_files = true;
option java_outer_classname = "ActiveConfigProto";
+message ActiveEventActivation {
+ optional int32 atom_matcher_index = 1;
+
+ // Time left in activation. When this proto is loaded after device boot,
+ // the activation should be set to active for this duration.
+ optional int64 remaining_ttl_nanos = 2;
+}
+
message ActiveMetric {
- // metric id
- optional int64 metric_id = 1;
- // Remaining time to live in nano seconds. -1 for infinity.
- optional int64 time_to_live_nanos = 2;
+ optional int64 id = 1;
+ repeated ActiveEventActivation activation = 2;
}
message ActiveConfig {
- // config id
- optional int64 config_id = 1;
- // config uid
+ optional int64 id = 1;
optional int32 uid = 2;
- // metrics
- repeated ActiveMetric active_metric = 3;
+ repeated ActiveMetric metric = 3;
}
// all configs and their metrics on device.
message ActiveConfigList {
- repeated ActiveConfig active_config = 1;
-}
\ No newline at end of file
+ repeated ActiveConfig config = 1;
+}
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 2bd4299..3a84b79 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -48,6 +48,7 @@
import "frameworks/base/core/proto/android/stats/enums.proto";
import "frameworks/base/core/proto/android/stats/intelligence/enums.proto";
import "frameworks/base/core/proto/android/stats/launcher/launcher.proto";
+import "frameworks/base/core/proto/android/stats/mediametrics/mediametrics.proto";
import "frameworks/base/core/proto/android/stats/storage/storage_enums.proto";
import "frameworks/base/core/proto/android/stats/style/style_enums.proto";
import "frameworks/base/core/proto/android/telecomm/enums.proto";
@@ -283,6 +284,16 @@
ThermalThrottlingSeverityStateChanged thermal_throttling_severity_state_changed = 189;
RoleRequestResultReported role_request_result_reported =
190 [(log_from_module) = "permissioncontroller"];
+ MediametricsAudiopolicyReported mediametrics_audiopolicy_reported = 191;
+ MediametricsAudiorecordReported mediametrics_audiorecord_reported = 192;
+ MediametricsAudiothreadReported mediametrics_audiothread_reported = 193;
+ MediametricsAudiotrackReported mediametrics_audiotrack_reported = 194;
+ MediametricsCodecReported mediametrics_codec_reported = 195;
+ MediametricsDrmWidevineReported mediametrics_drm_widevine_reported = 196;
+ MediametricsExtractorReported mediametrics_extractor_reported = 197;
+ MediametricsMediadrmReported mediametrics_mediadrm_reported = 198;
+ MediametricsNuPlayerReported mediametrics_nuplayer_reported = 199;
+ MediametricsRecorderReported mediametrics_recorder_reported = 200;
}
// Pulled events will start at field 10000.
@@ -3296,7 +3307,10 @@
INSTALL_STAGED_NOT_READY = 3;
INSTALL_STAGED_READY = 4;
INSTALL_SUCCESS = 5;
- INSTALL_FAILURE = 6;
+ // Replaced by INSTALL_FAILURE_DOWNLOAD, INSTALL_FAILURE_STATE_MISMATCH,
+ // and INSTALL_FAILURE_COMMIT.
+ INSTALL_FAILURE = 6 [deprecated = true];
+ // This enum is for installs that are manually cancelled via the Manual Update UI.
INSTALL_CANCELLED = 7;
INSTALLER_ROLLBACK_REQUESTED = 8;
INSTALLER_ROLLBACK_INITIATED = 9;
@@ -3313,6 +3327,9 @@
INSTALL_STAGED_CANCEL_REQUESTED = 20;
INSTALL_STAGED_CANCEL_SUCCESS = 21;
INSTALL_STAGED_CANCEL_FAILURE = 22;
+ INSTALL_FAILURE_DOWNLOAD = 23;
+ INSTALL_FAILURE_STATE_MISMATCH = 24;
+ INSTALL_FAILURE_COMMIT = 25;
}
optional State state = 6;
// Possible experiment ids for monitoring this push.
@@ -5809,6 +5826,160 @@
}
/**
+ * Track Media Codec usage
+ * Logged from:
+ * frameworks/av/media/libstagefright/MediaCodec.cpp
+ * frameworks/av/services/mediaanalytics/statsd_codec.cpp
+ */
+message MediametricsCodecReported {
+ optional int64 timestamp_nanos = 1;
+ optional string package_name = 2;
+ optional int64 package_version_code = 3;
+ optional int64 media_apex_version = 4;
+
+ optional android.stats.mediametrics.CodecData codec_data = 5 [(android.os.statsd.log_mode) = MODE_BYTES];
+}
+
+/**
+ * Track Media Extractor (pulling video/audio streams out of containers) usage
+ * Logged from:
+ * frameworks/av/media/libstagefright/RemoteMediaExtractor.cpp
+ * frameworks/av/services/mediaanalytics/statsd_extractor.cpp
+ */
+message MediametricsExtractorReported {
+ optional int64 timestamp_nanos = 1;
+ optional string package_name = 2;
+ optional int64 package_version_code = 3;
+ optional int64 media_apex_version = 4;
+
+ optional android.stats.mediametrics.ExtractorData extractor_data = 5 [(android.os.statsd.log_mode) = MODE_BYTES];
+}
+
+/**
+ * Track how we arbitrate between microphone/input requests.
+ * Logged from
+ * frameworks/av/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+ * frameworks/av/services/mediaanalytics/statsd_audiopolicy.cpp
+ */
+message MediametricsAudiopolicyReported {
+ optional int64 timestamp_nanos = 1;
+ optional string package_name = 2;
+ optional int64 package_version_code = 3;
+ optional int64 media_apex_version = 4;
+
+ optional android.stats.mediametrics.AudioPolicyData audiopolicy_data = 5 [(android.os.statsd.log_mode) = MODE_BYTES];
+}
+
+/**
+ * Track how we arbitrate between microphone requests.
+ * Logged from
+ * frameworks/av/media/libaudioclient/AudioRecord.cpp
+ * frameworks/av/services/mediaanalytics/statsd_audiorecord.cpp
+ */
+message MediametricsAudiorecordReported {
+ optional int64 timestamp_nanos = 1;
+ optional string package_name = 2;
+ optional int64 package_version_code = 3;
+ optional int64 media_apex_version = 4;
+
+ optional android.stats.mediametrics.AudioRecordData audiorecord_data = 5 [(android.os.statsd.log_mode) = MODE_BYTES];
+}
+
+/**
+ * Track how we arbitrate between microphone/input requests.
+ * Logged from
+ * frameworks/av/media/libnblog/ReportPerformance.cpp
+ * frameworks/av/services/mediaanalytics/statsd_audiothread.cpp
+ */
+message MediametricsAudiothreadReported {
+ optional int64 timestamp_nanos = 1;
+ optional string package_name = 2;
+ optional int64 package_version_code = 3;
+ optional int64 media_apex_version = 4;
+
+ optional android.stats.mediametrics.AudioThreadData audiothread_data = 5 [(android.os.statsd.log_mode) = MODE_BYTES];
+}
+
+/**
+ * Track how we arbitrate between microphone/input requests.
+ * Logged from
+ * frameworks/av/media/libaudioclient/AudioTrack.cpp
+ * frameworks/av/services/mediaanalytics/statsd_audiotrack.cpp
+ */
+message MediametricsAudiotrackReported {
+ optional int64 timestamp_nanos = 1;
+ optional string package_name = 2;
+ optional int64 package_version_code = 3;
+ optional int64 media_apex_version = 4;
+
+ optional android.stats.mediametrics.AudioTrackData audiotrack_data = 5 [(android.os.statsd.log_mode) = MODE_BYTES];
+}
+
+/**
+ * Track information about DRM framework performance
+ * Logged from
+ * frameworks/av/drm/libmediadrm/DrmHal.cpp
+ * frameworks/av/services/mediaanalytics/statsd_drm.cpp
+ */
+message MediametricsMediadrmReported {
+ optional int64 timestamp_nanos = 1;
+ optional string package_name = 2;
+ optional int64 package_version_code = 3;
+ optional int64 media_apex_version = 4;
+
+ // vendor+description tell about which DRM plugin is in use on this device
+ optional string vendor = 5;
+ optional string description = 6;
+ // from frameworks/av/drm/libmediadrm/protos/metrics.proto
+ optional bytes framework_stats = 7 [(android.os.statsd.log_mode) = MODE_BYTES];
+}
+
+/**
+ * Track information about the widevine DRM plugin performance
+ * Logged from
+ * vendor/widevine/libwvdrmengine/cdm/metrics
+ * frameworks/av/services/mediaanalytics/statsd_drm.cpp
+ */
+message MediametricsDrmWidevineReported {
+ optional int64 timestamp_nanos = 1;
+ optional string package_name = 2;
+ optional int64 package_version_code = 3;
+ optional int64 media_apex_version = 4;
+
+ optional bytes vendor_specific_stats = 5 [(android.os.statsd.log_mode) = MODE_BYTES];
+}
+
+/**
+ * Track information about recordings (e.g. camcorder)
+ * Logged from
+ * frameworks/av/media/libmediaplayerservice/StagefrightRecorder.cpp
+ * frameworks/av/services/mediaanalytics/statsd_recorder.cpp
+ */
+message MediametricsRecorderReported {
+ optional int64 timestamp_nanos = 1;
+ optional string package_name = 2;
+ optional int64 package_version_code = 3;
+ optional int64 media_apex_version = 4;
+
+ optional android.stats.mediametrics.RecorderData recorder_data = 5 [(android.os.statsd.log_mode) = MODE_BYTES];
+}
+
+/**
+ * Track Media Player usage
+ * Logged from:
+ * frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+ * frameworks/av/services/mediaanalytics/statsd_nuplayer.cpp
+ */
+message MediametricsNuPlayerReported {
+ optional int64 timestamp_nanos = 1;
+ optional string package_name = 2;
+ optional int64 package_version_code = 3;
+ optional int64 media_apex_version = 4;
+
+ optional android.stats.mediametrics.NuPlayerData nuplayer_data = 5 [(android.os.statsd.log_mode) = MODE_BYTES];
+}
+
+/**
* State of a dangerous permission requested by a package
*/
message DangerousPermissionState {
@@ -5863,7 +6034,10 @@
INSTALL_STAGED_NOT_READY = 3;
INSTALL_STAGED_READY = 4;
INSTALL_SUCCESS = 5;
- INSTALL_FAILURE = 6;
+ // Replaced by INSTALL_FAILURE_DOWNLOAD, INSTALL_FAILURE_STATE_MISMATCH,
+ // and INSTALL_FAILURE_COMMIT.
+ INSTALL_FAILURE = 6 [deprecated = true];
+ // This enum is for installs that are manually cancelled via the Manual Update UI.
INSTALL_CANCELLED = 7;
INSTALLER_ROLLBACK_REQUESTED = 8;
INSTALLER_ROLLBACK_INITIATED = 9;
@@ -5880,6 +6054,9 @@
INSTALL_STAGED_CANCEL_REQUESTED = 20;
INSTALL_STAGED_CANCEL_SUCCESS = 21;
INSTALL_STAGED_CANCEL_FAILURE = 22;
+ INSTALL_FAILURE_DOWNLOAD = 23;
+ INSTALL_FAILURE_STATE_MISMATCH = 24;
+ INSTALL_FAILURE_COMMIT = 25;
}
optional Status status = 4;
}
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index ca874b5..0ade531 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -678,7 +678,8 @@
writeFieldValueTreeToStream(mTagId, getValues(), &protoOutput);
}
-void writeExperimentIdsToProto(const std::vector<int64_t>& experimentIds, std::vector<uint8_t>* protoOut) {
+void writeExperimentIdsToProto(const std::vector<int64_t>& experimentIds,
+ std::vector<uint8_t>* protoOut) {
ProtoOutputStream proto;
for (const auto& expId : experimentIds) {
proto.write(FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED | FIELD_ID_EXPERIMENT_ID,
diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp
index e22b853..9ad7f09 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -18,12 +18,26 @@
#include "Log.h"
#include "MetricProducer.h"
+using android::util::FIELD_COUNT_REPEATED;
+using android::util::FIELD_TYPE_INT32;
+using android::util::FIELD_TYPE_INT64;
+using android::util::FIELD_TYPE_MESSAGE;
+using android::util::ProtoOutputStream;
+
namespace android {
namespace os {
namespace statsd {
using std::map;
+// for ActiveMetric
+const int FIELD_ID_ACTIVE_METRIC_ID = 1;
+const int FIELD_ID_ACTIVE_METRIC_ACTIVATION = 2;
+
+// for ActiveEventActivation
+const int FIELD_ID_ACTIVE_EVENT_ACTIVATION_ATOM_MATCHER_INDEX = 1;
+const int FIELD_ID_ACTIVE_EVENT_ACTIVATION_REMAINING_TTL_NANOS = 2;
+
void MetricProducer::onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event) {
if (!mIsActive) {
return;
@@ -74,7 +88,7 @@
bool isActive = mEventActivationMap.empty();
for (auto& it : mEventActivationMap) {
if (it.second->state == ActivationState::kActive &&
- elapsedTimestampNs > it.second->ttl_ns + it.second->activation_ns) {
+ elapsedTimestampNs > it.second->ttl_ns + it.second->start_ns) {
it.second->state = ActivationState::kNotActive;
}
if (it.second->state == ActivationState::kActive) {
@@ -95,8 +109,8 @@
}
}
-void MetricProducer::addActivation(int activationTrackerIndex, int64_t ttl_seconds,
- int deactivationTrackerIndex) {
+void MetricProducer::addActivation(int activationTrackerIndex, const ActivationType& activationType,
+ int64_t ttl_seconds, int deactivationTrackerIndex) {
std::lock_guard<std::mutex> lock(mMutex);
// When a metric producer does not depend on any activation, its mIsActive is true.
// Therefore, if this is the 1st activation, mIsActive will turn to false. Otherwise it does not
@@ -104,8 +118,8 @@
if (mEventActivationMap.empty()) {
mIsActive = false;
}
- std::shared_ptr<Activation> activation = std::make_shared<Activation>();
- activation->ttl_ns = ttl_seconds * NS_PER_SEC;
+ std::shared_ptr<Activation> activation =
+ std::make_shared<Activation>(activationType, ttl_seconds * NS_PER_SEC);
mEventActivationMap.emplace(activationTrackerIndex, activation);
if (-1 != deactivationTrackerIndex) {
mEventDeactivationMap.emplace(deactivationTrackerIndex, activation);
@@ -117,13 +131,16 @@
if (it == mEventActivationMap.end()) {
return;
}
- if (mActivationType == MetricActivation::ACTIVATE_ON_BOOT &&
- it->second->state == ActivationState::kNotActive) {
- it->second->state = ActivationState::kActiveOnBoot;
+ auto& activation = it->second;
+ if (ACTIVATE_ON_BOOT == activation->activationType) {
+ if (ActivationState::kNotActive == activation->state) {
+ activation->state = ActivationState::kActiveOnBoot;
+ }
+ // If the Activation is already active or set to kActiveOnBoot, do nothing.
return;
}
- it->second->activation_ns = elapsedTimestampNs;
- it->second->state = ActivationState::kActive;
+ activation->start_ns = elapsedTimestampNs;
+ activation->state = ActivationState::kActive;
mIsActive = true;
}
@@ -135,46 +152,55 @@
it->second->state = ActivationState::kNotActive;
}
-void MetricProducer::setActiveLocked(int64_t currentTimeNs, int64_t remainingTtlNs) {
+void MetricProducer::loadActiveMetricLocked(const ActiveMetric& activeMetric,
+ int64_t currentTimeNs) {
if (mEventActivationMap.size() == 0) {
return;
}
- for (auto& pair : mEventActivationMap) {
- auto& activation = pair.second;
- if (activation->ttl_ns >= remainingTtlNs) {
- activation->activation_ns = currentTimeNs + remainingTtlNs - activation->ttl_ns;
- activation->state = kActive;
- mIsActive = true;
- VLOG("setting new activation->time to %lld, %lld, %lld",
- (long long)activation->activation_ns, (long long)currentTimeNs,
- (long long)remainingTtlNs);
- return;
+ for (int i = 0; i < activeMetric.activation_size(); i++) {
+ const auto& activeEventActivation = activeMetric.activation(i);
+ auto it = mEventActivationMap.find(activeEventActivation.atom_matcher_index());
+ if (it == mEventActivationMap.end()) {
+ ALOGE("Saved event activation not found");
+ continue;
}
+ auto& activation = it->second;
+ // We don't want to change the ttl for future activations, so we set the start_ns
+ // such that start_ns + ttl_ns == currentTimeNs + remaining_ttl_nanos
+ activation->start_ns =
+ currentTimeNs + activeEventActivation.remaining_ttl_nanos() - activation->ttl_ns;
+ activation->state = ActivationState::kActive;
+ mIsActive = true;
}
- ALOGE("Required ttl is longer than all possible activations.");
}
-int64_t MetricProducer::getRemainingTtlNsLocked(int64_t currentTimeNs) const {
- int64_t maxTtl = 0;
- for (const auto& activation : mEventActivationMap) {
- if (activation.second->state == kActive) {
- maxTtl = std::max(maxTtl, activation.second->ttl_ns + activation.second->activation_ns -
- currentTimeNs);
- }
- }
- return maxTtl;
-}
+void MetricProducer::writeActiveMetricToProtoOutputStream(
+ int64_t currentTimeNs, ProtoOutputStream* proto) {
+ proto->write(FIELD_TYPE_INT64 | FIELD_ID_ACTIVE_METRIC_ID, (long long)mMetricId);
+ for (auto& it : mEventActivationMap) {
+ const int atom_matcher_index = it.first;
+ const std::shared_ptr<Activation>& activation = it.second;
-void MetricProducer::prepActiveForBootIfNecessaryLocked(int64_t currentTimeNs) {
- if (mActivationType != MetricActivation::ACTIVATE_ON_BOOT) {
- return;
- }
- for (auto& activation : mEventActivationMap) {
- if (activation.second->state == kActiveOnBoot) {
- activation.second->state = kActive;
- activation.second->activation_ns = currentTimeNs;
- mIsActive = true;
+ if (ActivationState::kNotActive == activation->state ||
+ (ActivationState::kActive == activation->state &&
+ activation->start_ns + activation->ttl_ns < currentTimeNs)) {
+ continue;
}
+
+ const uint64_t activationToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
+ FIELD_ID_ACTIVE_METRIC_ACTIVATION);
+ proto->write(FIELD_TYPE_INT32 | FIELD_ID_ACTIVE_EVENT_ACTIVATION_ATOM_MATCHER_INDEX,
+ atom_matcher_index);
+ if (ActivationState::kActive == activation->state) {
+ const int64_t remainingTtlNs =
+ activation->start_ns + activation->ttl_ns - currentTimeNs;
+ proto->write(FIELD_TYPE_INT64 | FIELD_ID_ACTIVE_EVENT_ACTIVATION_REMAINING_TTL_NANOS,
+ (long long)remainingTtlNs);
+ } else if (ActivationState::kActiveOnBoot == activation->state) {
+ proto->write(FIELD_TYPE_INT64 | FIELD_ID_ACTIVE_EVENT_ACTIVATION_REMAINING_TTL_NANOS,
+ (long long)activation->ttl_ns);
+ }
+ proto->end(activationToken);
}
}
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 750566d..7676f59 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -19,6 +19,7 @@
#include <shared_mutex>
+#include <frameworks/base/cmds/statsd/src/active_config_list.pb.h>
#include "HashableDimensionKey.h"
#include "anomaly/AnomalyTracker.h"
#include "condition/ConditionWizard.h"
@@ -198,15 +199,9 @@
return mMetricId;
}
- int64_t getRemainingTtlNs(int64_t currentTimeNs) const {
+ void loadActiveMetric(const ActiveMetric& activeMetric, int64_t currentTimeNs) {
std::lock_guard<std::mutex> lock(mMutex);
- return getRemainingTtlNsLocked(currentTimeNs);
- }
-
- // Set metric to active for ttlNs.
- void setActive(int64_t currentTimeNs, int64_t remainingTtlNs) {
- std::lock_guard<std::mutex> lock(mMutex);
- setActiveLocked(currentTimeNs, remainingTtlNs);
+ loadActiveMetricLocked(activeMetric, currentTimeNs);
}
// Let MetricProducer drop in-memory data to save memory.
@@ -238,17 +233,8 @@
return isActiveLocked();
}
- void prepActiveForBootIfNecessary(int64_t currentTimeNs) {
- std::lock_guard<std::mutex> lock(mMutex);
- prepActiveForBootIfNecessaryLocked(currentTimeNs);
- }
-
- void addActivation(int activationTrackerIndex, int64_t ttl_seconds,
- int deactivationTrackerIndex = -1);
-
- inline void setActivationType(const MetricActivation::ActivationType& activationType) {
- mActivationType = activationType;
- }
+ void addActivation(int activationTrackerIndex, const ActivationType& activationType,
+ int64_t ttl_seconds, int deactivationTrackerIndex = -1);
void prepareFistBucket() {
std::lock_guard<std::mutex> lock(mMutex);
@@ -257,6 +243,8 @@
void flushIfExpire(int64_t elapsedTimestampNs);
+ void writeActiveMetricToProtoOutputStream(
+ int64_t currentTimeNs, ProtoOutputStream* proto);
protected:
virtual void onConditionChangedLocked(const bool condition, const int64_t eventTime) = 0;
virtual void onSlicedConditionMayChangeLocked(bool overallCondition,
@@ -282,9 +270,7 @@
void prepActiveForBootIfNecessaryLocked(int64_t currentTimeNs);
- int64_t getRemainingTtlNsLocked(int64_t currentTimeNs) const;
-
- void setActiveLocked(int64_t currentTimeNs, int64_t remainingTtlNs);
+ void loadActiveMetricLocked(const ActiveMetric& activeMetric, int64_t currentTimeNs);
virtual void prepareFistBucketLocked() {};
/**
@@ -396,11 +382,16 @@
mutable std::mutex mMutex;
struct Activation {
- Activation() : ttl_ns(0), activation_ns(0), state(ActivationState::kNotActive) {}
+ Activation(const ActivationType& activationType, const int64_t ttlNs)
+ : ttl_ns(ttlNs),
+ start_ns(0),
+ state(ActivationState::kNotActive),
+ activationType(activationType) {}
- int64_t ttl_ns;
- int64_t activation_ns;
+ const int64_t ttl_ns;
+ int64_t start_ns;
ActivationState state;
+ const ActivationType activationType;
};
// When the metric producer has multiple activations, these activations are ORed to determine
// whether the metric producer is ready to generate metrics.
@@ -411,8 +402,6 @@
bool mIsActive;
- MetricActivation::ActivationType mActivationType;
-
FRIEND_TEST(MetricActivationE2eTest, TestCountMetric);
FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithOneDeactivation);
FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithTwoDeactivations);
@@ -420,6 +409,9 @@
FRIEND_TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead);
FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBoot);
+ FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivations);
+ FRIEND_TEST(StatsLogProcessorTest,
+ TestActivationOnBootMultipleActivationsDifferentActivationTypes);
};
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 6a55289..947f377 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -54,6 +54,11 @@
const int FIELD_ID_ANNOTATIONS_INT64 = 1;
const int FIELD_ID_ANNOTATIONS_INT32 = 2;
+// for ActiveConfig
+const int FIELD_ID_ACTIVE_CONFIG_ID = 1;
+const int FIELD_ID_ACTIVE_CONFIG_UID = 2;
+const int FIELD_ID_ACTIVE_CONFIG_METRIC = 3;
+
MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config,
const int64_t timeBaseNs, const int64_t currentTimeNs,
const sp<UidMap>& uidMap,
@@ -503,25 +508,41 @@
return totalSize;
}
-void MetricsManager::setActiveMetrics(ActiveConfig config, int64_t currentTimeNs) {
- if (config.active_metric_size() == 0) {
+void MetricsManager::loadActiveConfig(const ActiveConfig& config, int64_t currentTimeNs) {
+ if (config.metric_size() == 0) {
ALOGW("No active metric for config %s", mConfigKey.ToString().c_str());
return;
}
- for (int i = 0; i < config.active_metric_size(); i++) {
- for (int metric : mMetricIndexesWithActivation) {
- if (mAllMetricProducers[metric]->getMetricId() == config.active_metric(i).metric_id()) {
- VLOG("Setting active metric: %lld",
- (long long)mAllMetricProducers[metric]->getMetricId());
- mAllMetricProducers[metric]->setActive(
- currentTimeNs, config.active_metric(i).time_to_live_nanos());
- mIsActive = true;
+ for (int i = 0; i < config.metric_size(); i++) {
+ const auto& activeMetric = config.metric(i);
+ for (int metricIndex : mMetricIndexesWithActivation) {
+ const auto& metric = mAllMetricProducers[metricIndex];
+ if (metric->getMetricId() == activeMetric.id()) {
+ VLOG("Setting active metric: %lld", (long long)metric->getMetricId());
+ metric->loadActiveMetric(activeMetric, currentTimeNs);
+ mIsActive |= metric->isActive();
}
}
}
}
+void MetricsManager::writeActiveConfigToProtoOutputStream(
+ int64_t currentTimeNs, ProtoOutputStream* proto) {
+ proto->write(FIELD_TYPE_INT64 | FIELD_ID_ACTIVE_CONFIG_ID, (long long)mConfigKey.GetId());
+ proto->write(FIELD_TYPE_INT32 | FIELD_ID_ACTIVE_CONFIG_UID, mConfigKey.GetUid());
+ for (int metricIndex : mMetricIndexesWithActivation) {
+ const auto& metric = mAllMetricProducers[metricIndex];
+ const uint64_t metricToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
+ FIELD_ID_ACTIVE_CONFIG_METRIC);
+ metric->writeActiveMetricToProtoOutputStream(currentTimeNs, proto);
+ proto->end(metricToken);
+ }
+}
+
+
+
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index d05bb8b..818131e 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -16,7 +16,6 @@
#pragma once
-#include <frameworks/base/cmds/statsd/src/active_config_list.pb.h>
#include "anomaly/AlarmMonitor.h"
#include "anomaly/AlarmTracker.h"
#include "anomaly/AnomalyTracker.h"
@@ -139,21 +138,10 @@
return mIsActive;
}
- inline void getActiveMetrics(std::vector<MetricProducer*>& metrics) const {
- for (const auto& metric : mAllMetricProducers) {
- if (metric->isActive()) {
- metrics.push_back(metric.get());
- }
- }
- }
+ void loadActiveConfig(const ActiveConfig& config, int64_t currentTimeNs);
- inline void prepForShutDown(int64_t currentTimeNs) {
- for (const auto& metric : mAllMetricProducers) {
- metric->prepActiveForBootIfNecessary(currentTimeNs);
- }
- }
-
- void setActiveMetrics(ActiveConfig config, int64_t currentTimeNs);
+ void writeActiveConfigToProtoOutputStream(
+ int64_t currentTimeNs, ProtoOutputStream* proto);
private:
// For test only.
@@ -299,6 +287,9 @@
FRIEND_TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead);
FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBoot);
+ FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivations);
+ FRIEND_TEST(StatsLogProcessorTest,
+ TestActivationOnBootMultipleActivationsDifferentActivationTypes);
};
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index 31b424e..b027fa0 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -727,7 +727,6 @@
return false;
}
const sp<MetricProducer>& metric = allMetricProducers[metricTrackerIndex];
- metric->setActivationType(metric_activation.activation_type());
metricsWithActivation.push_back(metricTrackerIndex);
for (int j = 0; j < metric_activation.event_activation_size(); ++j) {
const EventActivation& activation = metric_activation.event_activation(j);
@@ -740,6 +739,13 @@
activationAtomTrackerToMetricMap[atomMatcherIndex].push_back(
metricTrackerIndex);
+ ActivationType activationType;
+ if (activation.has_activation_type()) {
+ activationType = activation.activation_type();
+ } else {
+ activationType = metric_activation.activation_type();
+ }
+
if (activation.has_deactivation_atom_matcher_id()) {
auto deactivationAtomMatcherIt =
logEventTrackerMap.find(activation.deactivation_atom_matcher_id());
@@ -750,10 +756,10 @@
const int deactivationMatcherIndex = deactivationAtomMatcherIt->second;
deactivationAtomTrackerToMetricMap[deactivationMatcherIndex]
.push_back(metricTrackerIndex);
- metric->addActivation(atomMatcherIndex, activation.ttl_seconds(),
+ metric->addActivation(atomMatcherIndex, activationType, activation.ttl_seconds(),
deactivationMatcherIndex);
} else {
- metric->addActivation(atomMatcherIndex, activation.ttl_seconds());
+ metric->addActivation(atomMatcherIndex, activationType, activation.ttl_seconds());
}
}
}
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index 2260b9b..4e419b6 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -377,21 +377,23 @@
optional float probability_of_informing = 7 [default = 1.1];
}
+enum ActivationType {
+ ACTIVATION_TYPE_UNKNOWN = 0;
+ ACTIVATE_IMMEDIATELY = 1;
+ ACTIVATE_ON_BOOT = 2;
+}
+
message EventActivation {
optional int64 atom_matcher_id = 1;
optional int64 ttl_seconds = 2;
optional int64 deactivation_atom_matcher_id = 3;
+ optional ActivationType activation_type = 4;
}
message MetricActivation {
optional int64 metric_id = 1;
- enum ActivationType {
- UNKNOWN = 0;
- ACTIVATE_IMMEDIATELY = 1;
- ACTIVATE_ON_BOOT = 2;
- }
- optional ActivationType activation_type = 3;
+ optional ActivationType activation_type = 3 [deprecated = true];
repeated EventActivation event_activation = 2;
}
diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp
index 91e282a..49b4e90 100644
--- a/cmds/statsd/tests/StatsLogProcessor_test.cpp
+++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp
@@ -339,6 +339,7 @@
auto metric3Activation = config2.add_metric_activation();
metric3Activation->set_metric_id(metricId3);
+ metric3Activation->set_activation_type(ACTIVATE_IMMEDIATELY);
auto metric3ActivationTrigger = metric3Activation->add_event_activation();
metric3ActivationTrigger->set_atom_matcher_id(wakelockAcquireMatcher.id());
metric3ActivationTrigger->set_ttl_seconds(100);
@@ -366,12 +367,14 @@
auto metric5Activation = config3.add_metric_activation();
metric5Activation->set_metric_id(metricId5);
+ metric5Activation->set_activation_type(ACTIVATE_IMMEDIATELY);
auto metric5ActivationTrigger = metric5Activation->add_event_activation();
metric5ActivationTrigger->set_atom_matcher_id(wakelockAcquireMatcher.id());
metric5ActivationTrigger->set_ttl_seconds(100);
auto metric6Activation = config3.add_metric_activation();
metric6Activation->set_metric_id(metricId6);
+ metric6Activation->set_activation_type(ACTIVATE_IMMEDIATELY);
auto metric6ActivationTrigger = metric6Activation->add_event_activation();
metric6ActivationTrigger->set_atom_matcher_id(wakelockAcquireMatcher.id());
metric6ActivationTrigger->set_ttl_seconds(200);
@@ -507,17 +510,13 @@
// When we shut down, metrics 3 & 5 have 100ns remaining, metric 6 has 100s + 100ns.
int64_t shutDownTime = timeBase1 + 100 * NS_PER_SEC;
- EXPECT_TRUE(metricProducer3->isActive());
- int64_t ttl3 = metricProducer3->getRemainingTtlNs(shutDownTime);
- EXPECT_EQ(100, ttl3);
- EXPECT_TRUE(metricProducer5->isActive());
- int64_t ttl5 = metricProducer5->getRemainingTtlNs(shutDownTime);
- EXPECT_EQ(100, ttl5);
- EXPECT_TRUE(metricProducer6->isActive());
- int64_t ttl6 = metricProducer6->getRemainingTtlNs(shutDownTime);
- EXPECT_EQ(100 + 100 * NS_PER_SEC, ttl6);
-
- processor.WriteMetricsActivationToDisk(shutDownTime);
+ processor.SaveActiveConfigsToDisk(shutDownTime);
+ const int64_t ttl3 = event->GetElapsedTimestampNs() +
+ metric3ActivationTrigger->ttl_seconds() * NS_PER_SEC - shutDownTime;
+ const int64_t ttl5 = event->GetElapsedTimestampNs() +
+ metric5ActivationTrigger->ttl_seconds() * NS_PER_SEC - shutDownTime;
+ const int64_t ttl6 = event->GetElapsedTimestampNs() +
+ metric6ActivationTrigger->ttl_seconds() * NS_PER_SEC - shutDownTime;
// Create a second StatsLogProcessor and push the same 3 configs.
long timeBase2 = 1000;
@@ -611,25 +610,25 @@
EXPECT_FALSE(metricProducer1003->isActive());
const auto& activation1003 = metricProducer1003->mEventActivationMap.begin()->second;
EXPECT_EQ(100 * NS_PER_SEC, activation1003->ttl_ns);
- EXPECT_EQ(0, activation1003->activation_ns);
+ EXPECT_EQ(0, activation1003->start_ns);
EXPECT_FALSE(metricProducer1005->isActive());
const auto& activation1005 = metricProducer1005->mEventActivationMap.begin()->second;
EXPECT_EQ(100 * NS_PER_SEC, activation1005->ttl_ns);
- EXPECT_EQ(0, activation1005->activation_ns);
+ EXPECT_EQ(0, activation1005->start_ns);
EXPECT_FALSE(metricProducer1006->isActive());
const auto& activation1006 = metricProducer1006->mEventActivationMap.begin()->second;
EXPECT_EQ(200 * NS_PER_SEC, activation1006->ttl_ns);
- EXPECT_EQ(0, activation1006->activation_ns);
+ EXPECT_EQ(0, activation1006->start_ns);
- processor2->LoadMetricsActivationFromDisk();
+ processor2->LoadActiveConfigsFromDisk();
// After loading activations from disk, assert that all 3 metrics are active.
EXPECT_TRUE(metricProducer1003->isActive());
- EXPECT_EQ(timeBase2 + ttl3 - activation1003->ttl_ns, activation1003->activation_ns);
+ EXPECT_EQ(timeBase2 + ttl3 - activation1003->ttl_ns, activation1003->start_ns);
EXPECT_TRUE(metricProducer1005->isActive());
- EXPECT_EQ(timeBase2 + ttl5 - activation1005->ttl_ns, activation1005->activation_ns);
+ EXPECT_EQ(timeBase2 + ttl5 - activation1005->ttl_ns, activation1005->start_ns);
EXPECT_TRUE(metricProducer1006->isActive());
- EXPECT_EQ(timeBase2 + ttl6 - activation1006->ttl_ns, activation1003->activation_ns);
+ EXPECT_EQ(timeBase2 + ttl6 - activation1006->ttl_ns, activation1003->start_ns);
// Make sure no more broadcasts have happened.
EXPECT_EQ(broadcastCount, 1);
@@ -638,7 +637,6 @@
TEST(StatsLogProcessorTest, TestActivationOnBoot) {
int uid = 1111;
- // Setup a simple config, no activation
StatsdConfig config1;
config1.set_id(12341);
config1.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
@@ -659,7 +657,7 @@
auto metric1Activation = config1.add_metric_activation();
metric1Activation->set_metric_id(metricId1);
- metric1Activation->set_activation_type(MetricActivation::ACTIVATE_ON_BOOT);
+ metric1Activation->set_activation_type(ACTIVATE_ON_BOOT);
auto metric1ActivationTrigger = metric1Activation->add_event_activation();
metric1ActivationTrigger->set_atom_matcher_id(wakelockAcquireMatcher.id());
metric1ActivationTrigger->set_ttl_seconds(100);
@@ -697,7 +695,7 @@
const auto& activation1 = metricProducer1->mEventActivationMap.begin()->second;
EXPECT_EQ(100 * NS_PER_SEC, activation1->ttl_ns);
- EXPECT_EQ(0, activation1->activation_ns);
+ EXPECT_EQ(0, activation1->start_ns);
EXPECT_EQ(kNotActive, activation1->state);
std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1")};
@@ -705,15 +703,13 @@
processor->OnLogEvent(event.get());
EXPECT_FALSE(metricProducer1->isActive());
- EXPECT_EQ(0, activation1->activation_ns);
+ EXPECT_EQ(0, activation1->start_ns);
EXPECT_EQ(kActiveOnBoot, activation1->state);
int64_t shutDownTime = timeBase1 + 100 * NS_PER_SEC;
-
- processor->WriteMetricsActivationToDisk(shutDownTime);
- EXPECT_TRUE(metricProducer1->isActive());
- int64_t ttl1 = metricProducer1->getRemainingTtlNs(shutDownTime);
- EXPECT_EQ(100 * NS_PER_SEC, ttl1);
+ processor->SaveActiveConfigsToDisk(shutDownTime);
+ EXPECT_FALSE(metricProducer1->isActive());
+ const int64_t ttl1 = metric1ActivationTrigger->ttl_seconds() * NS_PER_SEC;
long timeBase2 = 1000;
sp<StatsLogProcessor> processor2 =
@@ -747,13 +743,743 @@
const auto& activation1001 = metricProducer1001->mEventActivationMap.begin()->second;
EXPECT_EQ(100 * NS_PER_SEC, activation1001->ttl_ns);
- EXPECT_EQ(0, activation1001->activation_ns);
+ EXPECT_EQ(0, activation1001->start_ns);
EXPECT_EQ(kNotActive, activation1001->state);
- processor2->LoadMetricsActivationFromDisk();
+ processor2->LoadActiveConfigsFromDisk();
EXPECT_TRUE(metricProducer1001->isActive());
- EXPECT_EQ(timeBase2 + ttl1 - activation1001->ttl_ns, activation1001->activation_ns);
+ EXPECT_EQ(timeBase2 + ttl1 - activation1001->ttl_ns, activation1001->start_ns);
+ EXPECT_EQ(kActive, activation1001->state);
+}
+
+TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivations) {
+ int uid = 1111;
+
+ // Create config with 2 metrics:
+ // Metric 1: Activate on boot with 2 activations
+ // Metric 2: Always active
+ StatsdConfig config1;
+ config1.set_id(12341);
+ config1.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
+ auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
+ auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
+ *config1.add_atom_matcher() = wakelockAcquireMatcher;
+ *config1.add_atom_matcher() = screenOnMatcher;
+
+ long metricId1 = 1234561;
+ long metricId2 = 1234562;
+
+ auto countMetric1 = config1.add_count_metric();
+ countMetric1->set_id(metricId1);
+ countMetric1->set_what(wakelockAcquireMatcher.id());
+ countMetric1->set_bucket(FIVE_MINUTES);
+
+ auto countMetric2 = config1.add_count_metric();
+ countMetric2->set_id(metricId2);
+ countMetric2->set_what(wakelockAcquireMatcher.id());
+ countMetric2->set_bucket(FIVE_MINUTES);
+
+ auto metric1Activation = config1.add_metric_activation();
+ metric1Activation->set_metric_id(metricId1);
+ metric1Activation->set_activation_type(ACTIVATE_ON_BOOT);
+ auto metric1ActivationTrigger1 = metric1Activation->add_event_activation();
+ metric1ActivationTrigger1->set_atom_matcher_id(wakelockAcquireMatcher.id());
+ metric1ActivationTrigger1->set_ttl_seconds(100);
+ auto metric1ActivationTrigger2 = metric1Activation->add_event_activation();
+ metric1ActivationTrigger2->set_atom_matcher_id(screenOnMatcher.id());
+ metric1ActivationTrigger2->set_ttl_seconds(200);
+
+ ConfigKey cfgKey1(uid, 12341);
+ long timeBase1 = 1;
+ sp<StatsLogProcessor> processor =
+ CreateStatsLogProcessor(timeBase1, timeBase1, config1, cfgKey1);
+
+ // Metric 1 is not active.
+ // Metric 2 is active.
+ // {{{---------------------------------------------------------------------------
+ EXPECT_EQ(1, processor->mMetricsManagers.size());
+ auto it = processor->mMetricsManagers.find(cfgKey1);
+ EXPECT_TRUE(it != processor->mMetricsManagers.end());
+ auto& metricsManager1 = it->second;
+ EXPECT_TRUE(metricsManager1->isActive());
+
+ auto metricIt = metricsManager1->mAllMetricProducers.begin();
+ for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId1) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end());
+ auto& metricProducer1 = *metricIt;
+ EXPECT_FALSE(metricProducer1->isActive());
+
+ metricIt = metricsManager1->mAllMetricProducers.begin();
+ for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId2) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end());
+ auto& metricProducer2 = *metricIt;
+ EXPECT_TRUE(metricProducer2->isActive());
+
+ int i = 0;
+ for (; i < metricsManager1->mAllAtomMatchers.size(); i++) {
+ if (metricsManager1->mAllAtomMatchers[i]->getId() ==
+ metric1ActivationTrigger1->atom_matcher_id()) {
+ break;
+ }
+ }
+ const auto& activation1 = metricProducer1->mEventActivationMap.at(i);
+ EXPECT_EQ(100 * NS_PER_SEC, activation1->ttl_ns);
+ EXPECT_EQ(0, activation1->start_ns);
+ EXPECT_EQ(kNotActive, activation1->state);
+
+ i = 0;
+ for (; i < metricsManager1->mAllAtomMatchers.size(); i++) {
+ if (metricsManager1->mAllAtomMatchers[i]->getId() ==
+ metric1ActivationTrigger2->atom_matcher_id()) {
+ break;
+ }
+ }
+ const auto& activation2 = metricProducer1->mEventActivationMap.at(i);
+ EXPECT_EQ(200 * NS_PER_SEC, activation2->ttl_ns);
+ EXPECT_EQ(0, activation2->start_ns);
+ EXPECT_EQ(kNotActive, activation2->state);
+ // }}}------------------------------------------------------------------------------
+
+ // Trigger Activation 1 for Metric 1
+ std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1")};
+ auto event = CreateAcquireWakelockEvent(attributions1, "wl1", 100 + timeBase1);
+ processor->OnLogEvent(event.get());
+
+ // Metric 1 is not active; Activation 1 set to kActiveOnBoot
+ // Metric 2 is active.
+ // {{{---------------------------------------------------------------------------
+ EXPECT_FALSE(metricProducer1->isActive());
+ EXPECT_EQ(0, activation1->start_ns);
+ EXPECT_EQ(kActiveOnBoot, activation1->state);
+ EXPECT_EQ(0, activation2->start_ns);
+ EXPECT_EQ(kNotActive, activation2->state);
+
+ EXPECT_TRUE(metricProducer2->isActive());
+ // }}}-----------------------------------------------------------------------------
+
+ // Simulate shutdown by saving state to disk
+ int64_t shutDownTime = timeBase1 + 100 * NS_PER_SEC;
+ processor->SaveActiveConfigsToDisk(shutDownTime);
+ EXPECT_FALSE(metricProducer1->isActive());
+ int64_t ttl1 = metric1ActivationTrigger1->ttl_seconds() * NS_PER_SEC;
+
+ // Simulate device restarted state by creating new instance of StatsLogProcessor with the
+ // same config.
+ long timeBase2 = 1000;
+ sp<StatsLogProcessor> processor2 =
+ CreateStatsLogProcessor(timeBase2, timeBase2, config1, cfgKey1);
+
+ // Metric 1 is not active.
+ // Metric 2 is active.
+ // {{{---------------------------------------------------------------------------
+ EXPECT_EQ(1, processor2->mMetricsManagers.size());
+ it = processor2->mMetricsManagers.find(cfgKey1);
+ EXPECT_TRUE(it != processor2->mMetricsManagers.end());
+ auto& metricsManager1001 = it->second;
+ EXPECT_TRUE(metricsManager1001->isActive());
+
+ metricIt = metricsManager1001->mAllMetricProducers.begin();
+ for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId1) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end());
+ auto& metricProducer1001 = *metricIt;
+ EXPECT_FALSE(metricProducer1001->isActive());
+
+ metricIt = metricsManager1001->mAllMetricProducers.begin();
+ for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId2) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end());
+ auto& metricProducer1002 = *metricIt;
+ EXPECT_TRUE(metricProducer1002->isActive());
+
+ i = 0;
+ for (; i < metricsManager1001->mAllAtomMatchers.size(); i++) {
+ if (metricsManager1001->mAllAtomMatchers[i]->getId() ==
+ metric1ActivationTrigger1->atom_matcher_id()) {
+ break;
+ }
+ }
+ const auto& activation1001_1 = metricProducer1001->mEventActivationMap.at(i);
+ EXPECT_EQ(100 * NS_PER_SEC, activation1001_1->ttl_ns);
+ EXPECT_EQ(0, activation1001_1->start_ns);
+ EXPECT_EQ(kNotActive, activation1001_1->state);
+
+ i = 0;
+ for (; i < metricsManager1001->mAllAtomMatchers.size(); i++) {
+ if (metricsManager1001->mAllAtomMatchers[i]->getId() ==
+ metric1ActivationTrigger2->atom_matcher_id()) {
+ break;
+ }
+ }
+
+ const auto& activation1001_2 = metricProducer1001->mEventActivationMap.at(i);
+ EXPECT_EQ(200 * NS_PER_SEC, activation1001_2->ttl_ns);
+ EXPECT_EQ(0, activation1001_2->start_ns);
+ EXPECT_EQ(kNotActive, activation1001_2->state);
+ // }}}-----------------------------------------------------------------------------------
+
+ // Load saved state from disk.
+ processor2->LoadActiveConfigsFromDisk();
+
+ // Metric 1 active; Activation 1 is active, Activation 2 is not active
+ // Metric 2 is active.
+ // {{{---------------------------------------------------------------------------
+ EXPECT_TRUE(metricProducer1001->isActive());
+ EXPECT_EQ(timeBase2 + ttl1 - activation1001_1->ttl_ns, activation1001_1->start_ns);
+ EXPECT_EQ(kActive, activation1001_1->state);
+ EXPECT_EQ(0, activation1001_2->start_ns);
+ EXPECT_EQ(kNotActive, activation1001_2->state);
+
+ EXPECT_TRUE(metricProducer1002->isActive());
+ // }}}--------------------------------------------------------------------------------
+
+ // Trigger Activation 2 for Metric 1.
+ auto screenOnEvent = CreateScreenStateChangedEvent(
+ android::view::DISPLAY_STATE_ON,
+ timeBase2 + 200
+ );
+ processor2->OnLogEvent(screenOnEvent.get());
+
+ // Metric 1 active; Activation 1 is active, Activation 2 is set to kActiveOnBoot
+ // Metric 2 is active.
+ // {{{---------------------------------------------------------------------------
+ EXPECT_TRUE(metricProducer1001->isActive());
+ EXPECT_EQ(timeBase2 + ttl1 - activation1001_1->ttl_ns, activation1001_1->start_ns);
+ EXPECT_EQ(kActive, activation1001_1->state);
+ EXPECT_EQ(0, activation1001_2->start_ns);
+ EXPECT_EQ(kActiveOnBoot, activation1001_2->state);
+
+ EXPECT_TRUE(metricProducer1002->isActive());
+ // }}}---------------------------------------------------------------------------
+
+ // Simulate shutdown by saving state to disk
+ shutDownTime = timeBase2 + 50 * NS_PER_SEC;
+ processor2->SaveActiveConfigsToDisk(shutDownTime);
+ EXPECT_TRUE(metricProducer1001->isActive());
+ EXPECT_TRUE(metricProducer1002->isActive());
+ ttl1 = timeBase2 + metric1ActivationTrigger1->ttl_seconds() * NS_PER_SEC - shutDownTime;
+ int64_t ttl2 = metric1ActivationTrigger2->ttl_seconds() * NS_PER_SEC;
+
+ // Simulate device restarted state by creating new instance of StatsLogProcessor with the
+ // same config.
+ long timeBase3 = timeBase2 + 120 * NS_PER_SEC;
+ sp<StatsLogProcessor> processor3 =
+ CreateStatsLogProcessor(timeBase3, timeBase3, config1, cfgKey1);
+
+ // Metric 1 is not active.
+ // Metric 2 is active.
+ // {{{---------------------------------------------------------------------------
+ EXPECT_EQ(1, processor3->mMetricsManagers.size());
+ it = processor3->mMetricsManagers.find(cfgKey1);
+ EXPECT_TRUE(it != processor3->mMetricsManagers.end());
+ auto& metricsManagerTimeBase3 = it->second;
+ EXPECT_TRUE(metricsManagerTimeBase3->isActive());
+
+ metricIt = metricsManagerTimeBase3->mAllMetricProducers.begin();
+ for (; metricIt != metricsManagerTimeBase3->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId1) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManagerTimeBase3->mAllMetricProducers.end());
+ auto& metricProducerTimeBase3_1 = *metricIt;
+ EXPECT_FALSE(metricProducerTimeBase3_1->isActive());
+
+ metricIt = metricsManagerTimeBase3->mAllMetricProducers.begin();
+ for (; metricIt != metricsManagerTimeBase3->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId2) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManagerTimeBase3->mAllMetricProducers.end());
+ auto& metricProducerTimeBase3_2 = *metricIt;
+ EXPECT_TRUE(metricProducerTimeBase3_2->isActive());
+
+ i = 0;
+ for (; i < metricsManagerTimeBase3->mAllAtomMatchers.size(); i++) {
+ if (metricsManagerTimeBase3->mAllAtomMatchers[i]->getId() ==
+ metric1ActivationTrigger1->atom_matcher_id()) {
+ break;
+ }
+ }
+ const auto& activationTimeBase3_1 = metricProducerTimeBase3_1->mEventActivationMap.at(i);
+ EXPECT_EQ(100 * NS_PER_SEC, activationTimeBase3_1->ttl_ns);
+ EXPECT_EQ(0, activationTimeBase3_1->start_ns);
+ EXPECT_EQ(kNotActive, activationTimeBase3_1->state);
+
+ i = 0;
+ for (; i < metricsManagerTimeBase3->mAllAtomMatchers.size(); i++) {
+ if (metricsManagerTimeBase3->mAllAtomMatchers[i]->getId() ==
+ metric1ActivationTrigger2->atom_matcher_id()) {
+ break;
+ }
+ }
+
+ const auto& activationTimeBase3_2 = metricProducerTimeBase3_1->mEventActivationMap.at(i);
+ EXPECT_EQ(200 * NS_PER_SEC, activationTimeBase3_2->ttl_ns);
+ EXPECT_EQ(0, activationTimeBase3_2->start_ns);
+ EXPECT_EQ(kNotActive, activationTimeBase3_2->state);
+
+ EXPECT_TRUE(metricProducerTimeBase3_2->isActive());
+ // }}}----------------------------------------------------------------------------------
+
+ // Load saved state from disk.
+ processor3->LoadActiveConfigsFromDisk();
+
+ // Metric 1 active: Activation 1 is active, Activation 2 is active
+ // Metric 2 is active.
+ // {{{---------------------------------------------------------------------------
+ EXPECT_TRUE(metricProducerTimeBase3_1->isActive());
+ EXPECT_EQ(timeBase3 + ttl1 - activationTimeBase3_1->ttl_ns, activationTimeBase3_1->start_ns);
+ EXPECT_EQ(kActive, activationTimeBase3_1->state);
+ EXPECT_EQ(timeBase3 + ttl2 - activationTimeBase3_2->ttl_ns, activationTimeBase3_2->start_ns);
+ EXPECT_EQ(kActive, activationTimeBase3_2->state);
+
+ EXPECT_TRUE(metricProducerTimeBase3_2->isActive());
+ // }}}-------------------------------------------------------------------------------
+
+ // Trigger Activation 2 for Metric 1 again.
+ screenOnEvent = CreateScreenStateChangedEvent(
+ android::view::DISPLAY_STATE_ON,
+ timeBase3 + 100 * NS_PER_SEC
+ );
+ processor3->OnLogEvent(screenOnEvent.get());
+
+ // Metric 1 active; Activation 1 is not active, Activation 2 is set to active
+ // Metric 2 is active.
+ // {{{---------------------------------------------------------------------------
+ EXPECT_TRUE(metricProducerTimeBase3_1->isActive());
+ EXPECT_EQ(kNotActive, activationTimeBase3_1->state);
+ EXPECT_EQ(timeBase3 + ttl2 - activationTimeBase3_2->ttl_ns, activationTimeBase3_2->start_ns);
+ EXPECT_EQ(kActive, activationTimeBase3_2->state);
+
+ EXPECT_TRUE(metricProducerTimeBase3_2->isActive());
+ // }}}---------------------------------------------------------------------------
+
+ // Simulate shutdown by saving state to disk.
+ shutDownTime = timeBase3 + 500 * NS_PER_SEC;
+ processor3->SaveActiveConfigsToDisk(shutDownTime);
+ EXPECT_TRUE(metricProducer1001->isActive());
+ EXPECT_TRUE(metricProducer1002->isActive());
+ ttl1 = timeBase3 + ttl1 - shutDownTime;
+ ttl2 = timeBase3 + metric1ActivationTrigger2->ttl_seconds() * NS_PER_SEC - shutDownTime;
+
+ // Simulate device restarted state by creating new instance of StatsLogProcessor with the
+ // same config.
+ long timeBase4 = timeBase3 + 600 * NS_PER_SEC;
+ sp<StatsLogProcessor> processor4 =
+ CreateStatsLogProcessor(timeBase4, timeBase4, config1, cfgKey1);
+
+ // Metric 1 is not active.
+ // Metric 2 is active.
+ // {{{---------------------------------------------------------------------------
+ EXPECT_EQ(1, processor4->mMetricsManagers.size());
+ it = processor4->mMetricsManagers.find(cfgKey1);
+ EXPECT_TRUE(it != processor4->mMetricsManagers.end());
+ auto& metricsManagerTimeBase4 = it->second;
+ EXPECT_TRUE(metricsManagerTimeBase4->isActive());
+
+ metricIt = metricsManagerTimeBase4->mAllMetricProducers.begin();
+ for (; metricIt != metricsManagerTimeBase4->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId1) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManagerTimeBase4->mAllMetricProducers.end());
+ auto& metricProducerTimeBase4_1 = *metricIt;
+ EXPECT_FALSE(metricProducerTimeBase4_1->isActive());
+
+ metricIt = metricsManagerTimeBase4->mAllMetricProducers.begin();
+ for (; metricIt != metricsManagerTimeBase4->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId2) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManagerTimeBase4->mAllMetricProducers.end());
+ auto& metricProducerTimeBase4_2 = *metricIt;
+ EXPECT_TRUE(metricProducerTimeBase4_2->isActive());
+
+ i = 0;
+ for (; i < metricsManagerTimeBase4->mAllAtomMatchers.size(); i++) {
+ if (metricsManagerTimeBase4->mAllAtomMatchers[i]->getId() ==
+ metric1ActivationTrigger1->atom_matcher_id()) {
+ break;
+ }
+ }
+ const auto& activationTimeBase4_1 = metricProducerTimeBase4_1->mEventActivationMap.at(i);
+ EXPECT_EQ(100 * NS_PER_SEC, activationTimeBase4_1->ttl_ns);
+ EXPECT_EQ(0, activationTimeBase4_1->start_ns);
+ EXPECT_EQ(kNotActive, activationTimeBase4_1->state);
+
+ i = 0;
+ for (; i < metricsManagerTimeBase4->mAllAtomMatchers.size(); i++) {
+ if (metricsManagerTimeBase4->mAllAtomMatchers[i]->getId() ==
+ metric1ActivationTrigger2->atom_matcher_id()) {
+ break;
+ }
+ }
+
+ const auto& activationTimeBase4_2 = metricProducerTimeBase4_1->mEventActivationMap.at(i);
+ EXPECT_EQ(200 * NS_PER_SEC, activationTimeBase4_2->ttl_ns);
+ EXPECT_EQ(0, activationTimeBase4_2->start_ns);
+ EXPECT_EQ(kNotActive, activationTimeBase4_2->state);
+
+ EXPECT_TRUE(metricProducerTimeBase4_2->isActive());
+ // }}}----------------------------------------------------------------------------------
+
+ // Load saved state from disk.
+ processor4->LoadActiveConfigsFromDisk();
+
+ // Metric 1 active: Activation 1 is not active, Activation 2 is not active
+ // Metric 2 is active.
+ // {{{---------------------------------------------------------------------------
+ EXPECT_FALSE(metricProducerTimeBase4_1->isActive());
+ EXPECT_EQ(kNotActive, activationTimeBase4_1->state);
+ EXPECT_EQ(kNotActive, activationTimeBase4_2->state);
+
+ EXPECT_TRUE(metricProducerTimeBase4_2->isActive());
+ // }}}-------------------------------------------------------------------------------
+}
+
+TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivationsDifferentActivationTypes) {
+ int uid = 1111;
+
+ // Create config with 2 metrics:
+ // Metric 1: Activate on boot with 2 activations
+ // Metric 2: Always active
+ StatsdConfig config1;
+ config1.set_id(12341);
+ config1.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
+ auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
+ auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
+ *config1.add_atom_matcher() = wakelockAcquireMatcher;
+ *config1.add_atom_matcher() = screenOnMatcher;
+
+ long metricId1 = 1234561;
+ long metricId2 = 1234562;
+
+ auto countMetric1 = config1.add_count_metric();
+ countMetric1->set_id(metricId1);
+ countMetric1->set_what(wakelockAcquireMatcher.id());
+ countMetric1->set_bucket(FIVE_MINUTES);
+
+ auto countMetric2 = config1.add_count_metric();
+ countMetric2->set_id(metricId2);
+ countMetric2->set_what(wakelockAcquireMatcher.id());
+ countMetric2->set_bucket(FIVE_MINUTES);
+
+ auto metric1Activation = config1.add_metric_activation();
+ metric1Activation->set_metric_id(metricId1);
+ metric1Activation->set_activation_type(ACTIVATE_ON_BOOT);
+ auto metric1ActivationTrigger1 = metric1Activation->add_event_activation();
+ metric1ActivationTrigger1->set_atom_matcher_id(wakelockAcquireMatcher.id());
+ metric1ActivationTrigger1->set_ttl_seconds(100);
+ auto metric1ActivationTrigger2 = metric1Activation->add_event_activation();
+ metric1ActivationTrigger2->set_atom_matcher_id(screenOnMatcher.id());
+ metric1ActivationTrigger2->set_ttl_seconds(200);
+ metric1ActivationTrigger2->set_activation_type(ACTIVATE_IMMEDIATELY);
+
+ ConfigKey cfgKey1(uid, 12341);
+ long timeBase1 = 1;
+ sp<StatsLogProcessor> processor =
+ CreateStatsLogProcessor(timeBase1, timeBase1, config1, cfgKey1);
+
+ // Metric 1 is not active.
+ // Metric 2 is active.
+ // {{{---------------------------------------------------------------------------
+ EXPECT_EQ(1, processor->mMetricsManagers.size());
+ auto it = processor->mMetricsManagers.find(cfgKey1);
+ EXPECT_TRUE(it != processor->mMetricsManagers.end());
+ auto& metricsManager1 = it->second;
+ EXPECT_TRUE(metricsManager1->isActive());
+
+ auto metricIt = metricsManager1->mAllMetricProducers.begin();
+ for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId1) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end());
+ auto& metricProducer1 = *metricIt;
+ EXPECT_FALSE(metricProducer1->isActive());
+
+ metricIt = metricsManager1->mAllMetricProducers.begin();
+ for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId2) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end());
+ auto& metricProducer2 = *metricIt;
+ EXPECT_TRUE(metricProducer2->isActive());
+
+ int i = 0;
+ for (; i < metricsManager1->mAllAtomMatchers.size(); i++) {
+ if (metricsManager1->mAllAtomMatchers[i]->getId() ==
+ metric1ActivationTrigger1->atom_matcher_id()) {
+ break;
+ }
+ }
+ const auto& activation1 = metricProducer1->mEventActivationMap.at(i);
+ EXPECT_EQ(100 * NS_PER_SEC, activation1->ttl_ns);
+ EXPECT_EQ(0, activation1->start_ns);
+ EXPECT_EQ(kNotActive, activation1->state);
+ EXPECT_EQ(ACTIVATE_ON_BOOT, activation1->activationType);
+
+ i = 0;
+ for (; i < metricsManager1->mAllAtomMatchers.size(); i++) {
+ if (metricsManager1->mAllAtomMatchers[i]->getId() ==
+ metric1ActivationTrigger2->atom_matcher_id()) {
+ break;
+ }
+ }
+ const auto& activation2 = metricProducer1->mEventActivationMap.at(i);
+ EXPECT_EQ(200 * NS_PER_SEC, activation2->ttl_ns);
+ EXPECT_EQ(0, activation2->start_ns);
+ EXPECT_EQ(kNotActive, activation2->state);
+ EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation2->activationType);
+ // }}}------------------------------------------------------------------------------
+
+ // Trigger Activation 1 for Metric 1
+ std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1")};
+ auto event = CreateAcquireWakelockEvent(attributions1, "wl1", 100 + timeBase1);
+ processor->OnLogEvent(event.get());
+
+ // Metric 1 is not active; Activation 1 set to kActiveOnBoot
+ // Metric 2 is active.
+ // {{{---------------------------------------------------------------------------
+ EXPECT_FALSE(metricProducer1->isActive());
+ EXPECT_EQ(0, activation1->start_ns);
+ EXPECT_EQ(kActiveOnBoot, activation1->state);
+ EXPECT_EQ(0, activation2->start_ns);
+ EXPECT_EQ(kNotActive, activation2->state);
+
+ EXPECT_TRUE(metricProducer2->isActive());
+ // }}}-----------------------------------------------------------------------------
+
+ // Simulate shutdown by saving state to disk
+ int64_t shutDownTime = timeBase1 + 100 * NS_PER_SEC;
+ processor->SaveActiveConfigsToDisk(shutDownTime);
+ EXPECT_FALSE(metricProducer1->isActive());
+ int64_t ttl1 = metric1ActivationTrigger1->ttl_seconds() * NS_PER_SEC;
+
+ // Simulate device restarted state by creating new instance of StatsLogProcessor with the
+ // same config.
+ long timeBase2 = 1000;
+ sp<StatsLogProcessor> processor2 =
+ CreateStatsLogProcessor(timeBase2, timeBase2, config1, cfgKey1);
+
+ // Metric 1 is not active.
+ // Metric 2 is active.
+ // {{{---------------------------------------------------------------------------
+ EXPECT_EQ(1, processor2->mMetricsManagers.size());
+ it = processor2->mMetricsManagers.find(cfgKey1);
+ EXPECT_TRUE(it != processor2->mMetricsManagers.end());
+ auto& metricsManager1001 = it->second;
+ EXPECT_TRUE(metricsManager1001->isActive());
+
+ metricIt = metricsManager1001->mAllMetricProducers.begin();
+ for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId1) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end());
+ auto& metricProducer1001 = *metricIt;
+ EXPECT_FALSE(metricProducer1001->isActive());
+
+ metricIt = metricsManager1001->mAllMetricProducers.begin();
+ for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId2) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end());
+ auto& metricProducer1002 = *metricIt;
+ EXPECT_TRUE(metricProducer1002->isActive());
+
+ i = 0;
+ for (; i < metricsManager1001->mAllAtomMatchers.size(); i++) {
+ if (metricsManager1001->mAllAtomMatchers[i]->getId() ==
+ metric1ActivationTrigger1->atom_matcher_id()) {
+ break;
+ }
+ }
+ const auto& activation1001_1 = metricProducer1001->mEventActivationMap.at(i);
+ EXPECT_EQ(100 * NS_PER_SEC, activation1001_1->ttl_ns);
+ EXPECT_EQ(0, activation1001_1->start_ns);
+ EXPECT_EQ(kNotActive, activation1001_1->state);
+ EXPECT_EQ(ACTIVATE_ON_BOOT, activation1001_1->activationType);
+
+ i = 0;
+ for (; i < metricsManager1001->mAllAtomMatchers.size(); i++) {
+ if (metricsManager1001->mAllAtomMatchers[i]->getId() ==
+ metric1ActivationTrigger2->atom_matcher_id()) {
+ break;
+ }
+ }
+
+ const auto& activation1001_2 = metricProducer1001->mEventActivationMap.at(i);
+ EXPECT_EQ(200 * NS_PER_SEC, activation1001_2->ttl_ns);
+ EXPECT_EQ(0, activation1001_2->start_ns);
+ EXPECT_EQ(kNotActive, activation1001_2->state);
+ EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation1001_2->activationType);
+ // }}}-----------------------------------------------------------------------------------
+
+ // Load saved state from disk.
+ processor2->LoadActiveConfigsFromDisk();
+
+ // Metric 1 active; Activation 1 is active, Activation 2 is not active
+ // Metric 2 is active.
+ // {{{---------------------------------------------------------------------------
+ EXPECT_TRUE(metricProducer1001->isActive());
+ EXPECT_EQ(timeBase2 + ttl1 - activation1001_1->ttl_ns, activation1001_1->start_ns);
+ EXPECT_EQ(kActive, activation1001_1->state);
+ EXPECT_EQ(0, activation1001_2->start_ns);
+ EXPECT_EQ(kNotActive, activation1001_2->state);
+
+ EXPECT_TRUE(metricProducer1002->isActive());
+ // }}}--------------------------------------------------------------------------------
+
+ // Trigger Activation 2 for Metric 1.
+ auto screenOnEvent = CreateScreenStateChangedEvent(
+ android::view::DISPLAY_STATE_ON,
+ timeBase2 + 200
+ );
+ processor2->OnLogEvent(screenOnEvent.get());
+
+ // Metric 1 active; Activation 1 is active, Activation 2 is active
+ // Metric 2 is active.
+ // {{{---------------------------------------------------------------------------
+ EXPECT_TRUE(metricProducer1001->isActive());
+ EXPECT_EQ(timeBase2 + ttl1 - activation1001_1->ttl_ns, activation1001_1->start_ns);
+ EXPECT_EQ(kActive, activation1001_1->state);
+ EXPECT_EQ(screenOnEvent->GetElapsedTimestampNs(), activation1001_2->start_ns);
+ EXPECT_EQ(kActive, activation1001_2->state);
+
+ EXPECT_TRUE(metricProducer1002->isActive());
+ // }}}---------------------------------------------------------------------------
+
+ // Simulate shutdown by saving state to disk
+ shutDownTime = timeBase2 + 50 * NS_PER_SEC;
+ processor2->SaveActiveConfigsToDisk(shutDownTime);
+ EXPECT_TRUE(metricProducer1001->isActive());
+ EXPECT_TRUE(metricProducer1002->isActive());
+ ttl1 = timeBase2 + metric1ActivationTrigger1->ttl_seconds() * NS_PER_SEC - shutDownTime;
+ int64_t ttl2 = screenOnEvent->GetElapsedTimestampNs() +
+ metric1ActivationTrigger2->ttl_seconds() * NS_PER_SEC - shutDownTime;
+
+ // Simulate device restarted state by creating new instance of StatsLogProcessor with the
+ // same config.
+ long timeBase3 = timeBase2 + 120 * NS_PER_SEC;
+ sp<StatsLogProcessor> processor3 =
+ CreateStatsLogProcessor(timeBase3, timeBase3, config1, cfgKey1);
+
+ // Metric 1 is not active.
+ // Metric 2 is active.
+ // {{{---------------------------------------------------------------------------
+ EXPECT_EQ(1, processor3->mMetricsManagers.size());
+ it = processor3->mMetricsManagers.find(cfgKey1);
+ EXPECT_TRUE(it != processor3->mMetricsManagers.end());
+ auto& metricsManagerTimeBase3 = it->second;
+ EXPECT_TRUE(metricsManagerTimeBase3->isActive());
+
+ metricIt = metricsManagerTimeBase3->mAllMetricProducers.begin();
+ for (; metricIt != metricsManagerTimeBase3->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId1) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManagerTimeBase3->mAllMetricProducers.end());
+ auto& metricProducerTimeBase3_1 = *metricIt;
+ EXPECT_FALSE(metricProducerTimeBase3_1->isActive());
+
+ metricIt = metricsManagerTimeBase3->mAllMetricProducers.begin();
+ for (; metricIt != metricsManagerTimeBase3->mAllMetricProducers.end(); metricIt++) {
+ if ((*metricIt)->getMetricId() == metricId2) {
+ break;
+ }
+ }
+ EXPECT_TRUE(metricIt != metricsManagerTimeBase3->mAllMetricProducers.end());
+ auto& metricProducerTimeBase3_2 = *metricIt;
+ EXPECT_TRUE(metricProducerTimeBase3_2->isActive());
+
+ i = 0;
+ for (; i < metricsManagerTimeBase3->mAllAtomMatchers.size(); i++) {
+ if (metricsManagerTimeBase3->mAllAtomMatchers[i]->getId() ==
+ metric1ActivationTrigger1->atom_matcher_id()) {
+ break;
+ }
+ }
+ const auto& activationTimeBase3_1 = metricProducerTimeBase3_1->mEventActivationMap.at(i);
+ EXPECT_EQ(100 * NS_PER_SEC, activationTimeBase3_1->ttl_ns);
+ EXPECT_EQ(0, activationTimeBase3_1->start_ns);
+ EXPECT_EQ(kNotActive, activationTimeBase3_1->state);
+ EXPECT_EQ(ACTIVATE_ON_BOOT, activationTimeBase3_1->activationType);
+
+ i = 0;
+ for (; i < metricsManagerTimeBase3->mAllAtomMatchers.size(); i++) {
+ if (metricsManagerTimeBase3->mAllAtomMatchers[i]->getId() ==
+ metric1ActivationTrigger2->atom_matcher_id()) {
+ break;
+ }
+ }
+
+ const auto& activationTimeBase3_2 = metricProducerTimeBase3_1->mEventActivationMap.at(i);
+ EXPECT_EQ(200 * NS_PER_SEC, activationTimeBase3_2->ttl_ns);
+ EXPECT_EQ(0, activationTimeBase3_2->start_ns);
+ EXPECT_EQ(kNotActive, activationTimeBase3_2->state);
+ EXPECT_EQ(ACTIVATE_IMMEDIATELY, activationTimeBase3_2->activationType);
+ // }}}----------------------------------------------------------------------------------
+
+ // Load saved state from disk.
+ processor3->LoadActiveConfigsFromDisk();
+
+ // Metric 1 active: Activation 1 is active, Activation 2 is active
+ // Metric 2 is active.
+ // {{{---------------------------------------------------------------------------
+ EXPECT_TRUE(metricProducerTimeBase3_1->isActive());
+ EXPECT_EQ(timeBase3 + ttl1 - activationTimeBase3_1->ttl_ns, activationTimeBase3_1->start_ns);
+ EXPECT_EQ(kActive, activationTimeBase3_1->state);
+ EXPECT_EQ(timeBase3 + ttl2 - activationTimeBase3_2->ttl_ns, activationTimeBase3_2->start_ns);
+ EXPECT_EQ(kActive, activationTimeBase3_2->state);
+
+ EXPECT_TRUE(metricProducerTimeBase3_2->isActive());
+ // }}}-------------------------------------------------------------------------------
+
+
+ // Trigger Activation 2 for Metric 1 again.
+ screenOnEvent = CreateScreenStateChangedEvent(
+ android::view::DISPLAY_STATE_ON,
+ timeBase3 + 100 * NS_PER_SEC
+ );
+ processor3->OnLogEvent(screenOnEvent.get());
+
+ // Metric 1 active; Activation 1 is not active, Activation 2 is set to active
+ // Metric 2 is active.
+ // {{{---------------------------------------------------------------------------
+ EXPECT_TRUE(metricProducerTimeBase3_1->isActive());
+ EXPECT_EQ(kNotActive, activationTimeBase3_1->state);
+ EXPECT_EQ(screenOnEvent->GetElapsedTimestampNs(), activationTimeBase3_2->start_ns);
+ EXPECT_EQ(kActive, activationTimeBase3_2->state);
+
+ EXPECT_TRUE(metricProducerTimeBase3_2->isActive());
+ // }}}---------------------------------------------------------------------------
}
#else
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
index f01ad06..6ec0a11 100644
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
@@ -418,7 +418,7 @@
const int64_t ttlNs = 2 * bucketSizeNs; // Two buckets.
auto metric_activation = config.add_metric_activation();
metric_activation->set_metric_id(metricId);
- metric_activation->set_activation_type(MetricActivation::ACTIVATE_IMMEDIATELY);
+ metric_activation->set_activation_type(ACTIVATE_IMMEDIATELY);
auto event_activation = metric_activation->add_event_activation();
event_activation->set_atom_matcher_id(batterySaverStartMatcher.id());
event_activation->set_ttl_seconds(ttlNs / 1000000000);
diff --git a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
index bf52bb0..d99d281 100644
--- a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
@@ -245,10 +245,10 @@
EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[0]->activation_ns, 0);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, 0);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[2]->activation_ns, 0);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
std::unique_ptr<LogEvent> event;
@@ -268,10 +268,10 @@
EXPECT_EQ(activeConfigsBroadcast.size(), 1);
EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
- EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[2]->activation_ns, 0);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
// First processed event.
@@ -285,10 +285,10 @@
EXPECT_TRUE(metricsManager->isActive());
EXPECT_TRUE(metricProducer->mIsActive);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
- EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
- EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
// 2nd processed event.
@@ -298,10 +298,10 @@
EXPECT_TRUE(metricsManager->isActive());
EXPECT_TRUE(metricProducer->mIsActive);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
- EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
// No new broadcast since the config should still be active.
EXPECT_EQ(broadcastCount, 1);
@@ -319,10 +319,10 @@
EXPECT_EQ(broadcastCount, 2);
EXPECT_EQ(activeConfigsBroadcast.size(), 0);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
// Re-activate metric via screen on.
@@ -335,10 +335,10 @@
EXPECT_EQ(activeConfigsBroadcast.size(), 1);
EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
- EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
// 4th processed event.
@@ -460,10 +460,10 @@
EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[0]->activation_ns, 0);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, 0);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[2]->activation_ns, 0);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap.size(), 1u);
EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end());
@@ -486,10 +486,10 @@
EXPECT_EQ(activeConfigsBroadcast.size(), 1);
EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
- EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[2]->activation_ns, 0);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]);
@@ -504,10 +504,10 @@
EXPECT_TRUE(metricsManager->isActive());
EXPECT_TRUE(metricProducer->mIsActive);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
- EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
- EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]);
@@ -518,10 +518,10 @@
EXPECT_TRUE(metricsManager->isActive());
EXPECT_TRUE(metricProducer->mIsActive);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
- EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]);
// No new broadcast since the config should still be active.
@@ -540,10 +540,10 @@
EXPECT_EQ(broadcastCount, 2);
EXPECT_EQ(activeConfigsBroadcast.size(), 0);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]);
@@ -557,10 +557,10 @@
EXPECT_EQ(activeConfigsBroadcast.size(), 1);
EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
- EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]);
@@ -577,10 +577,10 @@
EXPECT_EQ(activeConfigsBroadcast.size(), 1);
EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
- EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
- EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]);
@@ -597,10 +597,10 @@
EXPECT_EQ(activeConfigsBroadcast.size(), 1);
EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
- EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]);
@@ -613,10 +613,10 @@
EXPECT_EQ(broadcastCount, 4);
EXPECT_EQ(activeConfigsBroadcast.size(), 0);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]);
@@ -632,10 +632,10 @@
EXPECT_EQ(activeConfigsBroadcast.size(), 1);
EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
- EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]);
@@ -647,10 +647,10 @@
EXPECT_EQ(broadcastCount, 6);
EXPECT_EQ(activeConfigsBroadcast.size(), 0);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]);
@@ -782,10 +782,10 @@
EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[0]->activation_ns, 0);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, 0);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[2]->activation_ns, 0);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap.size(), 2u);
EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end());
@@ -810,10 +810,10 @@
EXPECT_EQ(activeConfigsBroadcast.size(), 1);
EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
- EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[2]->activation_ns, 0);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]);
EXPECT_EQ(eventDeactivationMap[4], eventActivationMap[2]);
@@ -829,10 +829,10 @@
EXPECT_TRUE(metricsManager->isActive());
EXPECT_TRUE(metricProducer->mIsActive);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
- EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
- EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]);
EXPECT_EQ(eventDeactivationMap[4], eventActivationMap[2]);
@@ -844,10 +844,10 @@
EXPECT_TRUE(metricsManager->isActive());
EXPECT_TRUE(metricProducer->mIsActive);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
- EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]);
EXPECT_EQ(eventDeactivationMap[4], eventActivationMap[2]);
@@ -867,10 +867,10 @@
EXPECT_EQ(broadcastCount, 2);
EXPECT_EQ(activeConfigsBroadcast.size(), 0);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]);
EXPECT_EQ(eventDeactivationMap[4], eventActivationMap[2]);
@@ -885,10 +885,10 @@
EXPECT_EQ(activeConfigsBroadcast.size(), 1);
EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
- EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]);
EXPECT_EQ(eventDeactivationMap[4], eventActivationMap[2]);
@@ -906,10 +906,10 @@
EXPECT_EQ(activeConfigsBroadcast.size(), 1);
EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
- EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
- EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]);
EXPECT_EQ(eventDeactivationMap[4], eventActivationMap[2]);
@@ -927,10 +927,10 @@
EXPECT_EQ(broadcastCount, 4);
EXPECT_EQ(activeConfigsBroadcast.size(), 0);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]);
EXPECT_EQ(eventDeactivationMap[4], eventActivationMap[2]);
@@ -943,10 +943,10 @@
EXPECT_EQ(broadcastCount, 4);
EXPECT_EQ(activeConfigsBroadcast.size(), 0);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]);
EXPECT_EQ(eventDeactivationMap[4], eventActivationMap[2]);
@@ -963,10 +963,10 @@
EXPECT_EQ(activeConfigsBroadcast.size(), 1);
EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
- EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]);
EXPECT_EQ(eventDeactivationMap[4], eventActivationMap[2]);
@@ -979,10 +979,10 @@
EXPECT_EQ(broadcastCount, 6);
EXPECT_EQ(activeConfigsBroadcast.size(), 0);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]);
EXPECT_EQ(eventDeactivationMap[4], eventActivationMap[2]);
@@ -1119,10 +1119,10 @@
EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[0]->activation_ns, 0);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, 0);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[2]->activation_ns, 0);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap.size(), 2u);
EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end());
@@ -1134,10 +1134,10 @@
EXPECT_TRUE(eventActivationMap2.find(0) != eventActivationMap2.end());
EXPECT_TRUE(eventActivationMap2.find(2) != eventActivationMap2.end());
EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap2[0]->activation_ns, 0);
+ EXPECT_EQ(eventActivationMap2[0]->start_ns, 0);
EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap2[2]->activation_ns, 0);
+ EXPECT_EQ(eventActivationMap2[2]->start_ns, 0);
EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap2.size(), 2u);
EXPECT_TRUE(eventDeactivationMap2.find(3) != eventDeactivationMap2.end());
@@ -1165,19 +1165,19 @@
EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
EXPECT_TRUE(metricProducer->mIsActive);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
- EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[2]->activation_ns, 0);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]);
EXPECT_EQ(eventDeactivationMap[4], eventActivationMap[2]);
EXPECT_TRUE(metricProducer2->mIsActive);
EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive);
- EXPECT_EQ(eventActivationMap2[0]->activation_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10);
EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap2[2]->activation_ns, 0);
+ EXPECT_EQ(eventActivationMap2[2]->start_ns, 0);
EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap2[3], eventActivationMap2[0]);
EXPECT_EQ(eventDeactivationMap2[4], eventActivationMap2[2]);
@@ -1195,19 +1195,19 @@
EXPECT_TRUE(metricsManager->isActive());
EXPECT_TRUE(metricProducer->mIsActive);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
- EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
- EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]);
EXPECT_EQ(eventDeactivationMap[4], eventActivationMap[2]);
EXPECT_TRUE(metricProducer2->mIsActive);
EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive);
- EXPECT_EQ(eventActivationMap2[0]->activation_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10);
EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kActive);
- EXPECT_EQ(eventActivationMap2[2]->activation_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + 20);
EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap2[3], eventActivationMap2[0]);
EXPECT_EQ(eventDeactivationMap2[4], eventActivationMap2[2]);
@@ -1221,19 +1221,19 @@
EXPECT_TRUE(metricsManager->isActive());
EXPECT_TRUE(metricProducer->mIsActive);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
- EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]);
EXPECT_EQ(eventDeactivationMap[4], eventActivationMap[2]);
EXPECT_TRUE(metricProducer2->mIsActive);
EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive);
- EXPECT_EQ(eventActivationMap2[0]->activation_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10);
EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap2[2]->activation_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + 20);
EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap2[3], eventActivationMap2[0]);
EXPECT_EQ(eventDeactivationMap2[4], eventActivationMap2[2]);
@@ -1257,19 +1257,19 @@
EXPECT_EQ(activeConfigsBroadcast.size(), 0);
EXPECT_FALSE(metricProducer->mIsActive);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]);
EXPECT_EQ(eventDeactivationMap[4], eventActivationMap[2]);
EXPECT_FALSE(metricProducer2->mIsActive);
EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap2[0]->activation_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10);
EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap2[2]->activation_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + 20);
EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap2[3], eventActivationMap2[0]);
EXPECT_EQ(eventDeactivationMap2[4], eventActivationMap2[2]);
@@ -1284,19 +1284,19 @@
EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
EXPECT_TRUE(metricProducer->mIsActive);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
- EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]);
EXPECT_EQ(eventDeactivationMap[4], eventActivationMap[2]);
EXPECT_TRUE(metricProducer2->mIsActive);
EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap2[0]->activation_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10);
EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kActive);
- EXPECT_EQ(eventActivationMap2[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap2[3], eventActivationMap2[0]);
EXPECT_EQ(eventDeactivationMap2[4], eventActivationMap2[2]);
@@ -1316,19 +1316,19 @@
EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
EXPECT_TRUE(metricProducer->mIsActive);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
- EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
- EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]);
EXPECT_EQ(eventDeactivationMap[4], eventActivationMap[2]);
EXPECT_TRUE(metricProducer2->mIsActive);
EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive);
- EXPECT_EQ(eventActivationMap2[0]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kActive);
- EXPECT_EQ(eventActivationMap2[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap2[3], eventActivationMap2[0]);
EXPECT_EQ(eventDeactivationMap2[4], eventActivationMap2[2]);
@@ -1348,19 +1348,19 @@
EXPECT_EQ(activeConfigsBroadcast.size(), 0);
EXPECT_FALSE(metricProducer->mIsActive);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]);
EXPECT_EQ(eventDeactivationMap[4], eventActivationMap[2]);
EXPECT_FALSE(metricProducer2->mIsActive);
EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap2[0]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap2[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap2[3], eventActivationMap2[0]);
EXPECT_EQ(eventDeactivationMap2[4], eventActivationMap2[2]);
@@ -1375,19 +1375,19 @@
EXPECT_EQ(activeConfigsBroadcast.size(), 0);
EXPECT_FALSE(metricProducer->mIsActive);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]);
EXPECT_EQ(eventDeactivationMap[4], eventActivationMap[2]);
EXPECT_FALSE(metricProducer2->mIsActive);
EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap2[0]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap2[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap2[3], eventActivationMap2[0]);
EXPECT_EQ(eventDeactivationMap2[4], eventActivationMap2[2]);
@@ -1406,19 +1406,19 @@
EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
EXPECT_TRUE(metricProducer->mIsActive);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
- EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]);
EXPECT_EQ(eventDeactivationMap[4], eventActivationMap[2]);
EXPECT_TRUE(metricProducer2->mIsActive);
EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive);
- EXPECT_EQ(eventActivationMap2[0]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+ EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap2[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap2[3], eventActivationMap2[0]);
EXPECT_EQ(eventDeactivationMap2[4], eventActivationMap2[2]);
@@ -1431,19 +1431,19 @@
EXPECT_EQ(activeConfigsBroadcast.size(), 0);
EXPECT_FALSE(metricProducer->mIsActive);
EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]);
EXPECT_EQ(eventDeactivationMap[4], eventActivationMap[2]);
EXPECT_FALSE(metricProducer2->mIsActive);
EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap2[0]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+ EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
- EXPECT_EQ(eventActivationMap2[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
EXPECT_EQ(eventDeactivationMap2[3], eventActivationMap2[0]);
EXPECT_EQ(eventDeactivationMap2[4], eventActivationMap2[2]);
diff --git a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
index e967eb3..ff6af38 100644
--- a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
@@ -279,7 +279,7 @@
const int64_t ttlNs = 2 * bucketSizeNs; // Two buckets.
auto metric_activation = config.add_metric_activation();
metric_activation->set_metric_id(metricId);
- metric_activation->set_activation_type(MetricActivation::ACTIVATE_IMMEDIATELY);
+ metric_activation->set_activation_type(ACTIVATE_IMMEDIATELY);
auto event_activation = metric_activation->add_event_activation();
event_activation->set_atom_matcher_id(batterySaverStartMatcher.id());
event_activation->set_ttl_seconds(ttlNs / 1000000000);
diff --git a/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java b/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java
index fc7b778..3e705fd 100644
--- a/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java
+++ b/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java
@@ -57,6 +57,7 @@
"AID_BLUETOOTH",
"AID_LMKD",
"com.android.managedprovisioning",
+ "AID_MEDIA",
"AID_NETWORK_STACK"
};
private static final Logger LOGGER = Logger.getLogger(TestDrive.class.getName());
diff --git a/cmds/telecom/src/com/android/commands/telecom/Telecom.java b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
index 1b7fbfe..0524450 100644
--- a/cmds/telecom/src/com/android/commands/telecom/Telecom.java
+++ b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
@@ -95,7 +95,8 @@
+ "telecom set-phone-account-disabled: Disables the given phone account, if it \n"
+ " has already been registered with telecom.\n"
+ "\n"
- + "telecom set-default-dialer: Sets the default dialer to the given component. \n"
+ + "telecom set-default-dialer: Sets the override default dialer to the given "
+ + "component; this will override whatever the dialer role is set to. \n"
+ "\n"
+ "telecom get-default-dialer: Displays the current default dialer. \n"
+ "\n"
@@ -254,13 +255,8 @@
private void runSetDefaultDialer() throws RemoteException {
final String packageName = nextArgRequired();
- final boolean success = mTelecomService.setDefaultDialer(packageName);
- if (success) {
- System.out.println("Success - " + packageName + " set as default dialer.");
- } else {
- System.out.println("Error - " + packageName + " is not an installed Dialer app, \n"
- + " or is already the default dialer.");
- }
+ mTelecomService.setTestDefaultDialer(packageName);
+ System.out.println("Success - " + packageName + " set as override default dialer.");
}
private void runGetDefaultDialer() throws RemoteException {
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 43531ed..4abf924 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2349,7 +2349,7 @@
*
* @param cancellationSignal A signal to cancel the operation in progress.
* @param callback The callback to send the action list. The actions list cannot
- * contain <code>null</code> elements.
+ * contain <code>null</code> elements. You can call this on any thread.
*/
public void onGetDirectActions(@NonNull CancellationSignal cancellationSignal,
@NonNull Consumer<List<DirectAction>> callback) {
@@ -2360,10 +2360,13 @@
* This is called to perform an action previously defined by the app.
* Apps also have access to {@link #getVoiceInteractor()} to follow up on the action.
*
- * @param actionId The ID for the action
- * @param arguments Any additional arguments provided by the caller
+ * @param actionId The ID for the action you previously reported via
+ * {@link #onGetDirectActions(CancellationSignal, Consumer)}.
+ * @param arguments Any additional arguments provided by the caller that are
+ * specific to the given action.
* @param cancellationSignal A signal to cancel the operation in progress.
- * @param resultListener The callback to provide the result back to the caller
+ * @param resultListener The callback to provide the result back to the caller.
+ * You can call this on any thread. The result bundle is action specific.
*
* @see #onGetDirectActions(CancellationSignal, Consumer)
*/
diff --git a/core/java/android/app/DirectAction.java b/core/java/android/app/DirectAction.java
index d191f4b..ef3627b 100644
--- a/core/java/android/app/DirectAction.java
+++ b/core/java/android/app/DirectAction.java
@@ -22,12 +22,19 @@
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
+import android.view.accessibility.AccessibilityNodeInfo;
import com.android.internal.util.Preconditions;
+import java.util.Objects;
+
/**
* Represents a abstract action that can be perform on this app. This are requested from
- * outside the app's UI (eg by SystemUI or assistant).
+ * outside the app's UI (eg by SystemUI or assistant). The semantics of these actions are
+ * not specified by the OS. This allows open-ended and scalable approach for defining how
+ * an app interacts with components that expose alternative interaction models to the user
+ * such as the assistant, SystemUI, etc. You can use {@link #equals(Object)} to compare
+ * instances of this class.
*/
public final class DirectAction implements Parcelable {
@@ -91,7 +98,7 @@
}
/**
- * Returns the ID for this action.
+ * @return the ID for this action.
*/
@NonNull
public String getId() {
@@ -99,7 +106,7 @@
}
/**
- * Returns any extras associated with this action.
+ * @return any extras associated with this action.
*/
@Nullable
public Bundle getExtras() {
@@ -107,7 +114,7 @@
}
/**
- * Returns the LocusId for the current state for the app
+ * @return the LocusId for the current state for the app
*/
@Nullable
public LocusId getLocusId() {
@@ -120,6 +127,28 @@
}
@Override
+ public int hashCode() {
+ return mID.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == null) {
+ return false;
+ }
+
+ if (other == this) {
+ return true;
+ }
+
+ if (getClass() != other.getClass()) {
+ return false;
+ }
+
+ return mID.equals(((DirectAction) other).mID);
+ }
+
+ @Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mTaskId);
dest.writeStrongBinder(mActivityId);
@@ -139,7 +168,8 @@
/**
* Creates a new instance.
*
- * @param id The mandatory action id.
+ * @param id The mandatory action id which must be unique in the
+ * current application state.
*/
public Builder(@NonNull String id) {
Preconditions.checkNotNull(id);
@@ -147,7 +177,9 @@
}
/**
- * Sets the optional action extras.
+ * Sets the optional action extras. These extras are action specific
+ * and their semantics are open-ended potentially representing how
+ * the action is visualized, interpreted, what its arguments are, etc.
*
* @param extras The extras.
* @return This builder.
@@ -158,7 +190,9 @@
}
/**
- * Sets the optional locus id.
+ * Sets the optional locus id. This is an identifier of the application
+ * state from a user perspective. For example, a specific chat in a
+ * messaging app.
*
* @param locusId The locus id.
* @return This builder.
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 3dd510c..0112396 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3009,7 +3009,14 @@
/**
* Variation of {@link #bindService} that, in the specific case of isolated
* services, allows the caller to generate multiple instances of a service
- * from a single component declaration.
+ * from a single component declaration. In other words, you can use this to bind
+ * to a service that has specified {@link android.R.attr#isolatedProcess} and, in
+ * addition to the existing behavior of running in an isolated process, you can
+ * also through the arguments here have the system bring up multiple concurrent
+ * processes hosting their own instances of that service. The <var>instanceName</var>
+ * you provide here identifies the different instances, and you can use
+ * {@link #updateServiceGroup(ServiceConnection, int, int)} to tell the system how it
+ * should manage each of these instances.
*
* @param service Identifies the service to connect to. The Intent must
* specify an explicit component name.
@@ -3027,6 +3034,8 @@
* @throws IllegalArgumentException If the instanceName is invalid.
*
* @see #bindService
+ * @see #updateServiceGroup
+ * @see android.R.attr#isolatedProcess
*/
public boolean bindIsolatedService(@RequiresPermission @NonNull Intent service,
@BindServiceFlags int flags, @NonNull String instanceName,
@@ -3082,10 +3091,16 @@
* are considered to be related. Supplying 0 reverts to the default behavior
* of not grouping.
* @param importance Additional importance of the processes within a group. Upon calling
- * here, this will override any previous group that was set for that
- * process. This fine-tunes process killing of all processes within
- * a related groups -- higher importance values will be killed before
- * lower ones.
+ * here, this will override any previous importance that was set for that
+ * process. The most important process is 0, and higher values are
+ * successively less important. You can view this as describing how
+ * to order the processes in an array, with the processes at the end of
+ * the array being the least important. This value has no meaning besides
+ * indicating how processes should be ordered in that array one after the
+ * other. This provides a way to fine-tune the system's process killing,
+ * guiding it to kill processes at the end of the array first.
+ *
+ * @see #bindIsolatedService
*/
public void updateServiceGroup(@NonNull ServiceConnection conn, int group,
int importance) {
diff --git a/core/java/android/content/om/IOverlayManager.aidl b/core/java/android/content/om/IOverlayManager.aidl
index 722c128..43a4fe5 100644
--- a/core/java/android/content/om/IOverlayManager.aidl
+++ b/core/java/android/content/om/IOverlayManager.aidl
@@ -152,4 +152,9 @@
* @param userId The user for which to change the overlay.
*/
boolean setLowestPriority(in String packageName, in int userId);
+
+ /**
+ * Returns the list of default overlay packages, or an empty array if there are none.
+ */
+ String[] getDefaultOverlayPackages();
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index a95e094..33c0bb9 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -6178,15 +6178,7 @@
* @param activity The component name of the activity that is to be preferred.
*
* @hide
- *
- * @deprecated This function no longer does anything. It is the platform's
- * responsibility to assign preferred activities and this cannot be modified
- * directly. To determine the activities resolved by the platform, use
- * {@link #resolveActivity} or {@link #queryIntentActivities}. To configure
- * an app to be responsible for a particular role and to check current role
- * holders, see {@link android.app.role.RoleManager}.
*/
- @Deprecated
@SystemApi
public void replacePreferredActivity(@NonNull IntentFilter filter, int match,
@NonNull List<ComponentName> set, @NonNull ComponentName activity) {
diff --git a/core/java/android/database/MatrixCursor.java b/core/java/android/database/MatrixCursor.java
index a52e96e..b0d399c 100644
--- a/core/java/android/database/MatrixCursor.java
+++ b/core/java/android/database/MatrixCursor.java
@@ -18,6 +18,7 @@
import android.annotation.UnsupportedAppUsage;
import android.os.Build;
+
import java.util.ArrayList;
/**
@@ -240,6 +241,12 @@
}
return this;
}
+
+ /** @hide */
+ public final RowBuilder add(int columnIndex, Object value) {
+ data[(row * columnCount) + columnIndex] = value;
+ return this;
+ }
}
// AbstractCursor implementation.
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index 7349f0c..8596af10 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -40,6 +40,7 @@
import android.os.Looper;
import android.os.PowerManager;
import android.os.RemoteException;
+import android.os.Trace;
import android.os.UserHandle;
import android.util.Log;
import android.util.Slog;
@@ -225,6 +226,7 @@
mAuthenticationCallback = callback;
mCryptoObject = crypto;
long sessionId = crypto != null ? crypto.getOpId() : 0;
+ Trace.beginSection("FaceManager#authenticate");
mService.authenticate(mToken, sessionId, userId, mServiceReceiver,
flags, mContext.getOpPackageName());
} catch (RemoteException e) {
@@ -236,6 +238,8 @@
getErrorString(mContext, FACE_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */));
}
+ } finally {
+ Trace.endSection();
}
}
}
@@ -276,6 +280,7 @@
if (mService != null) {
try {
mEnrollmentCallback = callback;
+ Trace.beginSection("FaceManager#enroll");
mService.enroll(mToken, token, mServiceReceiver,
mContext.getOpPackageName(), disabledFeatures);
} catch (RemoteException e) {
@@ -287,6 +292,8 @@
getErrorString(mContext, FACE_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */));
}
+ } finally {
+ Trace.endSection();
}
}
}
@@ -965,6 +972,7 @@
@Override
public void handleMessage(android.os.Message msg) {
+ Trace.beginSection("FaceManager#handleMessage: " + Integer.toString(msg.what));
switch (msg.what) {
case MSG_ENROLL_RESULT:
sendEnrollResult((Face) msg.obj, msg.arg1 /* remaining */);
@@ -1000,6 +1008,7 @@
default:
Log.w(TAG, "Unknown message: " + msg.what);
}
+ Trace.endSection();
}
}
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 94c8b91..3a4741a 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -978,11 +978,6 @@
*/
public static final int Q = CUR_DEVELOPMENT;
- /**
- * Stub for a potential new API level after P.
- * @hide
- */
- public static final int P0 = Q;
}
/** The type of build, like "user" or "eng". */
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 7cc7ccd..1b41694 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -866,8 +866,8 @@
if (storageManager.needsCheckpoint()) {
Log.i(TAG, "Rescue Party requested wipe. Aborting update instead.");
storageManager.abortChanges("rescueparty", false);
+ return;
}
- return;
} catch (RemoteException e) {
Log.i(TAG, "Failed to handle with checkpointing. Continuing with wipe.");
}
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index 1aa5b06..2a41c20 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -23,11 +23,8 @@
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.pm.IPackageManager;
-import android.content.pm.PackageManager;
-import android.content.pm.PermissionInfo;
import android.os.RemoteException;
import com.android.internal.annotations.Immutable;
@@ -107,11 +104,11 @@
/**
* Get set of permissions that have been split into more granular or dependent permissions.
*
- * <p>E.g. before {@link android.os.Build.VERSION_CODES#P0} an app that was granted
+ * <p>E.g. before {@link android.os.Build.VERSION_CODES#Q} an app that was granted
* {@link Manifest.permission#ACCESS_COARSE_LOCATION} could access he location while it was in
- * foreground and background. On platforms after {@link android.os.Build.VERSION_CODES#P0}
+ * foreground and background. On platforms after {@link android.os.Build.VERSION_CODES#Q}
* the location permission only grants location access while the app is in foreground. This
- * would break apps that target before {@link android.os.Build.VERSION_CODES#P0}. Hence whenever
+ * would break apps that target before {@link android.os.Build.VERSION_CODES#Q}. Hence whenever
* such an old app asks for a location permission (i.e. the
* {@link SplitPermissionInfo#getSplitPermission()}), then the
* {@link Manifest.permission#ACCESS_BACKGROUND_LOCATION} permission (inside
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 9215de1..774d4ae 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -159,6 +159,14 @@
public static final String NAMESPACE_INTELLIGENCE_ATTENTION = "intelligence_attention";
/**
+ * Definitions for properties related to Content Suggestions.
+ *
+ * @hide
+ */
+ public static final String NAMESPACE_INTELLIGENCE_CONTENT_SUGGESTIONS =
+ "intelligence_content_suggestions";
+
+ /**
* Namespace for all media native related features.
*
* @hide
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 4da0d2d..b0e980e 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1791,6 +1791,58 @@
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_MANAGE_DOMAIN_URLS = "android.settings.MANAGE_DOMAIN_URLS";
+ /**
+ * Broadcast to trigger notification of asking user to enable MMS.
+ * Need to specify {@link #EXTRA_ENABLE_MMS_DATA_REQUEST_REASON} and {@link #EXTRA_SUB_ID}.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_ENABLE_MMS_DATA_REQUEST =
+ "android.settings.ENABLE_MMS_DATA_REQUEST";
+
+ /**
+ * Integer value that specifies the reason triggering enable MMS data notification.
+ * This must be passed as an extra field to the {@link #ACTION_ENABLE_MMS_DATA_REQUEST}.
+ * Extra with value of EnableMmsDataReason interface.
+ * @hide
+ */
+ public static final String EXTRA_ENABLE_MMS_DATA_REQUEST_REASON =
+ "android.settings.extra.ENABLE_MMS_DATA_REQUEST_REASON";
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "ENABLE_MMS_DATA_REQUEST_REASON_" }, value = {
+ ENABLE_MMS_DATA_REQUEST_REASON_INCOMING_MMS,
+ ENABLE_MMS_DATA_REQUEST_REASON_OUTGOING_MMS,
+ })
+ public @interface EnableMmsDataReason{}
+
+ /**
+ * Requesting to enable MMS data because there's an incoming MMS.
+ * @hide
+ */
+ public static final int ENABLE_MMS_DATA_REQUEST_REASON_INCOMING_MMS = 0;
+
+ /**
+ * Requesting to enable MMS data because user is sending MMS.
+ * @hide
+ */
+ public static final int ENABLE_MMS_DATA_REQUEST_REASON_OUTGOING_MMS = 1;
+
+ /**
+ * Activity Action: Show screen of a cellular subscription and highlight the
+ * "enable MMS" toggle.
+ * <p>
+ * Input: {@link #EXTRA_SUB_ID}: Sub ID of the subscription.
+ * <p>
+ * Output: Nothing
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_MMS_MESSAGE_SETTING = "android.settings.MMS_MESSAGE_SETTING";
+
// End of Intent actions for Settings
/**
@@ -6053,9 +6105,8 @@
"unknown_sources_default_reversed";
/**
- * Comma-separated list of location providers that are accessible. Do not rely on
- * this value being present or correct, or on ContentObserver notifications on the
- * corresponding Uri.
+ * Comma-separated list of location providers that are enabled. Do not rely on this value
+ * being present or correct, or on ContentObserver notifications on the corresponding Uri.
*
* @deprecated The preferred methods for checking provider status and listening for changes
* are via {@link LocationManager#isProviderEnabled(String)} and
@@ -6098,17 +6149,14 @@
/**
* Location mode is off.
- *
- * @deprecated See {@link #LOCATION_MODE}.
*/
- @Deprecated
public static final int LOCATION_MODE_OFF = 0;
/**
* This mode no longer has any distinct meaning, but is interpreted as the location mode is
* on.
*
- * @deprecated See {@link #LOCATION_MODE_ON}.
+ * @deprecated See {@link #LOCATION_MODE}.
*/
@Deprecated
public static final int LOCATION_MODE_SENSORS_ONLY = 1;
@@ -6117,7 +6165,7 @@
* This mode no longer has any distinct meaning, but is interpreted as the location mode is
* on.
*
- * @deprecated See {@link #LOCATION_MODE_ON}.
+ * @deprecated See {@link #LOCATION_MODE}.
*/
@Deprecated
public static final int LOCATION_MODE_BATTERY_SAVING = 2;
@@ -6126,7 +6174,7 @@
* This mode no longer has any distinct meaning, but is interpreted as the location mode is
* on.
*
- * @deprecated See {@link #LOCATION_MODE_ON}.
+ * @deprecated See {@link #LOCATION_MODE}.
*/
@Deprecated
public static final int LOCATION_MODE_HIGH_ACCURACY = 3;
@@ -6134,9 +6182,9 @@
/**
* Location mode is on.
*
- * @deprecated See {@link #LOCATION_MODE}.
+ * @hide
*/
- @Deprecated
+ @SystemApi
public static final int LOCATION_MODE_ON = LOCATION_MODE_HIGH_ACCURACY;
/**
@@ -11913,6 +11961,36 @@
public static final String JOB_SCHEDULER_CONSTANTS = "job_scheduler_constants";
/**
+ * Job scheduler QuotaController specific settings.
+ * This is encoded as a key=value list, separated by commas. Ex:
+ *
+ * "max_job_count_working=5,max_job_count_rare=2"
+ *
+ * <p>
+ * Type: string
+ *
+ * @hide
+ * @see com.android.server.job.JobSchedulerService.Constants
+ */
+ public static final String JOB_SCHEDULER_QUOTA_CONTROLLER_CONSTANTS =
+ "job_scheduler_quota_controller_constants";
+
+ /**
+ * Job scheduler TimeController specific settings.
+ * This is encoded as a key=value list, separated by commas. Ex:
+ *
+ * "skip_not_ready_jobs=true5,other_key=2"
+ *
+ * <p>
+ * Type: string
+ *
+ * @hide
+ * @see com.android.server.job.JobSchedulerService.Constants
+ */
+ public static final String JOB_SCHEDULER_TIME_CONTROLLER_CONSTANTS =
+ "job_scheduler_time_controller_constants";
+
+ /**
* ShortcutManager specific settings.
* This is encoded as a key=value list, separated by commas. Ex:
*
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index cd8c7ae..c9d37bf 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -1995,7 +1995,8 @@
}
/**
- * @return the index of the activity that this state is for.
+ * @return the index of the activity that this state is for or -1
+ * if there was no assist data captured.
*/
public @IntRange(from = -1) int getIndex() {
return mIndex;
@@ -2048,7 +2049,8 @@
}
/**
- * Represents the id of an assist source activity.
+ * Represents the id of an assist source activity. You can use
+ * {@link #equals(Object)} to compare instances of this class.
*/
public static class ActivityId {
private final int mTaskId;
diff --git a/core/java/android/service/watchdog/ExplicitHealthCheckService.java b/core/java/android/service/watchdog/ExplicitHealthCheckService.java
index eeefb4a..dc9c858 100644
--- a/core/java/android/service/watchdog/ExplicitHealthCheckService.java
+++ b/core/java/android/service/watchdog/ExplicitHealthCheckService.java
@@ -183,7 +183,6 @@
*/
@SystemApi
public static final class PackageConfig implements Parcelable {
- // TODO: Receive from DeviceConfig flag
private static final long DEFAULT_HEALTH_CHECK_TIMEOUT_MILLIS = TimeUnit.HOURS.toMillis(1);
private final String mPackageName;
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index c2aec6a..a25f2ee 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -508,14 +508,25 @@
*
* @param displayId Display ID.
* @param shouldShow Indicates that the display should show IME.
- * @see KeyguardManager#isDeviceSecure()
- * @see KeyguardManager#isDeviceLocked()
* @hide
*/
@TestApi
default void setShouldShowIme(int displayId, boolean shouldShow) {
}
+ /**
+ * Indicates that the display should show IME.
+ *
+ * @param displayId The id of the display.
+ * @return {@code true} if the display should show IME when an input field becomes
+ * focused on it.
+ * @hide
+ */
+ @TestApi
+ default boolean shouldShowIme(int displayId) {
+ return false;
+ }
+
public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable {
/**
* X position for this window. With the default gravity it is ignored.
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 2e4db5c..c349443 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -192,4 +192,13 @@
} catch (RemoteException e) {
}
}
+
+ @Override
+ public boolean shouldShowIme(int displayId) {
+ try {
+ return WindowManagerGlobal.getWindowManagerService().shouldShowIme(displayId);
+ } catch (RemoteException e) {
+ }
+ return false;
+ }
}
diff --git a/core/java/android/view/textclassifier/TextClassificationManager.java b/core/java/android/view/textclassifier/TextClassificationManager.java
index 417c6e7..042b943 100644
--- a/core/java/android/view/textclassifier/TextClassificationManager.java
+++ b/core/java/android/view/textclassifier/TextClassificationManager.java
@@ -25,6 +25,7 @@
import android.database.ContentObserver;
import android.os.ServiceManager;
import android.provider.DeviceConfig;
+import android.provider.DeviceConfig.Properties;
import android.provider.Settings;
import android.service.textclassifier.TextClassifierService;
import android.view.textclassifier.TextClassifier.TextClassifierType;
@@ -199,7 +200,7 @@
getApplicationContext().getContentResolver()
.unregisterContentObserver(mSettingsObserver);
if (ConfigParser.ENABLE_DEVICE_CONFIG) {
- DeviceConfig.removeOnPropertyChangedListener(mSettingsObserver);
+ DeviceConfig.removeOnPropertiesChangedListener(mSettingsObserver);
}
}
} finally {
@@ -286,7 +287,7 @@
}
private static final class SettingsObserver extends ContentObserver
- implements DeviceConfig.OnPropertyChangedListener {
+ implements DeviceConfig.OnPropertiesChangedListener {
private final WeakReference<TextClassificationManager> mTcm;
@@ -298,7 +299,7 @@
false /* notifyForDescendants */,
this);
if (ConfigParser.ENABLE_DEVICE_CONFIG) {
- DeviceConfig.addOnPropertyChangedListener(
+ DeviceConfig.addOnPropertiesChangedListener(
DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
ActivityThread.currentApplication().getMainExecutor(),
this);
@@ -311,7 +312,7 @@
}
@Override
- public void onPropertyChanged(String namespace, String name, String value) {
+ public void onPropertiesChanged(Properties properties) {
invalidateSettings();
}
diff --git a/core/java/com/android/internal/app/AbstractResolverComparator.java b/core/java/com/android/internal/app/AbstractResolverComparator.java
index b7276a0..87d80d4 100644
--- a/core/java/com/android/internal/app/AbstractResolverComparator.java
+++ b/core/java/com/android/internal/app/AbstractResolverComparator.java
@@ -22,9 +22,14 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
import android.os.UserHandle;
import android.util.Log;
+
import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
+
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
@@ -35,6 +40,8 @@
abstract class AbstractResolverComparator implements Comparator<ResolvedComponentInfo> {
private static final int NUM_OF_TOP_ANNOTATIONS_TO_USE = 3;
+ private static final boolean DEBUG = false;
+ private static final String TAG = "AbstractResolverComp";
private AfterCompute mAfterCompute;
protected final PackageManager mPm;
@@ -47,6 +54,46 @@
// can be null if mHttp == false or current user has no default browser package
private final String mDefaultBrowserPackageName;
+ // message types
+ static final int RANKER_SERVICE_RESULT = 0;
+ static final int RANKER_RESULT_TIMEOUT = 1;
+
+ // timeout for establishing connections with a ResolverRankerService, collecting features and
+ // predicting ranking scores.
+ private static final int WATCHDOG_TIMEOUT_MILLIS = 500;
+
+ protected final Handler mHandler = new Handler(Looper.getMainLooper()) {
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case RANKER_SERVICE_RESULT:
+ if (DEBUG) {
+ Log.d(TAG, "RANKER_SERVICE_RESULT");
+ }
+ if (mHandler.hasMessages(RANKER_RESULT_TIMEOUT)) {
+ if (msg.obj != null) {
+ handleResultMessage(msg);
+ } else {
+ Log.e(TAG, "Receiving null prediction results.");
+ }
+ mHandler.removeMessages(RANKER_RESULT_TIMEOUT);
+ afterCompute();
+ }
+ break;
+
+ case RANKER_RESULT_TIMEOUT:
+ if (DEBUG) {
+ Log.d(TAG, "RANKER_RESULT_TIMEOUT; unbinding services");
+ }
+ mHandler.removeMessages(RANKER_SERVICE_RESULT);
+ afterCompute();
+ break;
+
+ default:
+ super.handleMessage(msg);
+ }
+ }
+ };
+
AbstractResolverComparator(Context context, Intent intent) {
String scheme = intent.getScheme();
mHttp = "http".equals(scheme) || "https".equals(scheme);
@@ -142,9 +189,16 @@
* #getScore(ComponentName)} or {@link #compare(Object, Object)}, in order to prepare the
* comparator for those calls. Note that {@link #getScore(ComponentName)} uses {@link
* ComponentName}, so the implementation will have to be prepared to identify a {@link
- * ResolvedComponentInfo} by {@link ComponentName}.
+ * ResolvedComponentInfo} by {@link ComponentName}. {@link #beforeCompute()} will be called
+ * before doing any computing.
*/
- abstract void compute(List<ResolvedComponentInfo> targets);
+ final void compute(List<ResolvedComponentInfo> targets) {
+ beforeCompute();
+ doCompute(targets);
+ }
+
+ /** Implementation of compute called after {@link #beforeCompute()}. */
+ abstract void doCompute(List<ResolvedComponentInfo> targets);
/**
* Returns the score that was calculated for the corresponding {@link ResolvedComponentInfo}
@@ -152,6 +206,9 @@
*/
abstract float getScore(ComponentName name);
+ /** Handles result message sent to mHandler. */
+ abstract void handleResultMessage(Message message);
+
/**
* Reports to UsageStats what was chosen.
*/
@@ -172,10 +229,26 @@
void updateModel(ComponentName componentName) {
}
+ /** Called before {@link #doCompute(List)}. Sets up 500ms timeout. */
+ void beforeCompute() {
+ if (DEBUG) Log.d(TAG, "Setting watchdog timer for " + WATCHDOG_TIMEOUT_MILLIS + "ms");
+ if (mHandler == null) {
+ Log.d(TAG, "Error: Handler is Null; Needs to be initialized.");
+ return;
+ }
+ mHandler.sendEmptyMessageDelayed(RANKER_RESULT_TIMEOUT, WATCHDOG_TIMEOUT_MILLIS);
+ }
+
/**
- * Called when the {@link ResolverActivity} is destroyed.
+ * Called when the {@link ResolverActivity} is destroyed. This calls {@link #afterCompute()}. If
+ * this call needs to happen at a different time during destroy, the method should be
+ * overridden.
*/
- abstract void destroy();
+ void destroy() {
+ mHandler.removeMessages(RANKER_SERVICE_RESULT);
+ mHandler.removeMessages(RANKER_RESULT_TIMEOUT);
+ afterCompute();
+ }
private boolean isDefaultBrowser(ResolveInfo ri) {
// It makes sense to prefer the default browser
diff --git a/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java b/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java
index cb44c67..3b4e1a0 100644
--- a/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java
+++ b/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java
@@ -26,6 +26,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.ResolveInfo;
+import android.os.Message;
import android.os.UserHandle;
import android.view.textclassifier.Log;
@@ -73,7 +74,7 @@
}
@Override
- void compute(List<ResolvedComponentInfo> targets) {
+ void doCompute(List<ResolvedComponentInfo> targets) {
List<AppTarget> appTargets = new ArrayList<>();
for (ResolvedComponentInfo target : targets) {
appTargets.add(new AppTarget.Builder(new AppTargetId(target.name.flattenToString()))
@@ -82,15 +83,24 @@
}
mAppPredictor.sortTargets(appTargets, mContext.getMainExecutor(),
sortedAppTargets -> {
- for (int i = 0; i < sortedAppTargets.size(); i++) {
- mTargetRanks.put(new ComponentName(sortedAppTargets.get(i).getPackageName(),
- sortedAppTargets.get(i).getClassName()), i);
- }
- afterCompute();
+ Message msg =
+ Message.obtain(mHandler, RANKER_SERVICE_RESULT, sortedAppTargets);
+ msg.sendToTarget();
});
}
@Override
+ void handleResultMessage(Message msg) {
+ if (msg.what == RANKER_SERVICE_RESULT) {
+ final List<AppTarget> sortedAppTargets = (List<AppTarget>) msg.obj;
+ for (int i = 0; i < sortedAppTargets.size(); i++) {
+ mTargetRanks.put(new ComponentName(sortedAppTargets.get(i).getPackageName(),
+ sortedAppTargets.get(i).getClassName()), i);
+ }
+ }
+ }
+
+ @Override
float getScore(ComponentName name) {
Integer rank = mTargetRanks.get(name);
if (rank == null) {
@@ -111,9 +121,4 @@
.setClassName(componentName.getClassName()).build(),
ACTION_LAUNCH).build());
}
-
- @Override
- void destroy() {
- // Do nothing. App Predictor destruction is handled by caller.
- }
}
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 204012f..1eabbd8 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -114,6 +114,7 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.ImageUtils;
+import com.android.internal.widget.ResolverDrawerLayout;
import com.google.android.collect.Lists;
@@ -143,6 +144,8 @@
public static final String EXTRA_PRIVATE_RETAIN_IN_ON_STOP
= "com.android.internal.app.ChooserActivity.EXTRA_PRIVATE_RETAIN_IN_ON_STOP";
+ private static final String PREF_NUM_SHEET_EXPANSIONS = "pref_num_sheet_expansions";
+
private static final boolean DEBUG = false;
/**
@@ -502,6 +505,21 @@
chooserHeader.setElevation(defaultElevation);
}
});
+
+ mResolverDrawerLayout.setOnCollapsedChangedListener(
+ new ResolverDrawerLayout.OnCollapsedChangedListener() {
+
+ // Only consider one expansion per activity creation
+ private boolean mWrittenOnce = false;
+
+ @Override
+ public void onCollapsedChanged(boolean isCollapsed) {
+ if (!isCollapsed && !mWrittenOnce) {
+ incrementNumSheetExpansions();
+ mWrittenOnce = true;
+ }
+ }
+ });
}
if (DEBUG) {
@@ -881,6 +899,15 @@
return CONTENT_PREVIEW_TEXT;
}
+ private int getNumSheetExpansions() {
+ return getPreferences(Context.MODE_PRIVATE).getInt(PREF_NUM_SHEET_EXPANSIONS, 0);
+ }
+
+ private void incrementNumSheetExpansions() {
+ getPreferences(Context.MODE_PRIVATE).edit().putInt(PREF_NUM_SHEET_EXPANSIONS,
+ getNumSheetExpansions() + 1).apply();
+ }
+
@Override
protected void onDestroy() {
super.onDestroy();
@@ -2030,7 +2057,8 @@
public static final int TARGET_STANDARD_AZ = 3;
private static final int MAX_SUGGESTED_APP_TARGETS = 4;
- private static final int MAX_TARGETS_PER_SERVICE = 2;
+ private static final int MAX_CHOOSER_TARGETS_PER_APP = 2;
+ private static final int MAX_SHORTCUT_TARGETS_PER_APP = 8;
private static final int MAX_SERVICE_TARGETS = 8;
@@ -2356,9 +2384,11 @@
final float baseScore = getBaseScore(origTarget, isShortcutResult);
Collections.sort(targets, mBaseTargetComparator);
+ final int maxTargets = isShortcutResult ? MAX_SHORTCUT_TARGETS_PER_APP
+ : MAX_CHOOSER_TARGETS_PER_APP;
float lastScore = 0;
boolean shouldNotify = false;
- for (int i = 0, N = Math.min(targets.size(), MAX_TARGETS_PER_SERVICE); i < N; i++) {
+ for (int i = 0, count = Math.min(targets.size(), maxTargets); i < count; i++) {
final ChooserTarget target = targets.get(i);
float targetScore = target.getScore();
targetScore *= baseScore;
@@ -2491,19 +2521,25 @@
private DirectShareViewHolder mDirectShareViewHolder;
private int mChooserTargetWidth = 0;
+ private boolean mShowAzLabelIfPoss;
private static final int VIEW_TYPE_DIRECT_SHARE = 0;
private static final int VIEW_TYPE_NORMAL = 1;
private static final int VIEW_TYPE_CONTENT_PREVIEW = 2;
private static final int VIEW_TYPE_PROFILE = 3;
+ private static final int VIEW_TYPE_AZ_LABEL = 4;
private static final int MAX_TARGETS_PER_ROW_PORTRAIT = 4;
private static final int MAX_TARGETS_PER_ROW_LANDSCAPE = 8;
+ private static final int NUM_EXPANSIONS_TO_HIDE_AZ_LABEL = 20;
+
public ChooserRowAdapter(ChooserListAdapter wrappedAdapter) {
mChooserListAdapter = wrappedAdapter;
mLayoutInflater = LayoutInflater.from(ChooserActivity.this);
+ mShowAzLabelIfPoss = getNumSheetExpansions() < NUM_EXPANSIONS_TO_HIDE_AZ_LABEL;
+
wrappedAdapter.registerDataSetObserver(new DataSetObserver() {
@Override
public void onChanged() {
@@ -2550,12 +2586,27 @@
}
@Override
+ public boolean areAllItemsEnabled() {
+ return false;
+ }
+
+ @Override
+ public boolean isEnabled(int position) {
+ int viewType = getItemViewType(position);
+ if (viewType == VIEW_TYPE_CONTENT_PREVIEW) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
public int getCount() {
return (int) (
getContentPreviewRowCount()
+ getProfileRowCount()
+ getServiceTargetRowCount()
+ getCallerAndRankedTargetRowCount()
+ + getAzLabelRowCount()
+ Math.ceil(
(float) mChooserListAdapter.getAlphaTargetCount()
/ getMaxTargetsPerRow())
@@ -2593,6 +2644,11 @@
return 0;
}
+ public int getAzLabelRowCount() {
+ // Only show a label if the a-z list is showing
+ return (mShowAzLabelIfPoss && mChooserListAdapter.getAlphaTargetCount() > 0) ? 1 : 0;
+ }
+
@Override
public Object getItem(int position) {
// We have nothing useful to return here.
@@ -2617,6 +2673,10 @@
return createProfileView(convertView, parent);
}
+ if (viewType == VIEW_TYPE_AZ_LABEL) {
+ return createAzLabelView(parent);
+ }
+
if (convertView == null) {
holder = createViewHolder(viewType, parent);
} else {
@@ -2630,27 +2690,29 @@
@Override
public int getItemViewType(int position) {
- if (position == 0 && getContentPreviewRowCount() == 1) {
- return VIEW_TYPE_CONTENT_PREVIEW;
- }
+ int count;
- if (getProfileRowCount() == 1 && position == getContentPreviewRowCount()) {
- return VIEW_TYPE_PROFILE;
- }
+ int countSum = (count = getContentPreviewRowCount());
+ if (count > 0 && position < countSum) return VIEW_TYPE_CONTENT_PREVIEW;
- final int start = getFirstRowPosition(position);
- final int startType = mChooserListAdapter.getPositionTargetType(start);
+ countSum += (count = getProfileRowCount());
+ if (count > 0 && position < countSum) return VIEW_TYPE_PROFILE;
- if (startType == ChooserListAdapter.TARGET_SERVICE) {
- return VIEW_TYPE_DIRECT_SHARE;
- }
+ countSum += (count = getServiceTargetRowCount());
+ if (count > 0 && position < countSum) return VIEW_TYPE_DIRECT_SHARE;
+
+ countSum += (count = getCallerAndRankedTargetRowCount());
+ if (count > 0 && position < countSum) return VIEW_TYPE_NORMAL;
+
+ countSum += (count = getAzLabelRowCount());
+ if (count > 0 && position < countSum) return VIEW_TYPE_AZ_LABEL;
return VIEW_TYPE_NORMAL;
}
@Override
public int getViewTypeCount() {
- return 4;
+ return 5;
}
private ViewGroup createContentPreviewView(View convertView, ViewGroup parent) {
@@ -2677,6 +2739,10 @@
return profileRow;
}
+ private View createAzLabelView(ViewGroup parent) {
+ return mLayoutInflater.inflate(R.layout.chooser_az_label_row, parent, false);
+ }
+
private RowViewHolder loadViewsIntoRow(RowViewHolder holder) {
final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
final int exactSpec = MeasureSpec.makeMeasureSpec(mChooserTargetWidth,
@@ -2775,16 +2841,24 @@
}
/**
- * Need to merge CALLER + ranked STANDARD into a single row. All other types
- * are placed into their own row as determined by their target type, and dividers
- * are added in the list to separate each type.
+ * Need to merge CALLER + ranked STANDARD into a single row and prevent a separator from
+ * showing on top of the AZ list if the AZ label is visible. All other types are placed into
+ * their own row as determined by their target type, and dividers are added in the list to
+ * separate each type.
*/
int getRowType(int rowPosition) {
+ // Merge caller and ranked standard into a single row
int positionType = mChooserListAdapter.getPositionTargetType(rowPosition);
if (positionType == ChooserListAdapter.TARGET_CALLER) {
return ChooserListAdapter.TARGET_STANDARD;
}
+ // If an the A-Z label is shown, prevent a separator from appearing by making the A-Z
+ // row type the same as the suggestion row type
+ if (getAzLabelRowCount() > 0 && positionType == ChooserListAdapter.TARGET_STANDARD_AZ) {
+ return ChooserListAdapter.TARGET_STANDARD;
+ }
+
return positionType;
}
@@ -2864,6 +2938,8 @@
return serviceCount + (row - serviceRows) * getMaxTargetsPerRow();
}
+ row -= getAzLabelRowCount();
+
return callerAndRankedCount + serviceCount
+ (row - callerAndRankedRows - serviceRows) * getMaxTargetsPerRow();
}
diff --git a/core/java/com/android/internal/app/ResolverRankerServiceResolverComparator.java b/core/java/com/android/internal/app/ResolverRankerServiceResolverComparator.java
index 726b186..a781907 100644
--- a/core/java/com/android/internal/app/ResolverRankerServiceResolverComparator.java
+++ b/core/java/com/android/internal/app/ResolverRankerServiceResolverComparator.java
@@ -18,7 +18,6 @@
package com.android.internal.app;
import android.app.usage.UsageStats;
-import android.app.usage.UsageStatsManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -28,9 +27,7 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.metrics.LogMaker;
-import android.os.Handler;
import android.os.IBinder;
-import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -67,10 +64,6 @@
private static final float RECENCY_MULTIPLIER = 2.f;
- // message types
- private static final int RESOLVER_RANKER_SERVICE_RESULT = 0;
- private static final int RESOLVER_RANKER_RESULT_TIMEOUT = 1;
-
// timeout for establishing connections with a ResolverRankerService.
private static final int CONNECTION_COST_TIMEOUT_MILLIS = 200;
// timeout for establishing connections with a ResolverRankerService, collecting features and
@@ -93,57 +86,6 @@
private Context mContext;
private CountDownLatch mConnectSignal;
- private final Handler mHandler = new Handler(Looper.getMainLooper()) {
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case RESOLVER_RANKER_SERVICE_RESULT:
- if (DEBUG) {
- Log.d(TAG, "RESOLVER_RANKER_SERVICE_RESULT");
- }
- if (mHandler.hasMessages(RESOLVER_RANKER_RESULT_TIMEOUT)) {
- if (msg.obj != null) {
- final List<ResolverTarget> receivedTargets =
- (List<ResolverTarget>) msg.obj;
- if (receivedTargets != null && mTargets != null
- && receivedTargets.size() == mTargets.size()) {
- final int size = mTargets.size();
- boolean isUpdated = false;
- for (int i = 0; i < size; ++i) {
- final float predictedProb =
- receivedTargets.get(i).getSelectProbability();
- if (predictedProb != mTargets.get(i).getSelectProbability()) {
- mTargets.get(i).setSelectProbability(predictedProb);
- isUpdated = true;
- }
- }
- if (isUpdated) {
- mRankerServiceName = mResolvedRankerName;
- }
- } else {
- Log.e(TAG, "Sizes of sent and received ResolverTargets diff.");
- }
- } else {
- Log.e(TAG, "Receiving null prediction results.");
- }
- mHandler.removeMessages(RESOLVER_RANKER_RESULT_TIMEOUT);
- afterCompute();
- }
- break;
-
- case RESOLVER_RANKER_RESULT_TIMEOUT:
- if (DEBUG) {
- Log.d(TAG, "RESOLVER_RANKER_RESULT_TIMEOUT; unbinding services");
- }
- mHandler.removeMessages(RESOLVER_RANKER_SERVICE_RESULT);
- afterCompute();
- break;
-
- default:
- super.handleMessage(msg);
- }
- }
- };
-
public ResolverRankerServiceResolverComparator(Context context, Intent intent,
String referrerPackage, AfterCompute afterCompute) {
super(context, intent);
@@ -159,11 +101,35 @@
setCallBack(afterCompute);
}
+ @Override
+ public void handleResultMessage(Message msg) {
+ if (msg.what != RANKER_SERVICE_RESULT) {
+ return;
+ }
+ final List<ResolverTarget> receivedTargets = (List<ResolverTarget>) msg.obj;
+ if (receivedTargets != null && mTargets != null
+ && receivedTargets.size() == mTargets.size()) {
+ final int size = mTargets.size();
+ boolean isUpdated = false;
+ for (int i = 0; i < size; ++i) {
+ final float predictedProb =
+ receivedTargets.get(i).getSelectProbability();
+ if (predictedProb != mTargets.get(i).getSelectProbability()) {
+ mTargets.get(i).setSelectProbability(predictedProb);
+ isUpdated = true;
+ }
+ }
+ if (isUpdated) {
+ mRankerServiceName = mResolvedRankerName;
+ }
+ } else {
+ Log.e(TAG, "Sizes of sent and received ResolverTargets diff.");
+ }
+ }
+
// compute features for each target according to usage stats of targets.
@Override
- public void compute(List<ResolvedComponentInfo> targets) {
- reset();
-
+ public void doCompute(List<ResolvedComponentInfo> targets) {
final long recentSinceTime = mCurrentTime - RECENCY_TIME_PERIOD;
float mostRecencyScore = 1.0f;
@@ -322,8 +288,8 @@
// unbind the service and clear unhandled messges.
@Override
public void destroy() {
- mHandler.removeMessages(RESOLVER_RANKER_SERVICE_RESULT);
- mHandler.removeMessages(RESOLVER_RANKER_RESULT_TIMEOUT);
+ mHandler.removeMessages(RANKER_SERVICE_RESULT);
+ mHandler.removeMessages(RANKER_RESULT_TIMEOUT);
if (mConnection != null) {
mContext.unbindService(mConnection);
mConnection.destroy();
@@ -417,15 +383,6 @@
return null;
}
- // set a watchdog, to avoid waiting for ranking service for too long.
- private void startWatchDog(int timeOutLimit) {
- if (DEBUG) Log.d(TAG, "Setting watchdog timer for " + timeOutLimit + "ms");
- if (mHandler == null) {
- Log.d(TAG, "Error: Handler is Null; Needs to be initialized.");
- }
- mHandler.sendEmptyMessageDelayed(RESOLVER_RANKER_RESULT_TIMEOUT, timeOutLimit);
- }
-
private class ResolverRankerServiceConnection implements ServiceConnection {
private final CountDownLatch mConnectSignal;
@@ -442,7 +399,7 @@
}
synchronized (mLock) {
final Message msg = Message.obtain();
- msg.what = RESOLVER_RANKER_SERVICE_RESULT;
+ msg.what = RANKER_SERVICE_RESULT;
msg.obj = targets;
mHandler.sendMessage(msg);
}
@@ -477,12 +434,13 @@
}
}
- private void reset() {
+ @Override
+ void beforeCompute() {
+ super.beforeCompute();
mTargetsDict.clear();
mTargets = null;
mRankerServiceName = new ComponentName(mContext, this.getClass());
mResolvedRankerName = null;
- startWatchDog(WATCHDOG_TIMEOUT_MILLIS);
initRanker(mContext);
}
diff --git a/core/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java
index 76826d3..9e8bd64 100644
--- a/core/java/com/android/internal/content/FileSystemProvider.java
+++ b/core/java/com/android/internal/content/FileSystemProvider.java
@@ -45,6 +45,7 @@
import android.webkit.MimeTypeMap;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.ArrayUtils;
import libcore.io.IoUtils;
@@ -450,7 +451,11 @@
@Override
public String getDocumentType(String documentId) throws FileNotFoundException {
- final File file = getFileForDocId(documentId);
+ return getDocumentType(documentId, getFileForDocId(documentId));
+ }
+
+ private String getDocumentType(final String documentId, final File file)
+ throws FileNotFoundException {
if (file.isDirectory()) {
return Document.MIME_TYPE_DIR;
} else {
@@ -532,51 +537,63 @@
return DocumentsContract.openImageThumbnail(file);
}
- protected RowBuilder includeFile(MatrixCursor result, String docId, File file)
+ protected RowBuilder includeFile(final MatrixCursor result, String docId, File file)
throws FileNotFoundException {
+ final String[] columns = result.getColumnNames();
+ final RowBuilder row = result.newRow();
+
if (docId == null) {
docId = getDocIdForFile(file);
} else {
file = getFileForDocId(docId);
}
+ final String mimeType = getDocumentType(docId, file);
+ row.add(Document.COLUMN_DOCUMENT_ID, docId);
+ row.add(Document.COLUMN_MIME_TYPE, mimeType);
- int flags = 0;
+ final int flagIndex = ArrayUtils.indexOf(columns, Document.COLUMN_FLAGS);
+ if (flagIndex != -1) {
+ int flags = 0;
+ if (file.canWrite()) {
+ if (mimeType.equals(Document.MIME_TYPE_DIR)) {
+ flags |= Document.FLAG_DIR_SUPPORTS_CREATE;
+ flags |= Document.FLAG_SUPPORTS_DELETE;
+ flags |= Document.FLAG_SUPPORTS_RENAME;
+ flags |= Document.FLAG_SUPPORTS_MOVE;
+ } else {
+ flags |= Document.FLAG_SUPPORTS_WRITE;
+ flags |= Document.FLAG_SUPPORTS_DELETE;
+ flags |= Document.FLAG_SUPPORTS_RENAME;
+ flags |= Document.FLAG_SUPPORTS_MOVE;
+ }
+ }
- if (file.canWrite()) {
- if (file.isDirectory()) {
- flags |= Document.FLAG_DIR_SUPPORTS_CREATE;
- flags |= Document.FLAG_SUPPORTS_DELETE;
- flags |= Document.FLAG_SUPPORTS_RENAME;
- flags |= Document.FLAG_SUPPORTS_MOVE;
- } else {
- flags |= Document.FLAG_SUPPORTS_WRITE;
- flags |= Document.FLAG_SUPPORTS_DELETE;
- flags |= Document.FLAG_SUPPORTS_RENAME;
- flags |= Document.FLAG_SUPPORTS_MOVE;
+ if (mimeType.startsWith("image/")) {
+ flags |= Document.FLAG_SUPPORTS_THUMBNAIL;
+ }
+
+ if (typeSupportsMetadata(mimeType)) {
+ flags |= Document.FLAG_SUPPORTS_METADATA;
+ }
+ row.add(flagIndex, flags);
+ }
+
+ final int displayNameIndex = ArrayUtils.indexOf(columns, Document.COLUMN_DISPLAY_NAME);
+ if (displayNameIndex != -1) {
+ row.add(displayNameIndex, file.getName());
+ }
+
+ final int lastModifiedIndex = ArrayUtils.indexOf(columns, Document.COLUMN_LAST_MODIFIED);
+ if (lastModifiedIndex != -1) {
+ final long lastModified = file.lastModified();
+ // Only publish dates reasonably after epoch
+ if (lastModified > 31536000000L) {
+ row.add(lastModifiedIndex, lastModified);
}
}
-
- final String mimeType = getDocumentType(docId);
- final String displayName = file.getName();
- if (mimeType.startsWith("image/")) {
- flags |= Document.FLAG_SUPPORTS_THUMBNAIL;
- }
-
- if (typeSupportsMetadata(mimeType)) {
- flags |= Document.FLAG_SUPPORTS_METADATA;
- }
-
- final RowBuilder row = result.newRow();
- row.add(Document.COLUMN_DOCUMENT_ID, docId);
- row.add(Document.COLUMN_DISPLAY_NAME, displayName);
- row.add(Document.COLUMN_SIZE, file.length());
- row.add(Document.COLUMN_MIME_TYPE, mimeType);
- row.add(Document.COLUMN_FLAGS, flags);
-
- // Only publish dates reasonably after epoch
- long lastModified = file.lastModified();
- if (lastModified > 31536000000L) {
- row.add(Document.COLUMN_LAST_MODIFIED, lastModified);
+ final int sizeIndex = ArrayUtils.indexOf(columns, Document.COLUMN_SIZE);
+ if (sizeIndex != -1) {
+ row.add(sizeIndex, file.length());
}
// Return the row builder just in case any subclass want to add more stuff to it.
diff --git a/core/java/com/android/internal/os/RoSystemProperties.java b/core/java/com/android/internal/os/RoSystemProperties.java
index b0855f4..8182d60 100644
--- a/core/java/com/android/internal/os/RoSystemProperties.java
+++ b/core/java/com/android/internal/os/RoSystemProperties.java
@@ -60,7 +60,7 @@
public static final boolean FW_SYSTEM_USER_SPLIT =
SystemProperties.getBoolean("ro.fw.system_user_split", false);
public static final boolean MULTIUSER_HEADLESS_SYSTEM_USER =
- SystemProperties.getBoolean("ro.fw.multiuser.headless_system_user", false);
+ SystemProperties.getBoolean("ro.fw.mu.headless_system_user", false);
// ------ ro.crypto.* -------- //
public static final CryptoProperties.state_values CRYPTO_STATE =
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index cfc32cf..7e501d2 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -50,9 +50,11 @@
* @param mask which flags to change
* @param fullscreenBounds the current bounds of the fullscreen stack, in screen coordinates
* @param dockedBounds the current bounds of the docked stack, in screen coordinates
+ * @param navbarColorManagedByIme {@code true} if navigation bar color is managed by IME.
*/
void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis, int dockedStackVis,
- int mask, in Rect fullscreenBounds, in Rect dockedBounds);
+ int mask, in Rect fullscreenBounds, in Rect dockedBounds,
+ boolean navbarColorManagedByIme);
void topAppWindowChanged(int displayId, boolean menuVisible);
void setImeWindowStatus(int displayId, in IBinder token, int vis, int backDisposition,
diff --git a/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java b/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java
index ff94264..6b0f8b2 100644
--- a/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java
+++ b/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java
@@ -39,12 +39,13 @@
public final IBinder mImeToken;
public final Rect mFullscreenStackBounds;
public final Rect mDockedStackBounds;
+ public final boolean mNavbarColorManagedByIme;
public RegisterStatusBarResult(ArrayMap<String, StatusBarIcon> icons, int disabledFlags1,
int systemUiVisibility, boolean menuVisible, int imeWindowVis, int imeBackDisposition,
boolean showImeSwitcher, int disabledFlags2, int fullscreenStackSysUiVisibility,
int dockedStackSysUiVisibility, IBinder imeToken, Rect fullscreenStackBounds,
- Rect dockedStackBounds) {
+ Rect dockedStackBounds, boolean navbarColorManagedByIme) {
mIcons = new ArrayMap<>(icons);
mDisabledFlags1 = disabledFlags1;
mSystemUiVisibility = systemUiVisibility;
@@ -58,6 +59,7 @@
mImeToken = imeToken;
mFullscreenStackBounds = fullscreenStackBounds;
mDockedStackBounds = dockedStackBounds;
+ mNavbarColorManagedByIme = navbarColorManagedByIme;
}
@Override
@@ -80,6 +82,7 @@
dest.writeStrongBinder(mImeToken);
dest.writeTypedObject(mFullscreenStackBounds, flags);
dest.writeTypedObject(mDockedStackBounds, flags);
+ dest.writeBoolean(mNavbarColorManagedByIme);
}
/**
@@ -103,11 +106,12 @@
final IBinder imeToken = source.readStrongBinder();
final Rect fullscreenStackBounds = source.readTypedObject(Rect.CREATOR);
final Rect dockedStackBounds = source.readTypedObject(Rect.CREATOR);
+ final boolean navbarColorManagedByIme = source.readBoolean();
return new RegisterStatusBarResult(icons, disabledFlags1, systemUiVisibility,
menuVisible, imeWindowVis, imeBackDisposition, showImeSwitcher,
disabledFlags2, fullscreenStackSysUiVisibility,
dockedStackSysUiVisibility, imeToken, fullscreenStackBounds,
- dockedStackBounds);
+ dockedStackBounds, navbarColorManagedByIme);
}
@Override
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index 6b0d85e..3adb36f 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -104,6 +104,7 @@
private OnDismissedListener mOnDismissedListener;
private RunOnDismissedListener mRunOnDismissedListener;
+ private OnCollapsedChangedListener mOnCollapsedChangedListener;
private boolean mDismissLocked;
@@ -267,6 +268,10 @@
return mOnDismissedListener != null && !mDismissLocked;
}
+ public void setOnCollapsedChangedListener(OnCollapsedChangedListener listener) {
+ mOnCollapsedChangedListener = listener;
+ }
+
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
final int action = ev.getActionMasked();
@@ -548,6 +553,10 @@
if (mScrollIndicatorDrawable != null) {
setWillNotDraw(!isCollapsed);
}
+
+ if (mOnCollapsedChangedListener != null) {
+ mOnCollapsedChangedListener.onCollapsedChanged(isCollapsed);
+ }
}
void dispatchOnDismissed() {
@@ -1078,8 +1087,25 @@
};
}
+ /**
+ * Listener for sheet dismissed events.
+ */
public interface OnDismissedListener {
- public void onDismissed();
+ /**
+ * Callback when the sheet is dismissed by the user.
+ */
+ void onDismissed();
+ }
+
+ /**
+ * Listener for sheet collapsed / expanded events.
+ */
+ public interface OnCollapsedChangedListener {
+ /**
+ * Callback when the sheet is either fully expanded or collapsed.
+ * @param isCollapsed true when collapsed, false when expanded.
+ */
+ void onCollapsedChanged(boolean isCollapsed);
}
private class RunOnDismissedListener implements Runnable {
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index c0b31e4..ecc9d64 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -387,9 +387,13 @@
Rect source, dst;
if (sourceObj != NULL) {
source = rectFromObj(env, sourceObj);
+ } else {
+ source.makeInvalid();
}
if (dstObj != NULL) {
dst = rectFromObj(env, dstObj);
+ } else {
+ dst.makeInvalid();
}
transaction->setGeometry(ctrl, source, dst, orientation);
}
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 1ff7418..9cffb2b 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -2354,4 +2354,11 @@
// OPEN: Settings > Pick preferred SIM dialog
DIALOG_PREFERRED_SIM_PICKER = 1709;
+
+ // OPEN: Settings > Network & internet > Mobile network > Delete sim
+ DIALOG_DELETE_SIM_CONFIRMATION = 1713;
+
+ // OPEN: Settings > Network & internet > Mobile network > Delete sim > (answer yes to
+ // confirmation)
+ DIALOG_DELETE_SIM_PROGRESS = 1714;
}
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index b47097d..8f16b41 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -501,7 +501,10 @@
}
optional IntentFirewall intent_firewall = 65;
- optional SettingProto job_scheduler_constants = 66;
+ optional SettingProto job_scheduler_constants = 66 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto job_scheduler_quota_controller_constants = 149 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto job_scheduler_time_controller_constants = 150 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
optional SettingProto keep_profile_in_background = 67 [ (android.privacy).dest = DEST_AUTOMATIC ];
message LangId {
@@ -1049,5 +1052,5 @@
// Please insert fields in alphabetical order and group them into messages
// if possible (to avoid reaching the method limit).
- // Next tag = 149;
+ // Next tag = 151;
}
diff --git a/core/proto/android/stats/devicepolicy/device_policy_enums.proto b/core/proto/android/stats/devicepolicy/device_policy_enums.proto
index 0db7424..0821d14 100644
--- a/core/proto/android/stats/devicepolicy/device_policy_enums.proto
+++ b/core/proto/android/stats/devicepolicy/device_policy_enums.proto
@@ -149,4 +149,6 @@
PROVISIONING_PREPARE_STARTED = 122;
PROVISIONING_PREPARE_COMPLETED = 123;
PROVISIONING_FLOW_TYPE = 124;
+ CROSS_PROFILE_APPS_GET_TARGET_USER_PROFILES = 125;
+ CROSS_PROFILE_APPS_START_ACTIVITY_AS_USER = 126;
}
diff --git a/core/proto/android/stats/mediametrics/mediametrics.proto b/core/proto/android/stats/mediametrics/mediametrics.proto
new file mode 100644
index 0000000..34ed90a
--- /dev/null
+++ b/core/proto/android/stats/mediametrics/mediametrics.proto
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+
+package android.stats.mediametrics;
+
+/**
+ * Track how we arbitrate between microphone/input requests.
+ * Logged from
+ * frameworks/av/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+ * frameworks/av/services/mediaanalytics/statsd_audiopolicy.cpp
+ * Next Tag: 10
+ */
+message AudioPolicyData {
+ optional int32 status = 1;
+ optional string request_source = 2;
+ optional string request_package = 3;
+ optional int32 request_session = 4;
+ optional string request_device = 5;
+ optional string active_source = 6;
+ optional string active_package = 7;
+ optional int32 active_session = 8;
+ optional string active_device = 9;
+}
+
+/**
+ * Track properties of audio recording
+ * Logged from
+ * frameworks/av/media/libaudioclient/AudioRecord.cpp
+ * frameworks/av/services/mediaanalytics/statsd_audiorecord.cpp
+ * Next Tag: 16
+ */
+message AudioRecordData {
+ optional string encoding = 1;
+ optional string source = 2;
+ optional int32 latency = 3;
+ optional int32 samplerate = 4;
+ optional int32 channels = 5;
+ optional int64 created_millis = 6;
+ optional int64 duration_millis = 7;
+ optional int32 count = 8;
+ optional int32 error_code = 9;
+ optional string error_function = 10;
+ optional int32 port_id = 11;
+ optional int32 frame_count = 12;
+ optional string attributes = 13;
+ optional int64 channel_mask = 14;
+ optional int64 start_count = 15;
+
+}
+
+/**
+ * Track audio thread performance data
+ * Logged from
+ * frameworks/av/media/libnblog/ReportPerformance.cpp
+ * frameworks/av/services/mediaanalytics/statsd_audiothread.cpp
+ * Next Tag: 28
+ */
+message AudioThreadData {
+ optional string type = 1;
+ optional int32 framecount = 2;
+ optional int32 samplerate = 3;
+ optional string work_millis_hist = 4;
+ optional string latency_millis_hist = 5;
+ optional string warmup_millis_hist = 6;
+ optional int64 underruns = 7;
+ optional int64 overruns = 8;
+ optional int64 active_millis = 9;
+ optional int64 duration_millis = 10;
+
+ optional int32 id = 11;
+ optional int32 port_id = 12;
+ optional int32 sample_rate = 13;
+ optional int64 channel_mask = 14;
+ optional string encoding = 15;
+ optional int32 frame_count = 16;
+ optional string output_device = 17;
+ optional string input_device = 18;
+ optional double io_jitter_mean_millis = 19;
+ optional double io_jitter_stddev_millis = 20;
+ optional double process_time_mean_millis = 21;
+ optional double process_time_stddev_millis = 22;
+ optional double timestamp_jitter_mean_millis = 23;
+ optional double timestamp_jitter_stddev_millis = 24;
+ optional double latency_mean_millis = 25;
+ optional double latency_stddev_millis = 26;
+
+}
+
+/**
+ * Track audio track playback data
+ * Logged from
+ * frameworks/av/media/libaudioclient/AudioTrack.cpp
+ * frameworks/av/services/mediaanalytics/statsd_audiotrack.cpp
+ * Next Tag: 12
+ */
+message AudioTrackData {
+ optional string stream_type = 1;
+ optional string content_type = 2;
+ optional string track_usage = 3;
+ optional int32 sample_rate = 4;
+ optional int64 channel_mask = 5;
+
+ optional int32 underrun_frames = 6;
+ optional int32 startup_glitch = 7;
+
+ optional int32 port_id = 8;
+ optional string encoding = 9;
+ optional int32 frame_count = 10;
+ optional string attributes = 11;
+
+
+}
+
+/**
+ * Track Media Codec usage
+ * Logged from:
+ * frameworks/av/media/libstagefright/MediaCodec.cpp
+ * frameworks/av/services/mediaanalytics/statsd_codec.cpp
+ * Next Tag: 21
+ */
+message CodecData {
+ optional string codec = 1;
+ optional string mime = 2;
+ optional string mode = 3;
+ optional int32 encoder = 4;
+ optional int32 secure = 5;
+ optional int32 width = 6;
+ optional int32 height = 7;
+ optional int32 rotation = 8;
+ optional int32 crypto = 9;
+ optional int32 profile = 10;
+ optional int32 level = 11;
+ optional int32 max_width = 12;
+ optional int32 max_height = 13;
+ optional int32 error_code = 14;
+ optional string error_state = 15;
+ optional int64 latency_max = 16;
+ optional int64 latency_min = 17;
+ optional int64 latency_avg = 18;
+ optional int64 latency_count = 19;
+ optional int64 latency_unknown = 20;
+}
+
+/**
+ * Track Media Extractor (pulling video/audio streams out of containers) usage
+ * Logged from:
+ * frameworks/av/media/libstagefright/RemoteMediaExtractor.cpp
+ * frameworks/av/services/mediaanalytics/statsd_extractor.cpp
+ * Next Tag: 4
+ */
+message ExtractorData {
+ optional string format = 1;
+ optional string mime = 2;
+ optional int32 tracks = 3;
+}
+
+/**
+ * Track Media Player usage
+ * this handles both nuplayer and nuplayer2
+ * Logged from:
+ * frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+ * frameworks/av/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
+ * frameworks/av/services/mediaanalytics/statsd_nuplayer.cpp
+ * Next Tag: 21
+ */
+message NuPlayerData {
+ optional string whichPlayer = 1;
+
+ optional string video_mime = 2;
+ optional string video_codec = 3;
+ optional int32 width = 4;
+ optional int32 height = 5;
+ optional int64 frames = 6;
+ optional int64 frames_dropped = 7;
+ optional double framerate = 8;
+ optional string audio_mime = 9;
+ optional string audio_codec = 10;
+ optional int64 duration_millis = 11;
+ optional int64 playing_millis = 12;
+ optional int32 error = 13;
+ optional int32 error_code = 14;
+ optional string error_state = 15;
+ optional string data_source_type = 16;
+ optional int64 rebuffering_millis = 17;
+ optional int32 rebuffers = 18;
+ optional int32 rebuffer_at_exit = 19;
+ optional int64 frames_dropped_startup = 20;
+}
+
+/**
+ * Track information about recordings (e.g. camcorder)
+ * Logged from
+ * frameworks/av/media/libmediaplayerservice/StagefrightRecorder.cpp
+ * frameworks/av/services/mediaanalytics/if_statsd.cpp
+ * Next Tag: 22
+ */
+message RecorderData {
+ optional string audio_mime = 1;
+ optional string video_mime = 2;
+ optional int32 video_profile = 3;
+ optional int32 video_level = 4;
+ optional int32 width = 5;
+ optional int32 height = 6;
+ optional int32 rotation = 7;
+ optional int32 framerate = 8;
+ optional int32 capture_fps = 9;
+ optional double capture_fps_enable = 10;
+ optional int64 duration_millis = 11;
+ optional int64 paused_millis = 12;
+ optional int32 paused_count = 13;
+ optional int32 audio_bitrate = 14;
+ optional int32 audio_channels = 15;
+ optional int32 audio_samplerate = 16;
+ optional int32 movie_timescale = 17;
+ optional int32 audio_timescale = 18;
+ optional int32 video_timescale = 19;
+ optional int32 video_bitrate = 20;
+ optional int32 iframe_interval = 21;
+}
diff --git a/core/res/res/layout/chooser_az_label_row.xml b/core/res/res/layout/chooser_az_label_row.xml
new file mode 100644
index 0000000..1b733fc
--- /dev/null
+++ b/core/res/res/layout/chooser_az_label_row.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<!-- Separator applied as background -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:text="@string/chooser_all_apps_button_label"
+ android:contentDescription="@string/chooser_all_apps_button_label"
+ android:background="@drawable/chooser_row_layer_list"
+ android:textAppearance="?attr/textAppearanceSmall"
+ android:textColor="?attr/textColorSecondary"
+ android:textSize="14sp"
+ android:singleLine="true"
+ android:paddingTop="16dp"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"/>
+
diff --git a/core/res/res/layout/chooser_grid.xml b/core/res/res/layout/chooser_grid.xml
index 8727f4c..17b5f50 100644
--- a/core/res/res/layout/chooser_grid.xml
+++ b/core/res/res/layout/chooser_grid.xml
@@ -37,8 +37,8 @@
android:layout_width="24dp"
android:layout_height="4dp"
android:src="@drawable/ic_drag_handle"
- android:clickable="true"
android:layout_marginTop="@dimen/chooser_edge_margin_thin"
+ android:layout_marginBottom="@dimen/chooser_edge_margin_thin"
android:tint="@color/lighter_gray"
android:layout_centerHorizontal="true"
android:layout_alignParentTop="true" />
@@ -46,11 +46,8 @@
<TextView android:id="@+id/title"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
- android:textAppearance="?attr/textAppearanceMedium"
- android:textSize="20sp"
- android:textColor="?attr/textColorPrimary"
+ android:textAppearance="@style/TextAppearance.DeviceDefault.WindowTitle"
android:gravity="center"
- android:paddingTop="@dimen/chooser_edge_margin_thin"
android:paddingBottom="@dimen/chooser_view_spacing"
android:paddingLeft="24dp"
android:paddingRight="24dp"
diff --git a/core/res/res/layout/chooser_grid_preview_text.xml b/core/res/res/layout/chooser_grid_preview_text.xml
index f3ca0af..e889e85 100644
--- a/core/res/res/layout/chooser_grid_preview_text.xml
+++ b/core/res/res/layout/chooser_grid_preview_text.xml
@@ -44,6 +44,7 @@
android:layout_toStartOf="@id/copy_button"
android:layout_centerVertical="true"
android:ellipsize="end"
+ android:fontFamily="@android:string/config_headlineFontFamily"
android:textColor="?android:attr/textColorPrimary"
android:maxLines="2"/>
@@ -112,8 +113,8 @@
android:layout_gravity="center_vertical"
android:ellipsize="end"
android:maxLines="2"
- android:textSize="20sp"
- android:textColor="?android:attr/textColorPrimary"/>
+ android:textAppearance="@style/TextAppearance.DeviceDefault.WindowTitle"
+ android:fontFamily="@android:string/config_headlineFontFamily"/>
</LinearLayout>
</LinearLayout>
diff --git a/core/res/res/layout/chooser_profile_row.xml b/core/res/res/layout/chooser_profile_row.xml
index 1a24a07..fe4f949 100644
--- a/core/res/res/layout/chooser_profile_row.xml
+++ b/core/res/res/layout/chooser_profile_row.xml
@@ -20,7 +20,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center">
- <TextView
+ <Button
android:id="@+id/profile_button"
android:layout_width="wrap_content"
android:layout_height="48dp"
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index ad3203e..04ccb74 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3863,10 +3863,6 @@
{@see android.view.Display#FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS} -->
<string name="config_secondaryHomeComponent" translatable="false">com.android.launcher3/com.android.launcher3.SecondaryDisplayLauncher</string>
- <!-- Force secondary home launcher specified in config_secondaryHomeComponent always. If this is
- not set, secondary home launcher can be replaced by user. -->
- <bool name ="config_useSystemProvidedLauncherForSecondary">false</bool>
-
<!-- If device supports corner radius on windows.
This should be turned off on low-end devices to improve animation performance. -->
<bool name="config_supportsRoundedCornersOnWindows">true</bool>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index ef834aa..75fd3a0 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5373,4 +5373,7 @@
<!-- ChooserActivity - No direct share targets are available. [CHAR LIMIT=NONE] -->
<string name="chooser_no_direct_share_targets">Direct share not available</string>
+ <!-- ChooserActivity - Alphabetically sorted apps list label. [CHAR LIMIT=NONE] -->
+ <string name="chooser_all_apps_button_label">Apps list</string>
+
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 085ce56..fbe340e 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3678,7 +3678,6 @@
<!-- For Secondary Launcher -->
<java-symbol type="string" name="config_secondaryHomeComponent" />
- <java-symbol type="bool" name="config_useSystemProvidedLauncherForSecondary" />
<java-symbol type="string" name="battery_saver_notification_channel_name" />
<java-symbol type="string" name="battery_saver_sticky_disabled_notification_title" />
@@ -3772,4 +3771,6 @@
<java-symbol type="color" name="chooser_gradient_highlight" />
<java-symbol type="drawable" name="chooser_direct_share_label_placeholder" />
<java-symbol type="dimen" name="chooser_direct_share_label_placeholder_max_width" />
+ <java-symbol type="layout" name="chooser_az_label_row" />
+ <java-symbol type="string" name="chooser_all_apps_button_label" />
</resources>
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index f4d3c81..61fb811 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -294,6 +294,8 @@
Settings.Global.INTENT_FIREWALL_UPDATE_CONTENT_URL,
Settings.Global.INTENT_FIREWALL_UPDATE_METADATA_URL,
Settings.Global.JOB_SCHEDULER_CONSTANTS,
+ Settings.Global.JOB_SCHEDULER_QUOTA_CONTROLLER_CONSTANTS,
+ Settings.Global.JOB_SCHEDULER_TIME_CONTROLLER_CONSTANTS,
Settings.Global.KEEP_PROFILE_IN_BACKGROUND,
Settings.Global.KERNEL_CPU_THREAD_READER,
Settings.Global.LANG_ID_UPDATE_CONTENT_URL,
diff --git a/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java b/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java
index 3cb1e18..b93c3a7 100644
--- a/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java
+++ b/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java
@@ -57,7 +57,8 @@
0x80 /* dockedStackSysUiVisibility */,
new Binder() /* imeToken */,
new Rect(0x100, 0x200, 0x400, 0x800) /* fullscreenStackBounds */,
- new Rect(0x1000, 0x2000, 0x4000, 0x8000) /* dockedStackBounds */);
+ new Rect(0x1000, 0x2000, 0x4000, 0x8000) /* dockedStackBounds */,
+ true /* navbarColorManagedByIme */);
final RegisterStatusBarResult copy = clone(original);
@@ -80,6 +81,7 @@
assertThat(copy.mImeToken).isSameAs(original.mImeToken);
assertThat(copy.mFullscreenStackBounds).isEqualTo(original.mFullscreenStackBounds);
assertThat(copy.mDockedStackBounds).isEqualTo(original.mDockedStackBounds);
+ assertThat(copy.mNavbarColorManagedByIme).isEqualTo(original.mNavbarColorManagedByIme);
}
private RegisterStatusBarResult clone(RegisterStatusBarResult original) {
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 485add9..98ef00e 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -235,6 +235,7 @@
<permission name="android.permission.CALL_PRIVILEGED"/>
<permission name="android.permission.INTERACT_ACROSS_USERS"/>
<permission name="android.permission.MANAGE_USERS"/>
+ <permission name="android.permission.MANAGE_ROLE_HOLDERS"/>
<permission name="android.permission.MODIFY_AUDIO_ROUTING" />
<permission name="android.permission.MODIFY_PHONE_STATE"/>
<permission name="android.permission.STOP_APP_SWITCHES"/>
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index a56e7f5..f304f7c 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -24,6 +24,7 @@
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
import android.os.Build;
+import android.os.SystemProperties;
import android.util.Log;
import android.util.Pair;
import android.util.Range;
@@ -1105,7 +1106,11 @@
mBitrateRange = Range.create(0, Integer.MAX_VALUE);
mMaxInputChannelCount = MAX_INPUT_CHANNEL_COUNT;
// mBitrateRange = Range.create(1, 320000);
- mSampleRateRanges = new Range[] { Range.create(8000, 96000) };
+ final int minSampleRate = SystemProperties.
+ getInt("ro.mediacodec.min_sample_rate", 7350);
+ final int maxSampleRate = SystemProperties.
+ getInt("ro.mediacodec.max_sample_rate", 192000);
+ mSampleRateRanges = new Range[] { Range.create(minSampleRate, maxSampleRate) };
mSampleRates = null;
}
@@ -1677,6 +1682,13 @@
return "PerformancePoint(" + info + ")";
}
+ @Override
+ public int hashCode() {
+ // only max frame rate must equal between performance points that equal to one
+ // another
+ return mMaxFrameRate;
+ }
+
/**
* Create a detailed performance point with custom max frame rate and macroblock size.
*
diff --git a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
index 267d9f5..94962f7 100644
--- a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
+++ b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
@@ -609,6 +609,8 @@
return;
}
mAvailableVolumeItems.get(mVolumeGroupId).progress = progress;
+ mAvailableVolumeItems.get(
+ mVolumeGroupId).carVolumeItem.setProgress(progress);
mCarAudioManager.setGroupVolume(mVolumeGroupId, progress, 0);
} catch (CarNotConnectedException e) {
Log.e(TAG, "Car is not connected!", e);
diff --git a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeItem.java b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeItem.java
index e1ea6f6..b83740f 100644
--- a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeItem.java
+++ b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeItem.java
@@ -29,8 +29,6 @@
/** Holds all related data to represent a volume group. */
public class CarVolumeItem {
- private boolean mIsDirty;
-
private Drawable mPrimaryIcon;
private Drawable mSupplementalIcon;
private View.OnClickListener mSupplementalIconOnClickListener;
@@ -40,50 +38,38 @@
private int mMax;
private int mProgress;
private SeekBar.OnSeekBarChangeListener mOnSeekBarChangeListener;
-
- public CarVolumeItem() {
- mIsDirty = true;
- }
-
+
/**
* Called when {@link CarVolumeItem} is bound to its ViewHolder.
*/
void bind(CarVolumeItemViewHolder viewHolder) {
- if (mIsDirty) {
viewHolder.bind(/* carVolumeItem= */ this);
- mIsDirty = false;
- }
}
/** Sets progress of seekbar. */
public void setProgress(int progress) {
mProgress = progress;
- mIsDirty = true;
}
/** Sets max value of seekbar. */
public void setMax(int max) {
mMax = max;
- mIsDirty = true;
}
/** Sets {@link SeekBar.OnSeekBarChangeListener}. */
public void setOnSeekBarChangeListener(SeekBar.OnSeekBarChangeListener listener) {
mOnSeekBarChangeListener = listener;
- mIsDirty = true;
}
/** Sets the primary icon. */
public void setPrimaryIcon(Drawable drawable) {
mPrimaryIcon = drawable;
- mIsDirty = true;
}
/** Sets the supplemental icon and the visibility of the supplemental icon divider. */
public void setSupplementalIcon(Drawable drawable, boolean showSupplementalIconDivider) {
mSupplementalIcon = drawable;
mShowSupplementalIconDivider = showSupplementalIconDivider;
- mIsDirty = true;
}
/**
@@ -103,7 +89,6 @@
/** Sets {@code OnClickListener} for the supplemental icon. */
public void setSupplementalIconListener(View.OnClickListener listener) {
mSupplementalIconOnClickListener = listener;
- mIsDirty = true;
}
/** Defines the view holder which shows the information held by {@link CarVolumeItem}. */
diff --git a/packages/ExtServices/src/android/ext/services/notification/AssistantSettings.java b/packages/ExtServices/src/android/ext/services/notification/AssistantSettings.java
index 46288bb..296db46 100644
--- a/packages/ExtServices/src/android/ext/services/notification/AssistantSettings.java
+++ b/packages/ExtServices/src/android/ext/services/notification/AssistantSettings.java
@@ -102,10 +102,10 @@
}
private void registerDeviceConfigs() {
- DeviceConfig.addOnPropertyChangedListener(
+ DeviceConfig.addOnPropertiesChangedListener(
DeviceConfig.NAMESPACE_SYSTEMUI,
this::postToHandler,
- this::onDeviceConfigPropertyChanged);
+ (properties) -> onDeviceConfigPropertiesChanged(properties.getNamespace()));
// Update the fields in this class from the current state of the device config.
updateFromDeviceConfigFlags();
@@ -116,10 +116,10 @@
}
@VisibleForTesting
- void onDeviceConfigPropertyChanged(String namespace, String name, String value) {
+ void onDeviceConfigPropertiesChanged(String namespace) {
if (!DeviceConfig.NAMESPACE_SYSTEMUI.equals(namespace)) {
Log.e(LOG_TAG, "Received update from DeviceConfig for unrelated namespace: "
- + namespace + " " + name + "=" + value);
+ + namespace);
return;
}
diff --git a/packages/ExtServices/tests/src/android/ext/services/notification/AssistantSettingsTest.java b/packages/ExtServices/tests/src/android/ext/services/notification/AssistantSettingsTest.java
index ad52e2b..5c877de 100644
--- a/packages/ExtServices/tests/src/android/ext/services/notification/AssistantSettingsTest.java
+++ b/packages/ExtServices/tests/src/android/ext/services/notification/AssistantSettingsTest.java
@@ -96,10 +96,7 @@
SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES,
"false",
false /* makeDefault */));
- mAssistantSettings.onDeviceConfigPropertyChanged(
- DeviceConfig.NAMESPACE_SYSTEMUI,
- SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES,
- "false");
+ mAssistantSettings.onDeviceConfigPropertiesChanged(DeviceConfig.NAMESPACE_SYSTEMUI);
assertFalse(mAssistantSettings.mGenerateReplies);
}
@@ -111,10 +108,7 @@
SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES,
"true",
false /* makeDefault */));
- mAssistantSettings.onDeviceConfigPropertyChanged(
- DeviceConfig.NAMESPACE_SYSTEMUI,
- SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES,
- "true");
+ mAssistantSettings.onDeviceConfigPropertiesChanged(DeviceConfig.NAMESPACE_SYSTEMUI);
assertTrue(mAssistantSettings.mGenerateReplies);
}
@@ -126,10 +120,7 @@
SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES,
"false",
false /* makeDefault */));
- mAssistantSettings.onDeviceConfigPropertyChanged(
- DeviceConfig.NAMESPACE_SYSTEMUI,
- SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES,
- "false");
+ mAssistantSettings.onDeviceConfigPropertiesChanged(DeviceConfig.NAMESPACE_SYSTEMUI);
assertFalse(mAssistantSettings.mGenerateReplies);
@@ -138,10 +129,7 @@
SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES,
null,
false /* makeDefault */));
- mAssistantSettings.onDeviceConfigPropertyChanged(
- DeviceConfig.NAMESPACE_SYSTEMUI,
- SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES,
- null);
+ mAssistantSettings.onDeviceConfigPropertiesChanged(DeviceConfig.NAMESPACE_SYSTEMUI);
// Go back to the default value.
assertTrue(mAssistantSettings.mGenerateReplies);
@@ -154,10 +142,7 @@
SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS,
"false",
false /* makeDefault */));
- mAssistantSettings.onDeviceConfigPropertyChanged(
- DeviceConfig.NAMESPACE_SYSTEMUI,
- SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS,
- "false");
+ mAssistantSettings.onDeviceConfigPropertiesChanged(DeviceConfig.NAMESPACE_SYSTEMUI);
assertFalse(mAssistantSettings.mGenerateActions);
}
@@ -169,10 +154,7 @@
SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS,
"true",
false /* makeDefault */));
- mAssistantSettings.onDeviceConfigPropertyChanged(
- DeviceConfig.NAMESPACE_SYSTEMUI,
- SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS,
- "true");
+ mAssistantSettings.onDeviceConfigPropertiesChanged(DeviceConfig.NAMESPACE_SYSTEMUI);
assertTrue(mAssistantSettings.mGenerateActions);
}
@@ -184,10 +166,7 @@
SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS,
"false",
false /* makeDefault */));
- mAssistantSettings.onDeviceConfigPropertyChanged(
- DeviceConfig.NAMESPACE_SYSTEMUI,
- SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS,
- "false");
+ mAssistantSettings.onDeviceConfigPropertiesChanged(DeviceConfig.NAMESPACE_SYSTEMUI);
assertFalse(mAssistantSettings.mGenerateActions);
@@ -196,10 +175,7 @@
SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS,
null,
false /* makeDefault */));
- mAssistantSettings.onDeviceConfigPropertyChanged(
- DeviceConfig.NAMESPACE_SYSTEMUI,
- SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS,
- null);
+ mAssistantSettings.onDeviceConfigPropertiesChanged(DeviceConfig.NAMESPACE_SYSTEMUI);
// Go back to the default value.
assertTrue(mAssistantSettings.mGenerateActions);
@@ -212,10 +188,7 @@
SystemUiDeviceConfigFlags.NAS_MAX_MESSAGES_TO_EXTRACT,
"10",
false /* makeDefault */));
- mAssistantSettings.onDeviceConfigPropertyChanged(
- DeviceConfig.NAMESPACE_SYSTEMUI,
- SystemUiDeviceConfigFlags.NAS_MAX_MESSAGES_TO_EXTRACT,
- "10");
+ mAssistantSettings.onDeviceConfigPropertiesChanged(DeviceConfig.NAMESPACE_SYSTEMUI);
assertEquals(10, mAssistantSettings.mMaxMessagesToExtract);
}
@@ -227,20 +200,14 @@
SystemUiDeviceConfigFlags.NAS_MAX_SUGGESTIONS,
"5",
false /* makeDefault */));
- mAssistantSettings.onDeviceConfigPropertyChanged(
- DeviceConfig.NAMESPACE_SYSTEMUI,
- SystemUiDeviceConfigFlags.NAS_MAX_SUGGESTIONS,
- "5");
+ mAssistantSettings.onDeviceConfigPropertiesChanged(DeviceConfig.NAMESPACE_SYSTEMUI);
assertEquals(5, mAssistantSettings.mMaxSuggestions);
}
@Test
public void testMaxSuggestionsEmpty() {
- mAssistantSettings.onDeviceConfigPropertyChanged(
- DeviceConfig.NAMESPACE_SYSTEMUI,
- SystemUiDeviceConfigFlags.NAS_MAX_SUGGESTIONS,
- "");
+ mAssistantSettings.onDeviceConfigPropertiesChanged(DeviceConfig.NAMESPACE_SYSTEMUI);
assertEquals(DEFAULT_MAX_SUGGESTIONS, mAssistantSettings.mMaxSuggestions);
}
diff --git a/packages/NetworkPermissionConfig/AndroidManifest.xml b/packages/NetworkPermissionConfig/AndroidManifest.xml
index 34f987c..496fa4d 100644
--- a/packages/NetworkPermissionConfig/AndroidManifest.xml
+++ b/packages/NetworkPermissionConfig/AndroidManifest.xml
@@ -19,7 +19,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.networkstack.permissionconfig"
android:sharedUserId="android.uid.networkstack"
- android:versionCode="11"
+ android:versionCode="210000000"
android:versionName="Q-initial">
<uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28" />
<!--
diff --git a/packages/NetworkStack/Android.bp b/packages/NetworkStack/Android.bp
index e0bb862..62de2ba 100644
--- a/packages/NetworkStack/Android.bp
+++ b/packages/NetworkStack/Android.bp
@@ -56,15 +56,24 @@
srcs: [
"jni/network_stack_utils_jni.cpp"
],
-
+ sdk_version: "current",
shared_libs: [
"liblog",
- "libcutils",
- "libnativehelper",
+ "libnativehelper_compat_libc++",
],
- static_libs: [
- "libpcap",
- ],
+
+ // We cannot use plain "libc++" here to link libc++ dynamically because it results in:
+ // java.lang.UnsatisfiedLinkError: dlopen failed: library "libc++_shared.so" not found
+ // even if "libc++" is added into jni_libs below. Adding "libc++_shared" into jni_libs doesn't
+ // build because soong complains of:
+ // module NetworkStack missing dependencies: libc++_shared
+ //
+ // So, link libc++ statically. This means that we also need to ensure that all the C++ libraries
+ // we depend on do not dynamically link libc++. This is currently the case, because liblog is
+ // C-only and libnativehelper_compat_libc also uses stl: "c++_static".
+ //
+ // TODO: find a better solution for this in R.
+ stl: "c++_static",
cflags: [
"-Wall",
"-Werror",
@@ -79,7 +88,10 @@
static_libs: [
"NetworkStackBase",
],
- jni_libs: ["libnetworkstackutilsjni"],
+ jni_libs: [
+ "libnativehelper_compat_libc++",
+ "libnetworkstackutilsjni",
+ ],
// Resources already included in NetworkStackBase
resource_dirs: [],
jarjar_rules: "jarjar-rules-shared.txt",
diff --git a/packages/NetworkStack/jni/network_stack_utils_jni.cpp b/packages/NetworkStack/jni/network_stack_utils_jni.cpp
index 5544eaa..f2ba575 100644
--- a/packages/NetworkStack/jni/network_stack_utils_jni.cpp
+++ b/packages/NetworkStack/jni/network_stack_utils_jni.cpp
@@ -31,7 +31,7 @@
#include <string>
#include <nativehelper/JNIHelp.h>
-#include <utils/Log.h>
+#include <android/log.h>
namespace android {
constexpr const char NETWORKSTACKUTILS_PKG_NAME[] = "android/net/util/NetworkStackUtils";
@@ -249,7 +249,7 @@
extern "C" jint JNI_OnLoad(JavaVM* vm, void*) {
JNIEnv *env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
- ALOGE("ERROR: GetEnv failed");
+ __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "ERROR: GetEnv failed");
return JNI_ERR;
}
@@ -261,4 +261,4 @@
return JNI_VERSION_1_6;
}
-}; // namespace android
\ No newline at end of file
+}; // namespace android
diff --git a/packages/NetworkStack/src/android/net/apf/ApfFilter.java b/packages/NetworkStack/src/android/net/apf/ApfFilter.java
index 663e2f1..359c859 100644
--- a/packages/NetworkStack/src/android/net/apf/ApfFilter.java
+++ b/packages/NetworkStack/src/android/net/apf/ApfFilter.java
@@ -39,6 +39,7 @@
import android.content.IntentFilter;
import android.net.LinkAddress;
import android.net.LinkProperties;
+import android.net.NattKeepalivePacketDataParcelable;
import android.net.TcpKeepalivePacketDataParcelable;
import android.net.apf.ApfGenerator.IllegalInstructionException;
import android.net.apf.ApfGenerator.Register;
@@ -1691,13 +1692,13 @@
}
/**
- * Add keepalive ack packet filter.
+ * Add TCP keepalive ack packet filter.
* This will add a filter to drop acks to the keepalive packet passed as an argument.
*
* @param slot The index used to access the filter.
* @param sentKeepalivePacket The attributes of the sent keepalive packet.
*/
- public synchronized void addKeepalivePacketFilter(final int slot,
+ public synchronized void addTcpKeepalivePacketFilter(final int slot,
final TcpKeepalivePacketDataParcelable sentKeepalivePacket) {
log("Adding keepalive ack(" + slot + ")");
if (null != mKeepaliveAcks.get(slot)) {
@@ -1711,6 +1712,18 @@
}
/**
+ * Add NATT keepalive packet filter.
+ * This will add a filter to drop NATT keepalive packet which is passed as an argument.
+ *
+ * @param slot The index used to access the filter.
+ * @param sentKeepalivePacket The attributes of the sent keepalive packet.
+ */
+ public synchronized void addNattKeepalivePacketFilter(final int slot,
+ final NattKeepalivePacketDataParcelable sentKeepalivePacket) {
+ Log.e(TAG, "APF add NATT keepalive filter is not implemented");
+ }
+
+ /**
* Remove keepalive packet filter.
*
* @param slot The index used to access the filter.
diff --git a/packages/NetworkStack/src/android/net/ip/IpClient.java b/packages/NetworkStack/src/android/net/ip/IpClient.java
index 96e09fa..dc74c04 100644
--- a/packages/NetworkStack/src/android/net/ip/IpClient.java
+++ b/packages/NetworkStack/src/android/net/ip/IpClient.java
@@ -29,6 +29,7 @@
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
+import android.net.NattKeepalivePacketDataParcelable;
import android.net.NetworkStackIpMemoryStore;
import android.net.ProvisioningConfigurationParcelable;
import android.net.ProxyInfo;
@@ -371,6 +372,10 @@
private boolean mMulticastFiltering;
private long mStartTimeMillis;
+ /* This must match the definition in KeepaliveTracker.KeepaliveInfo */
+ private static final int TYPE_NATT = 1;
+ private static final int TYPE_TCP = 2;
+
/**
* Reading the snapshot is an asynchronous operation initiated by invoking
* Callback.startReadPacketFilter() and completed when the WiFi Service responds with an
@@ -553,6 +558,11 @@
IpClient.this.addKeepalivePacketFilter(slot, pkt);
}
@Override
+ public void addNattKeepalivePacketFilter(int slot, NattKeepalivePacketDataParcelable pkt) {
+ checkNetworkStackCallingPermission();
+ IpClient.this.addNattKeepalivePacketFilter(slot, pkt);
+ }
+ @Override
public void removeKeepalivePacketFilter(int slot) {
checkNetworkStackCallingPermission();
IpClient.this.removeKeepalivePacketFilter(slot);
@@ -691,11 +701,20 @@
}
/**
- * Called by WifiStateMachine to add keepalive packet filter before setting up
+ * Called by WifiStateMachine to add TCP keepalive packet filter before setting up
* keepalive offload.
*/
public void addKeepalivePacketFilter(int slot, @NonNull TcpKeepalivePacketDataParcelable pkt) {
- sendMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF, slot, 0 /* Unused */, pkt);
+ sendMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF, slot, TYPE_TCP, pkt);
+ }
+
+ /**
+ * Called by WifiStateMachine to add NATT keepalive packet filter before setting up
+ * keepalive offload.
+ */
+ public void addNattKeepalivePacketFilter(int slot,
+ @NonNull NattKeepalivePacketDataParcelable pkt) {
+ sendMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF, slot, TYPE_NATT, pkt);
}
/**
@@ -1607,9 +1626,16 @@
case CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF: {
final int slot = msg.arg1;
+ final int type = msg.arg2;
+
if (mApfFilter != null) {
- mApfFilter.addKeepalivePacketFilter(slot,
- (TcpKeepalivePacketDataParcelable) msg.obj);
+ if (type == TYPE_NATT) {
+ mApfFilter.addNattKeepalivePacketFilter(slot,
+ (NattKeepalivePacketDataParcelable) msg.obj);
+ } else {
+ mApfFilter.addTcpKeepalivePacketFilter(slot,
+ (TcpKeepalivePacketDataParcelable) msg.obj);
+ }
}
break;
}
diff --git a/packages/NetworkStack/tests/Android.bp b/packages/NetworkStack/tests/Android.bp
index fe3c1e8..039f6bf 100644
--- a/packages/NetworkStack/tests/Android.bp
+++ b/packages/NetworkStack/tests/Android.bp
@@ -56,6 +56,7 @@
"liblog",
"liblzma",
"libnativehelper",
+ "libnativehelper_compat_libc++",
"libnetworkstacktestsjni",
"libnetworkstackutilsjni",
"libpackagelistparser",
@@ -99,5 +100,4 @@
"libapf",
"libpcap",
],
-
}
diff --git a/packages/NetworkStack/tests/src/android/net/apf/ApfTest.java b/packages/NetworkStack/tests/src/android/net/apf/ApfTest.java
index a0e508f..93ab3be 100644
--- a/packages/NetworkStack/tests/src/android/net/apf/ApfTest.java
+++ b/packages/NetworkStack/tests/src/android/net/apf/ApfTest.java
@@ -1553,7 +1553,7 @@
parcel.seq = seqNum;
parcel.ack = ackNum;
- apfFilter.addKeepalivePacketFilter(slot1, parcel);
+ apfFilter.addTcpKeepalivePacketFilter(slot1, parcel);
program = cb.getApfProgram();
// Verify IPv4 keepalive ack packet is dropped
@@ -1592,7 +1592,7 @@
ipv6Parcel.seq = seqNum;
ipv6Parcel.ack = ackNum;
- apfFilter.addKeepalivePacketFilter(slot1, ipv6Parcel);
+ apfFilter.addTcpKeepalivePacketFilter(slot1, ipv6Parcel);
program = cb.getApfProgram();
// Verify IPv6 keepalive ack packet is dropped
@@ -1614,8 +1614,8 @@
apfFilter.removeKeepalivePacketFilter(slot1);
// Verify multiple filters
- apfFilter.addKeepalivePacketFilter(slot1, parcel);
- apfFilter.addKeepalivePacketFilter(slot2, ipv6Parcel);
+ apfFilter.addTcpKeepalivePacketFilter(slot1, parcel);
+ apfFilter.addTcpKeepalivePacketFilter(slot2, ipv6Parcel);
program = cb.getApfProgram();
// Verify IPv4 keepalive ack packet is dropped
diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java
index 0ffd471..05c2f24 100644
--- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java
+++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java
@@ -174,7 +174,7 @@
packageManager.getResourcesForApplication(mActivityPackage);
title = res.getString(mMetaData.getInt(META_DATA_PREFERENCE_TITLE));
} catch (PackageManager.NameNotFoundException | Resources.NotFoundException e) {
- Log.d(TAG, "Couldn't find info", e);
+ Log.w(TAG, "Couldn't find info", e);
}
} else {
title = mMetaData.getString(META_DATA_PREFERENCE_TITLE);
@@ -183,26 +183,16 @@
// Set the preference title to the activity's label if no
// meta-data is found
if (title == null) {
- title = getActivityInfo(context).loadLabel(packageManager);
+ final ActivityInfo activityInfo = getActivityInfo(context);
+ if (activityInfo == null) {
+ return null;
+ }
+ title = activityInfo.loadLabel(packageManager);
}
return title;
}
/**
- * Returns the raw metadata for summary, this is used for comparing 2 summary text without
- * loading the real string.
- */
- public String getSummaryReference() {
- if (mSummaryOverride != null) {
- return mSummaryOverride.toString();
- }
- if (mMetaData != null && mMetaData.containsKey(META_DATA_PREFERENCE_SUMMARY)) {
- return mMetaData.get(META_DATA_PREFERENCE_SUMMARY).toString();
- }
- return null;
- }
-
- /**
* Overrides the summary. This can happen when injected tile wants to provide dynamic summary.
*/
public void overrideSummary(CharSequence summaryOverride) {
@@ -302,7 +292,7 @@
if (iconResId != 0) {
final Icon icon = Icon.createWithResource(activityInfo.packageName, iconResId);
if (isIconTintable(context)) {
- final TypedArray a = context.obtainStyledAttributes(new int[] {
+ final TypedArray a = context.obtainStyledAttributes(new int[]{
android.R.attr.colorControlNormal});
final int tintColor = a.getColor(0, 0);
a.recycle();
@@ -357,6 +347,9 @@
if (infoList != null && !infoList.isEmpty()) {
mActivityInfo = infoList.get(0).activityInfo;
mMetaData = mActivityInfo.metaData;
+ } else {
+ Log.e(TAG, "Cannot find package info for "
+ + intent.getComponent().flattenToString());
}
}
return mActivityInfo;
diff --git a/packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_background.xml b/packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_background.xml
index 6b45a47..c8a80ac 100644
--- a/packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_background.xml
+++ b/packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_background.xml
@@ -14,5 +14,5 @@
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:alpha="0.24" android:color="@android:color/black" />
+ <item android:alpha="0.24" android:color="?android:attr/colorBackground" />
</selector>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_fill.xml b/packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_fill.xml
index 5ef085b..8dcfdbb 100644
--- a/packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_fill.xml
+++ b/packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_fill.xml
@@ -14,5 +14,5 @@
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:alpha="0.47" android:color="@android:color/black" />
+ <item android:alpha="0.47" android:color="?android:attr/colorBackground" />
</selector>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_background.xml b/packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_background.xml
index 81f63a4..34de548 100644
--- a/packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_background.xml
+++ b/packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_background.xml
@@ -14,5 +14,5 @@
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:alpha="0.3" android:color="@android:color/white" />
+ <item android:alpha="0.3" android:color="?android:attr/colorForeground" />
</selector>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_fill.xml b/packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_fill.xml
index 61f4e26..15944c3 100644
--- a/packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_fill.xml
+++ b/packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_fill.xml
@@ -14,5 +14,5 @@
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:color="@android:color/white" />
+ <item android:color="?android:attr/colorForeground" />
</selector>
\ No newline at end of file
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileTest.java
index d0d1e58..5da6205 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileTest.java
@@ -23,6 +23,7 @@
import org.robolectric.RuntimeEnvironment;
import org.robolectric.shadow.api.Shadow;
import org.robolectric.shadows.ShadowPackageManager;
+import org.robolectric.util.ReflectionHelpers;
@RunWith(RobolectricTestRunner.class)
public class TileTest {
@@ -164,4 +165,17 @@
assertThat(tile.mLastUpdateTime).isNotEqualTo(staleTimeStamp);
}
+
+ @Test
+ public void getTitle_noActivity_returnNull() {
+ final ResolveInfo info = new ResolveInfo();
+ info.activityInfo = mActivityInfo;
+ final ShadowPackageManager spm = Shadow.extract(mContext.getPackageManager());
+ spm.removePackage(mActivityInfo.packageName);
+
+ final Tile tile = new Tile(mActivityInfo, "category");
+ ReflectionHelpers.setField(tile, "mActivityInfo", null);
+
+ assertThat(tile.getTitle(RuntimeEnvironment.application)).isNull();
+ }
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index cd4f6cf..c94ee0e 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -797,6 +797,12 @@
Settings.Global.JOB_SCHEDULER_CONSTANTS,
GlobalSettingsProto.JOB_SCHEDULER_CONSTANTS);
dumpSetting(s, p,
+ Settings.Global.JOB_SCHEDULER_QUOTA_CONTROLLER_CONSTANTS,
+ GlobalSettingsProto.JOB_SCHEDULER_QUOTA_CONTROLLER_CONSTANTS);
+ dumpSetting(s, p,
+ Settings.Global.JOB_SCHEDULER_TIME_CONTROLLER_CONSTANTS,
+ GlobalSettingsProto.JOB_SCHEDULER_TIME_CONTROLLER_CONSTANTS);
+ dumpSetting(s, p,
Settings.Global.KEEP_PROFILE_IN_BACKGROUND,
GlobalSettingsProto.KEEP_PROFILE_IN_BACKGROUND);
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
index 66d5d11..25a3fa2 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
@@ -17,6 +17,7 @@
import android.annotation.Nullable;
import android.app.PendingIntent;
import android.content.Intent;
+import android.view.View;
import com.android.systemui.plugins.annotations.ProvidesInterface;
@@ -32,13 +33,20 @@
void startPendingIntentDismissingKeyguard(PendingIntent intent);
/**
- * Similar to {@link #startPendingIntentDismissingKeyguard(PendingIntent, Runnable)}, but allows
+ * Similar to {@link #startPendingIntentDismissingKeyguard(PendingIntent)}, but allows
* you to specify the callback that is executed on the UI thread after the intent is sent.
*/
void startPendingIntentDismissingKeyguard(PendingIntent intent,
Runnable intentSentUiThreadCallback);
/**
+ * Similar to {@link #startPendingIntentDismissingKeyguard(PendingIntent, Runnable)}, but also
+ * specifies an associated view that should be used for the activity launch animation.
+ */
+ void startPendingIntentDismissingKeyguard(PendingIntent intent,
+ Runnable intentSentUiThreadCallback, View associatedView);
+
+ /**
* The intent flag can be specified in startActivity().
*/
void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade, int flags);
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index d8f543f..112dde6 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -53,7 +53,7 @@
<!-- Clock with header -->
<dimen name="widget_small_font_size">22dp</dimen>
<dimen name="widget_vertical_padding">32dp</dimen>
- <dimen name="widget_vertical_padding_clock">30dp</dimen>
+ <dimen name="widget_vertical_padding_clock">12dp</dimen>
<!-- Subtitle paddings -->
<dimen name="widget_horizontal_padding">8dp</dimen>
<dimen name="widget_icon_size">16dp</dimen>
diff --git a/packages/SystemUI/res/drawable/button_border_selected.xml b/packages/SystemUI/res/drawable/button_border_selected.xml
index d9299ec..1e40ade 100644
--- a/packages/SystemUI/res/drawable/button_border_selected.xml
+++ b/packages/SystemUI/res/drawable/button_border_selected.xml
@@ -20,6 +20,6 @@
android:color="@color/notification_guts_selection_bg" />
<stroke
android:width="2dp"
- android:color="?android:attr/colorAccent"/>
+ android:color="@color/GM2_grey_300"/>
<corners android:radius="@dimen/rect_button_radius" />
</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout-land/global_actions_column.xml b/packages/SystemUI/res/layout-land/global_actions_column.xml
new file mode 100644
index 0000000..99a4e13
--- /dev/null
+++ b/packages/SystemUI/res/layout-land/global_actions_column.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<com.android.systemui.globalactions.GlobalActionsColumnLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@id/global_actions_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal"
+ android:clipToPadding="false"
+ android:theme="@style/qs_theme"
+ android:gravity="center_horizontal | top"
+ android:clipChildren="false"
+>
+ <LinearLayout
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:padding="0dp"
+ android:orientation="horizontal"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ >
+ <!-- Grid of action items -->
+ <LinearLayout
+ android:id="@android:id/list"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:layout_marginTop="@dimen/global_actions_grid_side_margin"
+ android:translationZ="@dimen/global_actions_translate"
+ android:paddingLeft="@dimen/global_actions_grid_horizontal_padding"
+ android:paddingRight="@dimen/global_actions_grid_horizontal_padding"
+ android:paddingTop="@dimen/global_actions_grid_vertical_padding"
+ android:paddingBottom="@dimen/global_actions_grid_vertical_padding"
+ android:background="?android:attr/colorBackgroundFloating"
+ />
+ <!-- For separated items-->
+ <LinearLayout
+ android:id="@+id/separated_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/global_actions_grid_side_margin"
+ android:layout_marginTop="@dimen/global_actions_grid_side_margin"
+ android:paddingLeft="@dimen/global_actions_grid_horizontal_padding"
+ android:paddingRight="@dimen/global_actions_grid_horizontal_padding"
+ android:paddingTop="@dimen/global_actions_grid_vertical_padding"
+ android:paddingBottom="@dimen/global_actions_grid_vertical_padding"
+ android:orientation="horizontal"
+ android:background="?android:attr/colorBackgroundFloating"
+ android:translationZ="@dimen/global_actions_translate"
+ />
+ </LinearLayout>
+
+</com.android.systemui.globalactions.GlobalActionsColumnLayout>
diff --git a/packages/SystemUI/res/layout-land/global_actions_column_seascape.xml b/packages/SystemUI/res/layout-land/global_actions_column_seascape.xml
new file mode 100644
index 0000000..0f86131
--- /dev/null
+++ b/packages/SystemUI/res/layout-land/global_actions_column_seascape.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<com.android.systemui.globalactions.GlobalActionsColumnLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@id/global_actions_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal"
+ android:clipToPadding="false"
+ android:theme="@style/qs_theme"
+ android:gravity="center_horizontal | bottom"
+ android:clipChildren="false"
+>
+ <LinearLayout
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:padding="0dp"
+ android:orientation="horizontal"
+ >
+ <!-- Grid of action items -->
+ <com.android.systemui.globalactions.ListGridLayout
+ android:id="@android:id/list"
+ android:layout_gravity="bottom|left"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:layout_marginBottom="@dimen/global_actions_grid_side_margin"
+ android:translationZ="@dimen/global_actions_translate"
+ android:paddingLeft="@dimen/global_actions_grid_horizontal_padding"
+ android:paddingRight="@dimen/global_actions_grid_horizontal_padding"
+ android:paddingTop="@dimen/global_actions_grid_vertical_padding"
+ android:paddingBottom="@dimen/global_actions_grid_vertical_padding"
+ android:background="?android:attr/colorBackgroundFloating"
+ />
+ <!-- For separated items-->
+ <LinearLayout
+ android:id="@+id/separated_button"
+ android:layout_gravity="top|left"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="@dimen/global_actions_grid_side_margin"
+ android:layout_marginBottom="@dimen/global_actions_grid_side_margin"
+ android:paddingLeft="@dimen/global_actions_grid_horizontal_padding"
+ android:paddingRight="@dimen/global_actions_grid_horizontal_padding"
+ android:paddingTop="@dimen/global_actions_grid_vertical_padding"
+ android:paddingBottom="@dimen/global_actions_grid_vertical_padding"
+ android:orientation="horizontal"
+ android:background="?android:attr/colorBackgroundFloating"
+ android:translationZ="@dimen/global_actions_translate"
+ />
+ </LinearLayout>
+
+</com.android.systemui.globalactions.GlobalActionsColumnLayout>
diff --git a/packages/SystemUI/res/layout/contextual.xml b/packages/SystemUI/res/layout/contextual.xml
index 9b6ccae..90a7768 100644
--- a/packages/SystemUI/res/layout/contextual.xml
+++ b/packages/SystemUI/res/layout/contextual.xml
@@ -42,16 +42,10 @@
android:layout_height="match_parent"
android:visibility="invisible"
/>
- <com.android.systemui.statusbar.policy.KeyButtonView
- android:id="@+id/rotate_suggestion"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_weight="0"
- android:scaleType="center"
- android:visibility="invisible"
- android:contentDescription="@string/accessibility_rotate_button"
- android:paddingStart="@dimen/navigation_key_padding"
- android:paddingEnd="@dimen/navigation_key_padding"
+ <include layout="@layout/rotate_suggestion"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="invisible"
/>
<com.android.systemui.statusbar.policy.KeyButtonView
android:id="@+id/accessibility_button"
diff --git a/packages/SystemUI/res/layout/global_actions_column.xml b/packages/SystemUI/res/layout/global_actions_column.xml
new file mode 100644
index 0000000..b58146b
--- /dev/null
+++ b/packages/SystemUI/res/layout/global_actions_column.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<com.android.systemui.globalactions.GlobalActionsColumnLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@id/global_actions_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:clipToPadding="false"
+ android:theme="@style/qs_theme"
+ android:gravity="center_vertical | right"
+ android:clipChildren="false"
+>
+ <LinearLayout
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:gravity="top | right"
+ android:orientation="vertical"
+ android:padding="0dp"
+ android:layout_marginTop="@dimen/global_actions_grid_container_bottom_margin"
+ android:layout_marginBottom="@dimen/global_actions_grid_container_bottom_margin"
+ >
+ <!-- Global actions is right-aligned to be physically near power button -->
+ <LinearLayout
+ android:id="@android:id/list"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:gravity="right"
+ android:translationZ="@dimen/global_actions_translate"
+ android:layout_marginRight="@dimen/global_actions_grid_side_margin"
+ android:paddingLeft="@dimen/global_actions_grid_horizontal_padding"
+ android:paddingRight="@dimen/global_actions_grid_horizontal_padding"
+ android:paddingTop="@dimen/global_actions_grid_vertical_padding"
+ android:paddingBottom="@dimen/global_actions_grid_vertical_padding"
+ />
+
+ <!-- For separated items-->
+ <LinearLayout
+ android:id="@+id/separated_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/global_actions_grid_side_margin"
+ android:layout_marginRight="@dimen/global_actions_grid_side_margin"
+ android:paddingLeft="@dimen/global_actions_grid_horizontal_padding"
+ android:paddingRight="@dimen/global_actions_grid_horizontal_padding"
+ android:paddingTop="@dimen/global_actions_grid_vertical_padding"
+ android:paddingBottom="@dimen/global_actions_grid_vertical_padding"
+ android:orientation="vertical"
+ android:gravity="center"
+ android:translationZ="@dimen/global_actions_translate"
+ />
+ </LinearLayout>
+
+</com.android.systemui.globalactions.GlobalActionsColumnLayout>
diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml
index 58af4a2..087e0bd 100644
--- a/packages/SystemUI/res/layout/notification_info.xml
+++ b/packages/SystemUI/res/layout/notification_info.xml
@@ -103,7 +103,6 @@
android:id="@+id/channel_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginBottom="@dimen/notification_guts_button_spacing"
android:paddingEnd="@*android:dimen/notification_content_margin_end"
android:gravity="center"
android:orientation="vertical">
@@ -127,6 +126,7 @@
android:id="@+id/blocking_helper"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/notification_guts_button_spacing"
android:layout_marginBottom="@dimen/notification_guts_button_spacing"
android:paddingEnd="@*android:dimen/notification_content_margin_end"
android:clipChildren="false"
@@ -216,67 +216,107 @@
android:id="@+id/interruptiveness_settings"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:gravity="center"
android:orientation="vertical">
- <LinearLayout
- android:id="@+id/buttons"
+ <RelativeLayout
+ android:id="@+id/alert"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:gravity="center">
-
- <Button
- android:id="@+id/alert"
- android:minWidth="@dimen/notification_importance_button_width"
+ android:padding="@dimen/notification_importance_button_padding"
+ android:clickable="true"
+ android:focusable="true">
+ <ImageView
+ android:id="@+id/alert_icon"
+ android:src="@drawable/ic_notification_interruptive"
+ android:background="@android:color/transparent"
+ android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:minHeight="@dimen/notification_importance_toggle_size"
- android:paddingStart="@dimen/notification_importance_button_horiz_padding"
- android:paddingEnd="@dimen/notification_importance_button_horiz_padding"
- android:drawablePadding="@dimen/notification_importance_drawable_padding"
- android:foreground="@drawable/button_ripple_radius"
- android:drawableLeft="@drawable/ic_notification_interruptive"
- android:text="@string/notification_alert_title" />
-
- <Button
- android:id="@+id/silence"
- android:minWidth="@dimen/notification_importance_button_width"
- android:layout_width="wrap_content"
+ android:clickable="false"
+ android:focusable="false"/>
+ <TextView
+ android:id="@+id/alert_label"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:minHeight="@dimen/notification_importance_toggle_size"
- android:paddingStart="@dimen/notification_importance_button_horiz_padding"
- android:paddingEnd="@dimen/notification_importance_button_horiz_padding"
- android:drawablePadding="@dimen/notification_importance_drawable_padding"
- android:foreground="@drawable/button_ripple_radius"
- android:layout_marginStart="@dimen/notification_importance_button_separation"
- android:drawableLeft="@drawable/ic_notification_gentle"
- android:text="@string/notification_silence_title" />
- </LinearLayout>
+ android:ellipsize="end"
+ android:maxLines="1"
+ android:clickable="false"
+ android:focusable="false"
+ android:layout_toEndOf="@id/alert_icon"
+ android:layout_marginStart="@dimen/notification_importance_drawable_padding"
+ android:textAppearance="@style/TextAppearance.NotificationImportanceButton.Unselected"
+ android:text="@string/notification_alert_title"/>
+ <TextView
+ android:id="@+id/alert_summary"
+ android:paddingTop="@dimen/notification_importance_button_padding"
+ android:text="@string/notification_channel_summary_default"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clickable="false"
+ android:focusable="false"
+ android:ellipsize="end"
+ android:maxLines="2"
+ android:layout_below="@id/alert_icon"
+ android:textAppearance="@style/TextAppearance.NotificationImportanceDetail"/>
+ </RelativeLayout>
- <TextView
- android:id="@+id/description"
+ <RelativeLayout
+ android:id="@+id/silence"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:text="@string/notification_alert_title"
- android:gravity="center"
- android:layout_marginTop="@dimen/notification_importance_text_marginTop"
- android:paddingStart="@dimen/notification_importance_description_padding"
- android:paddingEnd="@dimen/notification_importance_description_padding"
- android:textAppearance="@style/TextAppearance.NotificationImportanceDetail" />
+ android:padding="@dimen/notification_importance_button_padding"
+ android:layout_marginTop="@dimen/notification_importance_button_separation"
+ android:clickable="true"
+ android:focusable="true">
+ <ImageView
+ android:id="@+id/silence_icon"
+ android:src="@drawable/ic_notification_gentle"
+ android:background="@android:color/transparent"
+ android:layout_gravity="center"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:clickable="false"
+ android:focusable="false"/>
+ <TextView
+ android:id="@+id/silence_label"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:ellipsize="end"
+ android:maxLines="1"
+ android:clickable="false"
+ android:focusable="false"
+ android:layout_toEndOf="@id/silence_icon"
+ android:layout_marginStart="@dimen/notification_importance_drawable_padding"
+ android:textAppearance="@style/TextAppearance.NotificationImportanceButton.Unselected"
+ android:text="@string/notification_silence_title"/>
+ <TextView
+ android:id="@+id/silence_summary"
+ android:paddingTop="@dimen/notification_importance_button_padding"
+ android:text="@string/notification_channel_summary_default"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clickable="false"
+ android:focusable="false"
+ android:ellipsize="end"
+ android:maxLines="2"
+ android:layout_below="@id/silence_icon"
+ android:textAppearance="@style/TextAppearance.NotificationImportanceDetail"/>
+ </RelativeLayout>
+
</LinearLayout>
<RelativeLayout
android:id="@+id/bottom_buttons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingTop="@dimen/notification_guts_button_spacing" >
+ android:layout_marginTop="@dimen/notification_guts_button_spacing" >
<TextView
android:id="@+id/turn_off_notifications"
android:text="@string/inline_turn_off_notifications"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
- android:layout_centerVertical="true"
android:minWidth="@dimen/notification_importance_toggle_size"
android:minHeight="@dimen/notification_importance_toggle_size"
android:maxWidth="200dp"
@@ -286,11 +326,11 @@
android:text="@string/inline_ok_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_centerVertical="true"
+ android:layout_alignParentEnd="true"
+ android:gravity="center_vertical|end"
android:maxWidth="125dp"
android:minWidth="@dimen/notification_importance_toggle_size"
android:minHeight="@dimen/notification_importance_toggle_size"
- android:layout_alignParentEnd="true"
style="@style/TextAppearance.NotificationInfo.Button"/>
</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/qs_carrier.xml b/packages/SystemUI/res/layout/qs_carrier.xml
index 8f74806..8dd06f0 100644
--- a/packages/SystemUI/res/layout/qs_carrier.xml
+++ b/packages/SystemUI/res/layout/qs_carrier.xml
@@ -42,6 +42,7 @@
android:layout_weight="1"
android:textAppearance="@style/TextAppearance.QS.Status"
android:textDirection="locale"
+ android:marqueeRepeatLimit="marquee_forever"
android:singleLine="true"
android:maxEms="7"/>
diff --git a/packages/SystemUI/res/layout/quick_qs_status_icons.xml b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
index 7f69cf4..5b7e7e7 100644
--- a/packages/SystemUI/res/layout/quick_qs_status_icons.xml
+++ b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
@@ -19,8 +19,8 @@
android:id="@+id/quick_qs_status_icons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/qs_header_top_margin"
- android:layout_marginBottom="14dp"
+ android:paddingTop="@dimen/qs_header_top_padding"
+ android:paddingBottom="@dimen/qs_header_bottom_padding"
android:paddingStart="@dimen/status_bar_padding_start"
android:paddingEnd="@dimen/status_bar_padding_end"
android:layout_below="@id/quick_status_bar_system_icons"
diff --git a/packages/SystemUI/res/layout/rotate_suggestion.xml b/packages/SystemUI/res/layout/rotate_suggestion.xml
new file mode 100644
index 0000000..d7f67db
--- /dev/null
+++ b/packages/SystemUI/res/layout/rotate_suggestion.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<com.android.systemui.statusbar.policy.KeyButtonView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/rotate_suggestion"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="0"
+ android:scaleType="center"
+ android:visibility="invisible"
+ android:contentDescription="@string/accessibility_rotate_button"
+ android:paddingStart="@dimen/navigation_key_padding"
+ android:paddingEnd="@dimen/navigation_key_padding"
+/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/start_contextual.xml b/packages/SystemUI/res/layout/start_contextual.xml
new file mode 100644
index 0000000..e022c73
--- /dev/null
+++ b/packages/SystemUI/res/layout/start_contextual.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/start_menu_container"
+ android:layout_width="@dimen/navigation_key_width"
+ android:layout_height="match_parent"
+ android:importantForAccessibility="no"
+ android:focusable="false"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ >
+ <include layout="@layout/rotate_suggestion"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="invisible"
+ />
+ <include layout="@layout/back"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="invisible"
+ />
+</FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 7338687..4abe9f0 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -331,7 +331,7 @@
<!-- Nav bar button default ordering/layout -->
<string name="config_navBarLayout" translatable="false">left[.5W],back[1WC];home;recent[1WC],right[.5W]</string>
<string name="config_navBarLayoutQuickstep" translatable="false">back[1.7WC];home;contextual[1.7WC]</string>
- <string name="config_navBarLayoutHandle" translatable="false">back[1.7WC];home_handle;ime_switcher[1.7WC]</string>
+ <string name="config_navBarLayoutHandle" translatable="false">start_contextual[.1WC];home_handle;ime_switcher[.1WC]</string>
<bool name="quick_settings_show_full_alarm">false</bool>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 955cfb0..ce958ab 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -212,7 +212,7 @@
<dimen name="notification_guts_option_horizontal_padding">15dp</dimen>
<!-- The vertical space between items in the alert selections in the inline settings -->
- <dimen name="notification_guts_option_vertical_padding">24dp</dimen>
+ <dimen name="notification_guts_option_vertical_padding">20dp</dimen>
<!-- The vertical space between the alert selections in the inline settings -->
<dimen name="notification_guts_option_vertical_margin">6dp</dimen>
@@ -226,10 +226,12 @@
<dimen name="notification_importance_button_horiz_padding">28dp</dimen>
<dimen name="notification_importance_drawable_padding">8dp</dimen>
<dimen name="notification_importance_description_padding">20dp</dimen>
- <dimen name="notification_importance_description_text">12sp</dimen>
+ <dimen name="notification_importance_header_text">12sp</dimen>
+ <dimen name="notification_importance_description_text">14sp</dimen>
<dimen name="notification_importance_channel_text">16sp</dimen>
<dimen name="notification_importance_channel_group_text">14sp</dimen>
<dimen name="notification_importance_button_text">16sp</dimen>
+ <dimen name="notification_importance_button_padding">14dp</dimen>
<dimen name="rect_button_radius">8dp</dimen>
<!-- The minimum height for the snackbar shown after the snooze option has been chosen. -->
@@ -492,7 +494,8 @@
<dimen name="qs_footer_padding_end">16dp</dimen>
<dimen name="qs_footer_icon_size">16dp</dimen>
<dimen name="qs_paged_tile_layout_padding_bottom">0dp</dimen>
- <dimen name="qs_header_top_margin">15dp</dimen>
+ <dimen name="qs_header_top_padding">15dp</dimen>
+ <dimen name="qs_header_bottom_padding">14dp</dimen>
<dimen name="qs_notif_collapsed_space">64dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index acc03c4..cea336c 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1345,6 +1345,7 @@
<!-- Screen pinning dialog description. -->
<string name="screen_pinning_description">This keeps it in view until you unpin. Touch & hold Back and Overview to unpin.</string>
<string name="screen_pinning_description_recents_invisible">This keeps it in view until you unpin. Touch & hold Back and Home to unpin.</string>
+ <string name="screen_pinning_description_gestural">This keeps it in view until you unpin. Swipe up & hold to unpin.</string>
<!-- Screen pinning dialog description. -->
<string name="screen_pinning_description_accessible">This keeps it in view until you unpin. Touch & hold Overview to unpin.</string>
<string name="screen_pinning_description_recents_invisible_accessible">This keeps it in view until you unpin. Touch & hold Home to unpin.</string>
@@ -1658,19 +1659,19 @@
<string name="notification_alert_title">Prioritized</string>
<!-- [CHAR LIMIT=150] Notification Importance title: low importance level summary -->
- <string name="notification_channel_summary_low">Always silent. Displays in pull-down shade.</string>
+ <string name="notification_channel_summary_low">Helps you focus with notifications only in the pull-down shade. Always silent.</string>
<!-- [CHAR LIMIT=150] Notification Importance title: low importance level summary -->
- <string name="notification_channel_summary_low_status">Always silent. Displays in pull-down shade & status bar.</string>
+ <string name="notification_channel_summary_low_status">Displays below priority notifications. Always silent.</string>
<!-- [CHAR LIMIT=150] Notification Importance title: low importance level summary -->
- <string name="notification_channel_summary_low_lock">Always silent. Displays in pull-down shade & on lock screen.</string>
+ <string name="notification_channel_summary_low_lock">Displays below priority notifications. Always silent.</string>
<!-- [CHAR LIMIT=150] Notification Importance title: low importance level summary -->
- <string name="notification_channel_summary_low_status_lock">Always silent. Displays in pull-down shade, status bar & on lock screen.</string>
+ <string name="notification_channel_summary_low_status_lock">Displays below priority notifications. Always silent.</string>
<!-- [CHAR LIMIT=150] Notification Importance title: normal importance level summary -->
- <string name="notification_channel_summary_default">Makes sound and displays in pull-down shade, status bar & on lock screen.</string>
+ <string name="notification_channel_summary_default">Gets your attention with sound & a status bar icon. Shows on lock screen.</string>
<!-- Notification: Control panel: Label that displays when the app's notifications cannot be blocked. -->
<string name="notification_unblockable_desc">These notifications can\'t be modified.</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index d765f0c..23de2ac 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -473,7 +473,7 @@
</style>
<style name="TextAppearance.NotificationImportanceHeader">
- <item name="android:textSize">@dimen/notification_importance_description_text</item>
+ <item name="android:textSize">@dimen/notification_importance_header_text</item>
<item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
<item name="android:textColor">@color/notification_guts_header_text_color</item>
</style>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java
index 1a684a0..40d98c1 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java
@@ -295,8 +295,10 @@
info.serviceInfo.name);
PluginInfo<T> t = handleLoadPlugin(name);
if (t == null) continue;
- mMainHandler.obtainMessage(mMainHandler.PLUGIN_CONNECTED, t).sendToTarget();
+
+ // add plugin before sending PLUGIN_CONNECTED message
mPlugins.add(t);
+ mMainHandler.obtainMessage(mMainHandler.PLUGIN_CONNECTED, t).sendToTarget();
}
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
index 6f44623..b826b30 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
@@ -38,11 +38,6 @@
void startScreenPinning(int taskId) = 1;
/**
- * Enables/disables launcher/overview interaction features {@link InteractionType}.
- */
- void setInteractionState(int flags) = 4;
-
- /**
* Notifies SystemUI that split screen has been invoked.
*/
void onSplitScreenInvoked() = 5;
@@ -96,4 +91,9 @@
* Notifies that the accessibility button in the system's navigation area has been long clicked
*/
void notifyAccessibilityButtonLongClicked() = 16;
+
+ /**
+ * Ends the system screen pinning.
+ */
+ void stopScreenPinning() = 17;
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java
deleted file mode 100644
index 8d6f830..0000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.shared.system;
-
-import android.annotation.IntDef;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-public class NavigationBarCompat extends QuickStepContract {
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({HIT_TARGET_NONE, HIT_TARGET_BACK, HIT_TARGET_HOME, HIT_TARGET_OVERVIEW})
- public @interface HitTarget{}
-
- public static final int HIT_TARGET_NONE = 0;
- public static final int HIT_TARGET_BACK = 1;
- public static final int HIT_TARGET_HOME = 2;
- public static final int HIT_TARGET_OVERVIEW = 3;
- public static final int HIT_TARGET_ROTATION = 4;
- public static final int HIT_TARGET_DEAD_ZONE = 5;
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({FLAG_DISABLE_SWIPE_UP,
- FLAG_DISABLE_QUICK_SCRUB,
- FLAG_SHOW_OVERVIEW_BUTTON
- })
- public @interface InteractionType {}
-
- /**
- * Interaction type: whether the gesture to swipe up from the navigation bar will trigger
- * launcher to show overview
- */
- public static final int FLAG_DISABLE_SWIPE_UP = 0x1;
- /**
- * Interaction type: enable quick scrub interaction on the home button
- */
- public static final int FLAG_DISABLE_QUICK_SCRUB = 0x2;
-
- /**
- * Interaction type: show/hide the overview button while this service is connected to launcher
- */
- public static final int FLAG_SHOW_OVERVIEW_BUTTON = 0x4;
-
-
-}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java
index 0a6885c..037a8d3 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java
@@ -59,14 +59,22 @@
private ColorStateList mDefaultColorState;
private CharSequence mMessage;
private ColorStateList mNextMessageColorState = ColorStateList.valueOf(DEFAULT_COLOR);
+ private boolean mBouncerVisible;
private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
public void onFinishedGoingToSleep(int why) {
setSelected(false);
- };
+ }
+
public void onStartedWakingUp() {
setSelected(true);
- };
+ }
+
+ @Override
+ public void onKeyguardBouncerChanged(boolean bouncer) {
+ mBouncerVisible = bouncer;
+ update();
+ }
};
public KeyguardMessageArea(Context context) {
@@ -188,7 +196,7 @@
private void update() {
CharSequence status = mMessage;
- setVisibility(TextUtils.isEmpty(status) ? INVISIBLE : VISIBLE);
+ setVisibility(TextUtils.isEmpty(status) || !mBouncerVisible ? INVISIBLE : VISIBLE);
setText(status);
ColorStateList colorState = mDefaultColorState;
if (mNextMessageColorState.getDefaultColor() != DEFAULT_COLOR) {
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/AnalogClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/AnalogClockController.java
index 123e138..eec1d70 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/AnalogClockController.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/AnalogClockController.java
@@ -189,6 +189,7 @@
@Override
public void setDarkAmount(float darkAmount) {
mClockPosition.setDarkAmount(darkAmount);
+ mBigClockView.setDarkAmount(darkAmount);
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java
index 8db61b8..5fec61b 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java
@@ -181,6 +181,7 @@
@Override
public void setDarkAmount(float darkAmount) {
mClockPosition.setDarkAmount(darkAmount);
+ mView.setDarkAmount(darkAmount);
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java
index 962b8f8..1908345 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.content.res.Resources;
import android.util.AttributeSet;
+import android.util.MathUtils;
import android.view.View;
import android.widget.FrameLayout;
@@ -43,6 +44,8 @@
private int mBurnInPreventionOffsetX;
private int mBurnInPreventionOffsetY;
+ private float mDarkAmount;
+
public ClockLayout(Context context) {
this(context, null);
}
@@ -78,11 +81,21 @@
positionChildren();
}
+ /**
+ * See {@link com.android.systemui.plugins.ClockPlugin#setDarkAmount(float)}.
+ */
+ void setDarkAmount(float darkAmount) {
+ mDarkAmount = darkAmount;
+ positionChildren();
+ }
+
private void positionChildren() {
- final float offsetX = getBurnInOffset(mBurnInPreventionOffsetX * 2, true)
- - mBurnInPreventionOffsetX;
- final float offsetY = getBurnInOffset(mBurnInPreventionOffsetY * 2, false)
- - mBurnInPreventionOffsetY;
+ final float offsetX = MathUtils.lerp(0f,
+ getBurnInOffset(mBurnInPreventionOffsetX * 2, true) - mBurnInPreventionOffsetX,
+ mDarkAmount);
+ final float offsetY = MathUtils.lerp(0f,
+ getBurnInOffset(mBurnInPreventionOffsetY * 2, false) - mBurnInPreventionOffsetY,
+ mDarkAmount);
// Put the analog clock in the middle of the screen.
if (mAnalogClock != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
index 04f887b..41a7bc4 100644
--- a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
@@ -16,6 +16,7 @@
import android.app.PendingIntent;
import android.content.Intent;
+import android.view.View;
import com.android.systemui.plugins.ActivityStarter;
@@ -53,6 +54,16 @@
}
@Override
+ public void startPendingIntentDismissingKeyguard(PendingIntent intent,
+ Runnable intentSentCallback, View associatedView) {
+ if (mActualStarter == null) {
+ return;
+ }
+ mActualStarter.startPendingIntentDismissingKeyguard(intent, intentSentCallback,
+ associatedView);
+ }
+
+ @Override
public void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade,
int flags) {
if (mActualStarter == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 1feb63d..4b6306a 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -35,6 +35,7 @@
import com.android.systemui.assist.AssistManager;
import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.dock.DockManager;
import com.android.systemui.fragments.FragmentService;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.WakefulnessLifecycle;
@@ -296,6 +297,7 @@
@Inject Lazy<PackageManagerWrapper> mPackageManagerWrapper;
@Inject Lazy<SensorPrivacyController> mSensorPrivacyController;
@Inject Lazy<DumpController> mDumpController;
+ @Inject Lazy<DockManager> mDockManager;
@Inject
public Dependency() {
@@ -470,6 +472,7 @@
mProviders.put(PackageManagerWrapper.class, mPackageManagerWrapper::get);
mProviders.put(SensorPrivacyController.class, mSensorPrivacyController::get);
mProviders.put(DumpController.class, mDumpController::get);
+ mProviders.put(DockManager.class, mDockManager::get);
// TODO(b/118592525): to support multi-display , we start to add something which is
// per-display, while others may be global. I think it's time to add
diff --git a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
index 802903d..ad2e002 100644
--- a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
@@ -80,16 +80,6 @@
}
@Override
- public void removeAllItems() {
- if (mList != null) {
- mList.removeAllViews();
- }
- if (mSeparatedView != null) {
- mSeparatedView.removeAllViews();
- }
- }
-
- @Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
updateSettings();
diff --git a/packages/SystemUI/src/com/android/systemui/MultiListLayout.java b/packages/SystemUI/src/com/android/systemui/MultiListLayout.java
index f8287a4..d153fb0 100644
--- a/packages/SystemUI/src/com/android/systemui/MultiListLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/MultiListLayout.java
@@ -45,11 +45,6 @@
protected abstract ViewGroup getListView();
/**
- * Removes all child items from the separated and list views, if they exist.
- */
- protected abstract void removeAllItems();
-
- /**
* Sets the divided view, which may have a differently-colored background.
*/
public abstract void setDivisionView(View v);
@@ -110,6 +105,25 @@
onUpdateList();
}
+ protected void removeAllSeparatedViews() {
+ ViewGroup separated = getSeparatedView();
+ if (separated != null) {
+ separated.removeAllViews();
+ }
+ }
+
+ protected void removeAllListViews() {
+ ViewGroup list = getListView();
+ if (list != null) {
+ list.removeAllViews();
+ }
+ }
+
+ protected void removeAllItems() {
+ removeAllListViews();
+ removeAllSeparatedViews();
+ }
+
protected void onUpdateList() {
removeAllItems();
setSeparatedViewVisibility(mAdapter.hasSeparatedItems());
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index 2797570..10ae343 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -57,7 +57,6 @@
Key.SEEN_RINGER_GUIDANCE_COUNT,
Key.QS_HAS_TURNED_OFF_MOBILE_DATA,
Key.TOUCHED_RINGER_TOGGLE,
- Key.QUICK_STEP_INTERACTION_FLAGS,
Key.HAS_SEEN_ODI_CAPTIONS_TOOLTIP
})
public @interface Key {
@@ -103,7 +102,6 @@
String QS_TILE_SPECS_REVEALED = "QsTileSpecsRevealed";
String QS_HAS_TURNED_OFF_MOBILE_DATA = "QsHasTurnedOffMobileData";
String TOUCHED_RINGER_TOGGLE = "TouchedRingerToggle";
- String QUICK_STEP_INTERACTION_FLAGS = "QuickStepInteractionFlags";
String HAS_SEEN_ODI_CAPTIONS_TOOLTIP = "HasSeenODICaptionsTooltip";
}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index ffb5e81..f9926f3 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -34,6 +34,7 @@
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.classifier.FalsingManager;
+import com.android.systemui.dock.DockManager;
import com.android.systemui.fragments.FragmentService;
import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -179,6 +180,13 @@
@Singleton
@Provides
+ @Nullable
+ public DockManager provideDockManager(Context context) {
+ return null;
+ }
+
+ @Singleton
+ @Provides
public NotificationEntryManager provideNotificationEntryManager(Context context) {
return new NotificationEntryManager(context);
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
index 0332477..7094d28 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
@@ -16,9 +16,12 @@
package com.android.systemui.bubbles;
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
+
import android.os.UserHandle;
import android.view.LayoutInflater;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -40,15 +43,24 @@
public NotificationEntry entry;
BubbleView iconView;
BubbleExpandedView expandedView;
+ private long mLastUpdated;
+ private long mLastAccessed;
private static String groupId(NotificationEntry entry) {
UserHandle user = entry.notification.getUser();
- return user.getIdentifier() + '|' + entry.notification.getPackageName();
+ return user.getIdentifier() + "|" + entry.notification.getPackageName();
+ }
+
+ /** Used in tests when no UI is required. */
+ @VisibleForTesting(visibility = PRIVATE)
+ Bubble(NotificationEntry e) {
+ this (e, null);
}
Bubble(NotificationEntry e, BubbleExpandedView.OnBubbleBlockedListener listener) {
entry = e;
mKey = e.key;
+ mLastUpdated = e.notification.getPostTime();
mGroupId = groupId(e);
mListener = listener;
}
@@ -101,12 +113,37 @@
void setEntry(NotificationEntry entry) {
this.entry = entry;
+ mLastUpdated = entry.notification.getPostTime();
if (mInflated) {
iconView.update(entry);
expandedView.update(entry);
}
}
+ public long getLastActivity() {
+ return Math.max(mLastUpdated, mLastAccessed);
+ }
+
+ /**
+ * Should be invoked whenever a Bubble is accessed (selected while expanded).
+ */
+ void markAsAccessedAt(long lastAccessedMillis) {
+ mLastAccessed = lastAccessedMillis;
+ entry.setShowInShadeWhenBubble(false);
+ }
+
+ /**
+ * @return whether bubble is from a notification associated with a foreground service.
+ */
+ public boolean isOngoing() {
+ return entry.isForegroundService();
+ }
+
+ @Override
+ public String toString() {
+ return "Bubble{" + mKey + '}';
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index ef383ad..d071363 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -41,6 +41,7 @@
import android.os.ServiceManager;
import android.provider.Settings;
import android.service.notification.StatusBarNotification;
+import android.util.Log;
import android.view.Display;
import android.view.IPinnedStackController;
import android.view.IPinnedStackListener;
@@ -83,6 +84,7 @@
public class BubbleController implements ConfigurationController.ConfigurationListener {
private static final String TAG = "BubbleController";
+ private static final boolean DEBUG = true;
@Retention(SOURCE)
@IntDef({DISMISS_USER_GESTURE, DISMISS_AGED, DISMISS_TASK_FINISHED, DISMISS_BLOCKED,
@@ -203,6 +205,9 @@
configurationController.addCallback(this /* configurationListener */);
+ mBubbleData = data;
+ mBubbleData.setListener(mBubbleDataListener);
+
mNotificationEntryManager = Dependency.get(NotificationEntryManager.class);
mNotificationEntryManager.addNotificationEntryListener(mEntryListener);
@@ -219,9 +224,6 @@
} catch (RemoteException e) {
e.printStackTrace();
}
-
- mBubbleData = data;
- mBubbleData.setListener(mBubbleDataListener);
mSurfaceSynchronizer = synchronizer;
mBarService = IStatusBarService.Stub.asInterface(
@@ -482,7 +484,7 @@
}
@Override
- public void onSelectionChanged(Bubble selectedBubble) {
+ public void onSelectionChanged(@Nullable Bubble selectedBubble) {
if (mStackView != null) {
mStackView.setSelectedBubble(selectedBubble);
}
@@ -506,6 +508,18 @@
public void apply() {
mNotificationEntryManager.updateNotifications();
updateVisibility();
+
+ if (DEBUG) {
+ Log.d(TAG, "[BubbleData]");
+ Log.d(TAG, formatBubblesString(mBubbleData.getBubbles(),
+ mBubbleData.getSelectedBubble()));
+
+ if (mStackView != null) {
+ Log.d(TAG, "[BubbleStackView]");
+ Log.d(TAG, formatBubblesString(mStackView.getBubblesOnScreen(),
+ mStackView.getExpandedBubble()));
+ }
+ }
}
};
@@ -623,6 +637,23 @@
entry.setShowInShadeWhenBubble(!suppressNotification);
}
+ static String formatBubblesString(List<Bubble> bubbles, Bubble selected) {
+ StringBuilder sb = new StringBuilder();
+ for (Bubble bubble : bubbles) {
+ if (bubble == null) {
+ sb.append(" <null> !!!!!\n");
+ } else {
+ boolean isSelected = (bubble == selected);
+ sb.append(String.format("%s Bubble{act=%12d, ongoing=%d, key=%s}\n",
+ ((isSelected) ? "->" : " "),
+ bubble.getLastActivity(),
+ (bubble.isOngoing() ? 1 : 0),
+ bubble.getKey()));
+ }
+ }
+ return sb.toString();
+ }
+
/**
* Return true if the applications with the package name is running in foreground.
*
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
index 259665d..38ba91e 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
@@ -17,21 +17,26 @@
import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
-import android.app.ActivityManager;
+import static java.util.stream.Collectors.toList;
+
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;
import android.util.Log;
+import androidx.annotation.Nullable;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.bubbles.BubbleController.DismissReason;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import javax.inject.Inject;
@@ -44,6 +49,15 @@
public class BubbleData {
private static final String TAG = "BubbleData";
+ private static final boolean DEBUG = false;
+
+ private static final int MAX_BUBBLES = 5;
+
+ private static final Comparator<Bubble> BUBBLES_BY_LAST_ACTIVITY_DESCENDING =
+ Comparator.comparing(Bubble::getLastActivity).reversed();
+
+ private static final Comparator<Map.Entry<String, Long>> GROUPS_BY_LAST_ACTIVITY_DESCENDING =
+ Comparator.<Map.Entry<String, Long>, Long>comparing(Map.Entry::getValue).reversed();
/**
* This interface reports changes to the state and appearance of bubbles which should be applied
@@ -83,7 +97,7 @@
void onOrderChanged(List<Bubble> bubbles);
/** Indicates the selected bubble changed. */
- void onSelectionChanged(Bubble selectedBubble);
+ void onSelectionChanged(@Nullable Bubble selectedBubble);
/**
* The UI should transition to the given state, incorporating any pending changes during
@@ -98,16 +112,28 @@
void apply();
}
+ interface TimeSource {
+ long currentTimeMillis();
+ }
+
private final Context mContext;
- private final List<Bubble> mBubbles = new ArrayList<>();
+ private List<Bubble> mBubbles;
private Bubble mSelectedBubble;
private boolean mExpanded;
+
+ // TODO: ensure this is invalidated at the appropriate time
+ private int mSelectedBubbleExpandedPosition = -1;
+
+ private TimeSource mTimeSource = System::currentTimeMillis;
+
+ @Nullable
private Listener mListener;
@VisibleForTesting
@Inject
public BubbleData(Context context) {
mContext = context;
+ mBubbles = new ArrayList<>();
}
public boolean hasBubbles() {
@@ -122,29 +148,41 @@
return getBubbleWithKey(key) != null;
}
+ @Nullable
+ public Bubble getSelectedBubble() {
+ return mSelectedBubble;
+ }
+
public void setExpanded(boolean expanded) {
if (setExpandedInternal(expanded)) {
- mListener.apply();
+ dispatchApply();
}
}
public void setSelectedBubble(Bubble bubble) {
+ if (DEBUG) {
+ Log.d(TAG, "setSelectedBubble: " + bubble);
+ }
if (setSelectedBubbleInternal(bubble)) {
- mListener.apply();
+ dispatchApply();
}
}
public void notificationEntryUpdated(NotificationEntry entry) {
+ if (DEBUG) {
+ Log.d(TAG, "notificationEntryUpdated: " + entry);
+ }
Bubble bubble = getBubbleWithKey(entry.key);
if (bubble == null) {
// Create a new bubble
bubble = new Bubble(entry, this::onBubbleBlocked);
- mBubbles.add(0, bubble); // TODO: reorder/group
- mListener.onBubbleAdded(bubble);
+ doAdd(bubble);
+ dispatchOnBubbleAdded(bubble);
} else {
// Updates an existing bubble
bubble.setEntry(entry);
- mListener.onBubbleUpdated(bubble);
+ doUpdate(bubble);
+ dispatchOnBubbleUpdated(bubble);
}
if (shouldAutoExpand(entry)) {
setSelectedBubbleInternal(bubble);
@@ -154,49 +192,148 @@
} else if (mSelectedBubble == null) {
setSelectedBubbleInternal(bubble);
}
- // TODO: reorder/group
- mListener.apply();
+ dispatchApply();
+ }
+
+ private void doAdd(Bubble bubble) {
+ if (DEBUG) {
+ Log.d(TAG, "doAdd: " + bubble);
+ }
+ int minInsertPoint = 0;
+ boolean newGroup = !hasBubbleWithGroupId(bubble.getGroupId());
+ if (isExpanded()) {
+ // first bubble of a group goes to the end, otherwise it goes within the existing group
+ minInsertPoint =
+ newGroup ? mBubbles.size() : findFirstIndexForGroup(bubble.getGroupId());
+ }
+ insertBubble(minInsertPoint, bubble);
+ if (!isExpanded()) {
+ packGroup(findFirstIndexForGroup(bubble.getGroupId()));
+ }
+ if (mBubbles.size() > MAX_BUBBLES) {
+ mBubbles.stream()
+ // sort oldest first (ascending lastActivity)
+ .sorted(Comparator.comparingLong(Bubble::getLastActivity))
+ // skip the selected bubble
+ .filter((b) -> !b.equals(mSelectedBubble))
+ .findFirst()
+ .ifPresent((b) -> {
+ doRemove(b.getKey(), BubbleController.DISMISS_AGED);
+ dispatchApply();
+ });
+ }
+ }
+
+ private void doUpdate(Bubble bubble) {
+ if (DEBUG) {
+ Log.d(TAG, "doUpdate: " + bubble);
+ }
+ if (!isExpanded()) {
+ // while collapsed, update causes re-sort
+ mBubbles.remove(bubble);
+ insertBubble(0, bubble);
+ packGroup(findFirstIndexForGroup(bubble.getGroupId()));
+ }
}
public void notificationEntryRemoved(NotificationEntry entry, @DismissReason int reason) {
- int indexToRemove = indexForKey(entry.key);
- if (indexToRemove >= 0) {
- Bubble removed = mBubbles.remove(indexToRemove);
- removed.setDismissed();
- mListener.onBubbleRemoved(removed, reason);
- maybeSendDeleteIntent(reason, removed.entry);
+ if (DEBUG) {
+ Log.d(TAG, "notificationEntryRemoved: entry=" + entry + " reason=" + reason);
+ }
+ doRemove(entry.key, reason);
+ dispatchApply();
+ }
- if (mBubbles.isEmpty()) {
+ private void doRemove(String key, @DismissReason int reason) {
+ int indexToRemove = indexForKey(key);
+ if (indexToRemove >= 0) {
+ Bubble bubbleToRemove = mBubbles.get(indexToRemove);
+ if (mBubbles.size() == 1) {
+ // Going to become empty, handle specially.
setExpandedInternal(false);
setSelectedBubbleInternal(null);
- } else if (removed == mSelectedBubble) {
+ }
+ mBubbles.remove(indexToRemove);
+ dispatchOnBubbleRemoved(bubbleToRemove, reason);
+
+ // Note: If mBubbles.isEmpty(), then mSelectedBubble is now null.
+ if (Objects.equals(mSelectedBubble, bubbleToRemove)) {
+ // Move selection to the new bubble at the same position.
int newIndex = Math.min(indexToRemove, mBubbles.size() - 1);
Bubble newSelected = mBubbles.get(newIndex);
setSelectedBubbleInternal(newSelected);
}
- // TODO: reorder/group
- mListener.apply();
+ bubbleToRemove.setDismissed();
+ maybeSendDeleteIntent(reason, bubbleToRemove.entry);
}
}
public void dismissAll(@DismissReason int reason) {
- boolean changed = setExpandedInternal(false);
+ if (DEBUG) {
+ Log.d(TAG, "dismissAll: reason=" + reason);
+ }
+ if (mBubbles.isEmpty()) {
+ return;
+ }
+ setExpandedInternal(false);
+ setSelectedBubbleInternal(null);
while (!mBubbles.isEmpty()) {
Bubble bubble = mBubbles.remove(0);
bubble.setDismissed();
maybeSendDeleteIntent(reason, bubble.entry);
- mListener.onBubbleRemoved(bubble, reason);
- changed = true;
+ dispatchOnBubbleRemoved(bubble, reason);
}
- if (setSelectedBubbleInternal(null)) {
- changed = true;
- }
- if (changed) {
- // TODO: reorder/group
+ dispatchApply();
+ }
+
+ private void dispatchApply() {
+ if (mListener != null) {
mListener.apply();
}
}
+ private void dispatchOnBubbleAdded(Bubble bubble) {
+ if (mListener != null) {
+ mListener.onBubbleAdded(bubble);
+ }
+ }
+
+ private void dispatchOnBubbleRemoved(Bubble bubble, @DismissReason int reason) {
+ if (mListener != null) {
+ mListener.onBubbleRemoved(bubble, reason);
+ }
+ }
+
+ private void dispatchOnExpandedChanged(boolean expanded) {
+ if (mListener != null) {
+ mListener.onExpandedChanged(expanded);
+ }
+ }
+
+ private void dispatchOnSelectionChanged(@Nullable Bubble bubble) {
+ if (mListener != null) {
+ mListener.onSelectionChanged(bubble);
+ }
+ }
+
+ private void dispatchOnBubbleUpdated(Bubble bubble) {
+ if (mListener != null) {
+ mListener.onBubbleUpdated(bubble);
+ }
+ }
+
+ private void dispatchOnOrderChanged(List<Bubble> bubbles) {
+ if (mListener != null) {
+ mListener.onOrderChanged(bubbles);
+ }
+ }
+
+ private void dispatchShowFlyoutText(Bubble bubble, String text) {
+ if (mListener != null) {
+ mListener.showFlyoutText(bubble, text);
+ }
+ }
+
/**
* Requests a change to the selected bubble. Calls {@link Listener#onSelectionChanged} if
* the value changes.
@@ -204,7 +341,10 @@
* @param bubble the new selected bubble
* @return true if the state changed as a result
*/
- private boolean setSelectedBubbleInternal(Bubble bubble) {
+ private boolean setSelectedBubbleInternal(@Nullable Bubble bubble) {
+ if (DEBUG) {
+ Log.d(TAG, "setSelectedBubbleInternal: " + bubble);
+ }
if (Objects.equals(bubble, mSelectedBubble)) {
return false;
}
@@ -213,16 +353,17 @@
+ " (" + bubble + ") bubbles=" + mBubbles);
return false;
}
- if (mExpanded) {
- // TODO: bubble.markAsActive() ?
- bubble.entry.setShowInShadeWhenBubble(false);
+ if (mExpanded && bubble != null) {
+ mSelectedBubble.markAsAccessedAt(mTimeSource.currentTimeMillis());
}
mSelectedBubble = bubble;
- mListener.onSelectionChanged(mSelectedBubble);
+ dispatchOnSelectionChanged(mSelectedBubble);
+ if (!mExpanded || mSelectedBubble == null) {
+ mSelectedBubbleExpandedPosition = -1;
+ }
return true;
}
-
/**
* Requests a change to the expanded state. Calls {@link Listener#onExpandedChanged} if
* the value changes.
@@ -231,9 +372,15 @@
* @return true if the state changed as a result
*/
private boolean setExpandedInternal(boolean shouldExpand) {
+ if (DEBUG) {
+ Log.d(TAG, "setExpandedInternal: shouldExpand=" + shouldExpand);
+ }
if (mExpanded == shouldExpand) {
return false;
}
+ if (mSelectedBubble != null) {
+ mSelectedBubble.markAsAccessedAt(mTimeSource.currentTimeMillis());
+ }
if (shouldExpand) {
if (mBubbles.isEmpty()) {
Log.e(TAG, "Attempt to expand stack when empty!");
@@ -243,15 +390,126 @@
Log.e(TAG, "Attempt to expand stack without selected bubble!");
return false;
}
- // TODO: bubble.markAsActive() ?
- mSelectedBubble.entry.setShowInShadeWhenBubble(false);
+ } else {
+ repackAll();
}
- // TODO: reorder/regroup
mExpanded = shouldExpand;
- mListener.onExpandedChanged(mExpanded);
+ dispatchOnExpandedChanged(mExpanded);
return true;
}
+ private static long sortKey(Bubble bubble) {
+ long key = bubble.getLastActivity();
+ if (bubble.isOngoing()) {
+ // Set 2nd highest bit (signed long int), to partition between ongoing and regular
+ key |= 0x4000000000000000L;
+ }
+ return key;
+ }
+
+ /**
+ * Locates and inserts the bubble into a sorted position. The is inserted
+ * based on sort key, groupId is not considered. A call to {@link #packGroup(int)} may be
+ * required to keep grouping intact.
+ *
+ * @param minPosition the first insert point to consider
+ * @param newBubble the bubble to insert
+ * @return the position where the bubble was inserted
+ */
+ private int insertBubble(int minPosition, Bubble newBubble) {
+ long newBubbleSortKey = sortKey(newBubble);
+ String previousGroupId = null;
+
+ for (int pos = minPosition; pos < mBubbles.size(); pos++) {
+ Bubble bubbleAtPos = mBubbles.get(pos);
+ String groupIdAtPos = bubbleAtPos.getGroupId();
+ boolean atStartOfGroup = !groupIdAtPos.equals(previousGroupId);
+
+ if (atStartOfGroup && newBubbleSortKey > sortKey(bubbleAtPos)) {
+ // Insert before the start of first group which has older bubbles.
+ mBubbles.add(pos, newBubble);
+ return pos;
+ }
+ previousGroupId = groupIdAtPos;
+ }
+ mBubbles.add(newBubble);
+ return mBubbles.size() - 1;
+ }
+
+ private boolean hasBubbleWithGroupId(String groupId) {
+ return mBubbles.stream().anyMatch(b -> b.getGroupId().equals(groupId));
+ }
+
+ private int findFirstIndexForGroup(String appId) {
+ for (int i = 0; i < mBubbles.size(); i++) {
+ Bubble bubbleAtPos = mBubbles.get(i);
+ if (bubbleAtPos.getGroupId().equals(appId)) {
+ return i;
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * Starting at the given position, moves all bubbles with the same group id to follow. Bubbles
+ * at positions lower than {@code position} are unchanged. Relative order within the group
+ * unchanged. Relative order of any other bubbles are also unchanged.
+ *
+ * @param position the position of the first bubble for the group
+ */
+ private void packGroup(int position) {
+ if (DEBUG) {
+ Log.d(TAG, "packGroup: position=" + position);
+ }
+ Bubble groupStart = mBubbles.get(position);
+ final String groupAppId = groupStart.getGroupId();
+ List<Bubble> moving = new ArrayList<>();
+
+ // Walk backward, collect bubbles within the group
+ for (int i = mBubbles.size() - 1; i > position; i--) {
+ if (mBubbles.get(i).getGroupId().equals(groupAppId)) {
+ moving.add(0, mBubbles.get(i));
+ }
+ }
+ mBubbles.removeAll(moving);
+ mBubbles.addAll(position + 1, moving);
+ }
+
+ private void repackAll() {
+ if (DEBUG) {
+ Log.d(TAG, "repackAll()");
+ }
+ if (mBubbles.isEmpty()) {
+ return;
+ }
+ Map<String, Long> groupLastActivity = new HashMap<>();
+ for (Bubble bubble : mBubbles) {
+ long maxSortKeyForGroup = groupLastActivity.getOrDefault(bubble.getGroupId(), 0L);
+ long sortKeyForBubble = sortKey(bubble);
+ if (sortKeyForBubble > maxSortKeyForGroup) {
+ groupLastActivity.put(bubble.getGroupId(), sortKeyForBubble);
+ }
+ }
+
+ // Sort groups by their most recently active bubble
+ List<String> groupsByMostRecentActivity =
+ groupLastActivity.entrySet().stream()
+ .sorted(GROUPS_BY_LAST_ACTIVITY_DESCENDING)
+ .map(Map.Entry::getKey)
+ .collect(toList());
+
+ List<Bubble> repacked = new ArrayList<>(mBubbles.size());
+
+ // For each group, add bubbles, freshest to oldest
+ for (String appId : groupsByMostRecentActivity) {
+ mBubbles.stream()
+ .filter((b) -> b.getGroupId().equals(appId))
+ .sorted(BUBBLES_BY_LAST_ACTIVITY_DESCENDING)
+ .forEachOrdered(repacked::add);
+ }
+ mBubbles = repacked;
+ }
+
private void maybeSendDeleteIntent(@DismissReason int reason, NotificationEntry entry) {
if (reason == BubbleController.DISMISS_USER_GESTURE) {
Notification.BubbleMetadata bubbleMetadata = entry.getBubbleMetadata();
@@ -275,13 +533,14 @@
Bubble bubble = i.next();
if (bubble.getPackageName().equals(blockedPackage)) {
i.remove();
- mListener.onBubbleRemoved(bubble, BubbleController.DISMISS_BLOCKED);
+ // TODO: handle removal of selected bubble, and collapse safely if emptied (see
+ // dismissAll)
+ dispatchOnBubbleRemoved(bubble, BubbleController.DISMISS_BLOCKED);
changed = true;
}
}
if (changed) {
- // TODO: reorder/group
- mListener.apply();
+ dispatchApply();
}
}
@@ -295,24 +554,11 @@
return -1;
}
- private Bubble removeBubbleWithKey(String key) {
- for (int i = 0; i < mBubbles.size(); i++) {
- Bubble bubble = mBubbles.get(i);
- if (bubble.getKey().equals(key)) {
- mBubbles.remove(i);
- return bubble;
- }
- }
- return null;
- }
-
/**
* The set of bubbles.
- *
- * @deprecated
*/
- @Deprecated
- public Collection<Bubble> getBubbles() {
+ @VisibleForTesting(visibility = PRIVATE)
+ public List<Bubble> getBubbles() {
return Collections.unmodifiableList(mBubbles);
}
@@ -327,6 +573,11 @@
return null;
}
+ @VisibleForTesting(visibility = PRIVATE)
+ void setTimeSource(TimeSource timeSource) {
+ mTimeSource = timeSource;
+ }
+
public void setListener(Listener listener) {
mListener = listener;
}
@@ -334,17 +585,6 @@
boolean shouldAutoExpand(NotificationEntry entry) {
Notification.BubbleMetadata metadata = entry.getBubbleMetadata();
return metadata != null && metadata.getAutoExpandBubble()
- && isForegroundApp(entry.notification.getPackageName());
- }
-
- /**
- * Return true if the applications with the package name is running in foreground.
- *
- * @param pkgName application package name.
- */
- boolean isForegroundApp(String pkgName) {
- ActivityManager am = mContext.getSystemService(ActivityManager.class);
- List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1 /* maxNum */);
- return !tasks.isEmpty() && pkgName.equals(tasks.get(0).topActivity.getPackageName());
+ && BubbleController.isForegroundApp(mContext, entry.notification.getPackageName());
}
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 7029931..d1bc9a9 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -66,6 +66,7 @@
import java.math.BigDecimal;
import java.math.RoundingMode;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -227,7 +228,7 @@
mBubbleData = data;
mInflater = LayoutInflater.from(context);
- mTouchHandler = new BubbleTouchHandler(context, this);
+ mTouchHandler = new BubbleTouchHandler(this, data, context);
setOnTouchListener(mTouchHandler);
mInflater = LayoutInflater.from(context);
@@ -503,6 +504,9 @@
// via BubbleData.Listener
void addBubble(Bubble bubble) {
+ if (DEBUG) {
+ Log.d(TAG, "addBubble: " + bubble);
+ }
bubble.inflate(mInflater, this);
mBubbleContainer.addView(bubble.iconView, 0,
new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
@@ -513,10 +517,17 @@
// via BubbleData.Listener
void removeBubble(Bubble bubble) {
+ if (DEBUG) {
+ Log.d(TAG, "removeBubble: " + bubble);
+ }
// Remove it from the views
int removedIndex = mBubbleContainer.indexOfChild(bubble.iconView);
- mBubbleContainer.removeViewAt(removedIndex);
- logBubbleEvent(bubble, StatsLog.BUBBLE_UICHANGED__ACTION__DISMISSED);
+ if (removedIndex >= 0) {
+ mBubbleContainer.removeViewAt(removedIndex);
+ logBubbleEvent(bubble, StatsLog.BUBBLE_UICHANGED__ACTION__DISMISSED);
+ } else {
+ Log.d(TAG, "was asked to remove Bubble, but didn't find the view! " + bubble);
+ }
}
// via BubbleData.Listener
@@ -531,7 +542,10 @@
* position of any bubble.
*/
// via BubbleData.Listener
- public void setSelectedBubble(Bubble bubbleToSelect) {
+ public void setSelectedBubble(@Nullable Bubble bubbleToSelect) {
+ if (DEBUG) {
+ Log.d(TAG, "setSelectedBubble: " + bubbleToSelect);
+ }
if (mExpandedBubble != null && mExpandedBubble.equals(bubbleToSelect)) {
return;
}
@@ -562,6 +576,9 @@
*/
// via BubbleData.Listener
public void setExpanded(boolean shouldExpand) {
+ if (DEBUG) {
+ Log.d(TAG, "setExpanded: " + shouldExpand);
+ }
boolean wasExpanded = mIsExpanded;
if (shouldExpand == wasExpanded) {
return;
@@ -586,6 +603,9 @@
*/
@Deprecated
void stackDismissed(int reason) {
+ if (DEBUG) {
+ Log.d(TAG, "stackDismissed: reason=" + reason);
+ }
mBubbleData.dismissAll(reason);
logBubbleEvent(null /* no bubble associated with bubble stack dismiss */,
StatsLog.BUBBLE_UICHANGED__ACTION__STACK_DISMISSED);
@@ -633,6 +653,9 @@
@Deprecated
@MainThread
void collapseStack() {
+ if (DEBUG) {
+ Log.d(TAG, "collapseStack()");
+ }
mBubbleData.setExpanded(false);
}
@@ -642,6 +665,9 @@
@Deprecated
@MainThread
void collapseStack(Runnable endRunnable) {
+ if (DEBUG) {
+ Log.d(TAG, "collapseStack(endRunnable)");
+ }
collapseStack();
// TODO - use the runnable at end of animation
endRunnable.run();
@@ -657,6 +683,9 @@
@Deprecated
@MainThread
void expandStack() {
+ if (DEBUG) {
+ Log.d(TAG, "expandStack()");
+ }
mBubbleData.setExpanded(true);
}
@@ -664,6 +693,9 @@
* Tell the stack to animate to collapsed or expanded state.
*/
private void animateExpansion(boolean shouldExpand) {
+ if (DEBUG) {
+ Log.d(TAG, "animateExpansion: shouldExpand=" + shouldExpand);
+ }
if (mIsExpanded != shouldExpand) {
hideFlyoutImmediate();
@@ -745,6 +777,9 @@
/** Called when a drag operation on an individual bubble has started. */
public void onBubbleDragStart(View bubble) {
+ if (DEBUG) {
+ Log.d(TAG, "onBubbleDragStart: bubble=" + bubble);
+ }
mExpandedAnimationController.prepareForBubbleDrag(bubble);
}
@@ -760,6 +795,9 @@
/** Called when a drag operation on an individual bubble has finished. */
public void onBubbleDragFinish(
View bubble, float x, float y, float velX, float velY, boolean dismissed) {
+ if (DEBUG) {
+ Log.d(TAG, "onBubbleDragFinish: bubble=" + bubble + ", dismissed=" + dismissed);
+ }
if (!mIsExpanded || mIsExpansionAnimating) {
return;
}
@@ -772,6 +810,9 @@
}
void onDragStart() {
+ if (DEBUG) {
+ Log.d(TAG, "onDragStart()");
+ }
if (mIsExpanded || mIsExpansionAnimating) {
return;
}
@@ -792,6 +833,9 @@
}
void onDragFinish(float x, float y, float velX, float velY) {
+ if (DEBUG) {
+ Log.d(TAG, "onDragFinish");
+ }
// TODO: Add fling to bottom to dismiss.
mIsDragging = false;
@@ -958,6 +1002,9 @@
}
private void updateExpandedBubble() {
+ if (DEBUG) {
+ Log.d(TAG, "updateExpandedBubble()");
+ }
mExpandedViewContainer.removeAllViews();
if (mExpandedBubble != null && mIsExpanded) {
mExpandedViewContainer.addView(mExpandedBubble.expandedView);
@@ -1036,7 +1083,9 @@
}
private void applyCurrentState() {
- Log.d(TAG, "applyCurrentState: mIsExpanded=" + mIsExpanded);
+ if (DEBUG) {
+ Log.d(TAG, "applyCurrentState: mIsExpanded=" + mIsExpanded);
+ }
mExpandedViewContainer.setVisibility(mIsExpanded ? VISIBLE : GONE);
if (mIsExpanded) {
// First update the view so that it calculates a new height (ensuring the y position
@@ -1075,10 +1124,14 @@
}
private void updatePointerPosition() {
- if (mExpandedBubble != null) {
- float pointerPosition = mExpandedBubble.iconView.getTranslationX()
- + (mExpandedBubble.iconView.getWidth() / 2f);
- mExpandedBubble.expandedView.setPointerPosition((int) pointerPosition);
+ if (DEBUG) {
+ Log.d(TAG, "updatePointerPosition()");
+ }
+ Bubble expandedBubble = getExpandedBubble();
+ if (expandedBubble != null) {
+ BubbleView iconView = expandedBubble.iconView;
+ float pointerPosition = iconView.getTranslationX() + (iconView.getWidth() / 2f);
+ expandedBubble.expandedView.setPointerPosition((int) pointerPosition);
}
}
@@ -1174,4 +1227,18 @@
}
return mExpandedBubble.expandedView.performBackPressIfNeeded();
}
+
+ /** For debugging only */
+ List<Bubble> getBubblesOnScreen() {
+ List<Bubble> bubbles = new ArrayList<>();
+ for (int i = 0; i < mBubbleContainer.getChildCount(); i++) {
+ View child = mBubbleContainer.getChildAt(i);
+ if (child instanceof BubbleView) {
+ String key = ((BubbleView) child).getKey();
+ Bubble bubble = mBubbleData.getBubbleWithKey(key);
+ bubbles.add(bubble);
+ }
+ }
+ return bubbles;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
index a51d46c..82e6279 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
@@ -37,9 +37,12 @@
/** Velocity required to dismiss a bubble without dragging it into the dismiss target. */
private static final float DISMISS_MIN_VELOCITY = 4000f;
+ private static final String TAG = "BubbleTouchHandler";
+
private final PointF mTouchDown = new PointF();
private final PointF mViewPositionOnTouchDown = new PointF();
private final BubbleStackView mStack;
+ private final BubbleData mBubbleData;
private BubbleController mController = Dependency.get(BubbleController.class);
private PipDismissViewController mDismissViewController;
@@ -60,10 +63,12 @@
/** View that was initially touched, when we received the first ACTION_DOWN event. */
private View mTouchedView;
- BubbleTouchHandler(Context context, BubbleStackView stackView) {
+ BubbleTouchHandler(BubbleStackView stackView,
+ BubbleData bubbleData, Context context) {
final int touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
mTouchSlopSquared = touchSlop * touchSlop;
mDismissViewController = new PipDismissViewController(context);
+ mBubbleData = bubbleData;
mStack = stackView;
}
@@ -80,7 +85,7 @@
// If this is an ACTION_OUTSIDE event, or the stack reported that we aren't touching
// anything, collapse the stack.
if (action == MotionEvent.ACTION_OUTSIDE || mTouchedView == null) {
- mStack.collapseStack();
+ mBubbleData.setExpanded(false);
resetForNextGesture();
return false;
}
@@ -151,8 +156,8 @@
mStack.onDragFinishAsDismiss();
} else if (isFlyout) {
// TODO(b/129768381): Expand if tapped, dismiss if swiped away.
- if (!mStack.isExpanded() && !mMovedEnough) {
- mStack.expandStack();
+ if (!mBubbleData.isExpanded() && !mMovedEnough) {
+ mBubbleData.setExpanded(true);
}
} else if (mMovedEnough) {
mVelocityTracker.computeCurrentVelocity(/* maxVelocity */ 1000);
@@ -170,15 +175,13 @@
}
}
} else if (mTouchedView == mStack.getExpandedBubbleView()) {
- mStack.collapseStack();
+ mBubbleData.setExpanded(false);
} else if (isStack) {
- if (mStack.isExpanded()) {
- mStack.collapseStack();
- } else {
- mStack.expandStack();
- }
+ // Toggle expansion
+ mBubbleData.setExpanded(!mBubbleData.isExpanded());
} else {
- mStack.setExpandedBubble(((BubbleView) mTouchedView).getKey());
+ final String key = ((BubbleView) mTouchedView).getKey();
+ mBubbleData.setSelectedBubble(mBubbleData.getBubbleWithKey(key));
}
resetForNextGesture();
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index 0607654..5196ec6 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -27,7 +27,6 @@
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.SysUiServiceProvider;
import com.android.systemui.SystemUIApplication;
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.dock.DockManager;
@@ -46,7 +45,7 @@
Context context = dozeService;
SensorManager sensorManager = Dependency.get(AsyncSensorManager.class);
AlarmManager alarmManager = context.getSystemService(AlarmManager.class);
- DockManager dockManager = SysUiServiceProvider.getComponent(context, DockManager.class);
+ DockManager dockManager = Dependency.get(DockManager.class);
DozeHost host = getHost(dozeService);
AmbientDisplayConfiguration config = new AmbientDisplayConfiguration(context);
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsColumnLayout.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsColumnLayout.java
new file mode 100644
index 0000000..5907028
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsColumnLayout.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.globalactions;
+
+import static com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE;
+import static com.android.systemui.util.leak.RotationUtils.ROTATION_NONE;
+import static com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.View;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.R;
+
+/**
+ * Grid-based implementation of the button layout created by the global actions dialog.
+ */
+public class GlobalActionsColumnLayout extends GlobalActionsLayout {
+ private boolean mLastSnap;
+
+ public GlobalActionsColumnLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ super.onLayout(changed, l, t, r, b);
+
+ post(() -> updateSnap());
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ @VisibleForTesting
+ protected boolean shouldReverseListItems() {
+ int rotation = getCurrentRotation();
+ if (rotation == ROTATION_NONE) {
+ return false;
+ }
+ if (getCurrentLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
+ return rotation == ROTATION_LANDSCAPE;
+ }
+ return rotation == ROTATION_SEASCAPE;
+ }
+
+ @Override
+ public void onUpdateList() {
+ super.onUpdateList();
+ updateChildOrdering();
+ }
+
+ private void updateChildOrdering() {
+ if (shouldReverseListItems()) {
+ getListView().bringToFront();
+ } else {
+ getSeparatedView().bringToFront();
+ }
+ }
+
+ /**
+ * Snap this layout to align with the power button.
+ */
+ @VisibleForTesting
+ protected void snapToPowerButton() {
+ int offset = getPowerButtonOffsetDistance();
+ switch (getCurrentRotation()) {
+ case (ROTATION_LANDSCAPE):
+ setPadding(offset, 0, 0, 0);
+ setGravity(Gravity.LEFT | Gravity.TOP);
+ break;
+ case (ROTATION_SEASCAPE):
+ setPadding(0, 0, offset, 0);
+ setGravity(Gravity.RIGHT | Gravity.BOTTOM);
+ break;
+ default:
+ setPadding(0, offset, 0, 0);
+ setGravity(Gravity.TOP | Gravity.RIGHT);
+ break;
+ }
+ }
+
+ /**
+ * Detach this layout from snapping to the power button and instead center along that edge.
+ */
+ @VisibleForTesting
+ protected void centerAlongEdge() {
+ switch (getCurrentRotation()) {
+ case (ROTATION_LANDSCAPE):
+ setPadding(0, 0, 0, 0);
+ setGravity(Gravity.CENTER_HORIZONTAL | Gravity.TOP);
+ break;
+ case (ROTATION_SEASCAPE):
+ setPadding(0, 0, 0, 0);
+ setGravity(Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
+ break;
+ default:
+ setPadding(0, 0, 0, 0);
+ setGravity(Gravity.CENTER_VERTICAL | Gravity.RIGHT);
+ break;
+ }
+ }
+
+ /**
+ * Determines the distance from the top of the screen to the power button.
+ */
+ @VisibleForTesting
+ protected int getPowerButtonOffsetDistance() {
+ return Math.round(getContext().getResources().getDimension(
+ R.dimen.global_actions_top_padding));
+ }
+
+ /**
+ * Check whether there is enough extra space below the dialog such that we can offset the top
+ * of the dialog from the top of the phone to line it up with the power button, then either
+ * snap the dialog to the power button or center it along the edge with snapToPowerButton.
+ */
+ @VisibleForTesting
+ protected boolean shouldSnapToPowerButton() {
+ int offsetSize = getPowerButtonOffsetDistance();
+ int dialogSize;
+ int screenSize;
+ View wrapper = getWrapper();
+ int rotation = getCurrentRotation();
+ if (rotation == ROTATION_NONE) {
+ dialogSize = wrapper.getMeasuredHeight();
+ screenSize = getMeasuredHeight();
+ } else {
+ dialogSize = wrapper.getMeasuredWidth();
+ screenSize = getMeasuredWidth();
+ }
+ return dialogSize + offsetSize < screenSize;
+ }
+
+ @VisibleForTesting
+ protected void updateSnap() {
+ boolean snap = shouldSnapToPowerButton();
+ if (snap != mLastSnap) {
+ if (snap) {
+ snapToPowerButton();
+ } else {
+ centerAlongEdge();
+ }
+ }
+ mLastSnap = snap;
+ }
+
+ @VisibleForTesting
+ protected float getGridItemSize() {
+ return getContext().getResources().getDimension(R.dimen.global_actions_grid_item_height);
+ }
+
+ @VisibleForTesting
+ protected float getAnimationDistance() {
+ return getGridItemSize() / 2;
+ }
+
+ @Override
+ public float getAnimationOffsetX() {
+ if (getCurrentRotation() == ROTATION_NONE) {
+ return getAnimationDistance();
+ }
+ return 0;
+ }
+
+ @Override
+ public float getAnimationOffsetY() {
+ switch (getCurrentRotation()) {
+ case ROTATION_LANDSCAPE:
+ return -getAnimationDistance();
+ case ROTATION_SEASCAPE:
+ return getAnimationDistance();
+ default: // Portrait
+ return 0;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 64511a0..afe905e 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -1583,13 +1583,20 @@
}
private int getGlobalActionsLayoutId(Context context) {
- if (isForceGridEnabled(context) || shouldUsePanel()) {
- if (RotationUtils.getRotation(context) == RotationUtils.ROTATION_SEASCAPE) {
+ boolean useGridLayout = isForceGridEnabled(context) || shouldUsePanel();
+ if (RotationUtils.getRotation(context) == RotationUtils.ROTATION_SEASCAPE) {
+ if (useGridLayout) {
return com.android.systemui.R.layout.global_actions_grid_seascape;
+ } else {
+ return com.android.systemui.R.layout.global_actions_column_seascape;
}
- return com.android.systemui.R.layout.global_actions_grid;
+ } else {
+ if (useGridLayout) {
+ return com.android.systemui.R.layout.global_actions_grid;
+ } else {
+ return com.android.systemui.R.layout.global_actions_column;
+ }
}
- return com.android.systemui.R.layout.global_actions_wrapped;
}
@Override
@@ -1712,7 +1719,7 @@
}
public void onRotate(int from, int to) {
- if (mShowing && (shouldUsePanel() || isForceGridEnabled(mContext))) {
+ if (mShowing) {
refreshDialog();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java
index 554ed73..e1462d1 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java
@@ -22,58 +22,23 @@
import android.content.Context;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.HardwareBgDrawable;
-import com.android.systemui.MultiListLayout;
-import com.android.systemui.util.leak.RotationUtils;
/**
* Grid-based implementation of the button layout created by the global actions dialog.
*/
-public class GlobalActionsGridLayout extends MultiListLayout {
-
- boolean mBackgroundsSet;
-
+public class GlobalActionsGridLayout extends GlobalActionsLayout {
public GlobalActionsGridLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
- private void setBackgrounds() {
- int gridBackgroundColor = getResources().getColor(
- com.android.systemui.R.color.global_actions_grid_background, null);
- int separatedBackgroundColor = getResources().getColor(
- com.android.systemui.R.color.global_actions_separated_background, null);
- HardwareBgDrawable listBackground = new HardwareBgDrawable(true, true, getContext());
- HardwareBgDrawable separatedBackground = new HardwareBgDrawable(true, true, getContext());
- listBackground.setTint(gridBackgroundColor);
- separatedBackground.setTint(separatedBackgroundColor);
- getListView().setBackground(listBackground);
- getSeparatedView().setBackground(separatedBackground);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
- // backgrounds set only once, the first time onMeasure is called after inflation
- if (getListView() != null && !mBackgroundsSet) {
- setBackgrounds();
- mBackgroundsSet = true;
- }
- }
-
@VisibleForTesting
- protected int getCurrentRotation() {
- return RotationUtils.getRotation(mContext);
- }
-
- @VisibleForTesting
- protected void setupListView(ListGridLayout listView, int itemCount) {
- listView.setExpectedCount(itemCount);
+ protected void setupListView() {
+ ListGridLayout listView = getListView();
+ listView.setExpectedCount(mAdapter.countListItems());
listView.setReverseSublists(shouldReverseSublists());
listView.setReverseItems(shouldReverseListItems());
listView.setSwapRowsAndColumns(shouldSwapRowsAndColumns());
@@ -81,29 +46,8 @@
@Override
public void onUpdateList() {
+ setupListView();
super.onUpdateList();
-
- ViewGroup separatedView = getSeparatedView();
- ListGridLayout listView = getListView();
- setupListView(listView, mAdapter.countListItems());
-
- for (int i = 0; i < mAdapter.getCount(); i++) {
- // generate the view item
- View v;
- boolean separated = mAdapter.shouldBeSeparated(i);
- if (separated) {
- v = mAdapter.getView(i, null, separatedView);
- } else {
- v = mAdapter.getView(i, null, listView);
- }
- Log.d("GlobalActionsGridLayout", "View: " + v);
-
- if (separated) {
- separatedView.addView(v);
- } else {
- listView.addItem(v);
- }
- }
updateSeparatedItemSize();
}
@@ -111,7 +55,8 @@
* If the separated view contains only one item, expand the bounds of that item to take up the
* entire view, so that the whole thing is touch-able.
*/
- private void updateSeparatedItemSize() {
+ @VisibleForTesting
+ protected void updateSeparatedItemSize() {
ViewGroup separated = getSeparatedView();
if (separated.getChildCount() == 0) {
return;
@@ -129,13 +74,24 @@
}
@Override
- protected ViewGroup getSeparatedView() {
- return findViewById(com.android.systemui.R.id.separated_button);
+ protected ListGridLayout getListView() {
+ return (ListGridLayout) super.getListView();
}
@Override
- protected ListGridLayout getListView() {
- return findViewById(android.R.id.list);
+ protected void removeAllListViews() {
+ ListGridLayout list = getListView();
+ if (list != null) {
+ list.removeAllItems();
+ }
+ }
+
+ @Override
+ protected void addToListView(View v, boolean reverse) {
+ ListGridLayout list = getListView();
+ if (list != null) {
+ list.addItem(v);
+ }
}
@Override
@@ -174,12 +130,7 @@
return true;
}
- /**
- * Determines whether the ListGridLayout should reverse the ordering of items within sublists.
- * Used for RTL languages to ensure that items appear in the same positions, without having to
- * override layoutDirection, which breaks Talkback ordering.
- */
- @VisibleForTesting
+ @Override
protected boolean shouldReverseListItems() {
int rotation = getCurrentRotation();
boolean reverse = false; // should we add items to parents in the reverse order?
@@ -187,20 +138,13 @@
|| rotation == ROTATION_SEASCAPE) {
reverse = !reverse; // if we're in portrait or seascape, reverse items
}
- if (getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
+ if (getCurrentLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
reverse = !reverse; // if we're in an RTL language, reverse items (again)
}
return reverse;
}
- /**
- * Not ued in this implementation of the Global Actions Menu, but necessary for some others.
- */
- @Override
- public void setDivisionView(View v) {
- // do nothing
- }
-
+ @VisibleForTesting
protected float getAnimationDistance() {
int rows = getListView().getRowCount();
float gridItemSize = getContext().getResources().getDimension(
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsLayout.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsLayout.java
new file mode 100644
index 0000000..f755a93
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsLayout.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.globalactions;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.HardwareBgDrawable;
+import com.android.systemui.MultiListLayout;
+import com.android.systemui.R;
+import com.android.systemui.util.leak.RotationUtils;
+
+import java.util.Locale;
+
+/**
+ * Grid-based implementation of the button layout created by the global actions dialog.
+ */
+public abstract class GlobalActionsLayout extends MultiListLayout {
+
+ boolean mBackgroundsSet;
+
+ public GlobalActionsLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ private void setBackgrounds() {
+ int gridBackgroundColor = getResources().getColor(
+ R.color.global_actions_grid_background, null);
+ int separatedBackgroundColor = getResources().getColor(
+ R.color.global_actions_separated_background, null);
+ HardwareBgDrawable listBackground = new HardwareBgDrawable(true, true, getContext());
+ HardwareBgDrawable separatedBackground = new HardwareBgDrawable(true, true, getContext());
+ listBackground.setTint(gridBackgroundColor);
+ separatedBackground.setTint(separatedBackgroundColor);
+ getListView().setBackground(listBackground);
+ getSeparatedView().setBackground(separatedBackground);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+ // backgrounds set only once, the first time onMeasure is called after inflation
+ if (getListView() != null && !mBackgroundsSet) {
+ setBackgrounds();
+ mBackgroundsSet = true;
+ }
+ }
+
+ protected void addToListView(View v, boolean reverse) {
+ if (reverse) {
+ getListView().addView(v, 0);
+ } else {
+ getListView().addView(v);
+ }
+ }
+
+ protected void addToSeparatedView(View v, boolean reverse) {
+ if (reverse) {
+ getSeparatedView().addView(v, 0);
+ } else {
+ getSeparatedView().addView(v);
+ }
+ }
+
+ @VisibleForTesting
+ protected int getCurrentLayoutDirection() {
+ return TextUtils.getLayoutDirectionFromLocale(Locale.getDefault());
+ }
+
+ @VisibleForTesting
+ protected int getCurrentRotation() {
+ return RotationUtils.getRotation(mContext);
+ }
+
+ /**
+ * Determines whether the ListGridLayout should reverse the ordering of items within sublists.
+ * Used for RTL languages to ensure that items appear in the same positions, without having to
+ * override layoutDirection, which breaks Talkback ordering.
+ */
+ protected abstract boolean shouldReverseListItems();
+
+ @Override
+ public void onUpdateList() {
+ super.onUpdateList();
+
+ ViewGroup separatedView = getSeparatedView();
+ ViewGroup listView = getListView();
+
+ for (int i = 0; i < mAdapter.getCount(); i++) {
+ // generate the view item
+ View v;
+ boolean separated = mAdapter.shouldBeSeparated(i);
+ if (separated) {
+ v = mAdapter.getView(i, null, separatedView);
+ } else {
+ v = mAdapter.getView(i, null, listView);
+ }
+ if (separated) {
+ addToSeparatedView(v, false);
+ } else {
+ addToListView(v, shouldReverseListItems());
+ }
+ }
+ }
+
+ @Override
+ protected ViewGroup getSeparatedView() {
+ return findViewById(R.id.separated_button);
+ }
+
+ @Override
+ protected ViewGroup getListView() {
+ return findViewById(android.R.id.list);
+ }
+
+ protected View getWrapper() {
+ return getChildAt(0);
+ }
+
+ /**
+ * Not used in this implementation of the Global Actions Menu, but necessary for some others.
+ */
+ @Override
+ public void setDivisionView(View v) {
+ // do nothing
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
index 89ecc6a..d50f294e4 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
@@ -43,7 +43,7 @@
*/
public class PipNotification {
private static final String TAG = "PipNotification";
- private static final String NOTIFICATION_TAG = PipNotification.class.getName();
+ private static final String NOTIFICATION_TAG = PipNotification.class.getSimpleName();
private static final boolean DEBUG = PipManager.DEBUG;
private static final String ACTION_MENU = "PipNotification.menu";
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 6adce83..9431f20 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -38,6 +38,7 @@
import android.service.notification.ZenModeConfig;
import android.text.format.DateUtils;
import android.util.AttributeSet;
+import android.util.Log;
import android.util.Pair;
import android.util.StatsLog;
import android.view.ContextThemeWrapper;
@@ -524,11 +525,11 @@
mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
AlarmClock.ACTION_SHOW_ALARMS), 0);
} else if (v == mNextAlarmContainer) {
- if (mNextAlarm.getShowIntent() != null
- && mNextAlarm.getShowIntent().getIntent() != null) {
+ if (mNextAlarm.getShowIntent() != null) {
mActivityStarter.postStartActivityDismissingKeyguard(
- mNextAlarm.getShowIntent().getIntent(), 0);
+ mNextAlarm.getShowIntent());
} else {
+ Log.d(TAG, "No PendingIntent for next alarm. Using default intent");
mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
AlarmClock.ACTION_SHOW_ALARMS), 0);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 3ace705..78c7cd4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -17,14 +17,12 @@
package com.android.systemui.recents;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
+import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_UP;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
-import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_DISABLE_SWIPE_UP;
-import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_SHOW_OVERVIEW_BUTTON;
-import static com.android.systemui.shared.system.NavigationBarCompat.InteractionType;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_INPUT_MONITOR;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SUPPORTS_WINDOW_CORNERS;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
@@ -32,9 +30,9 @@
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
import android.annotation.FloatRange;
+import android.app.ActivityTaskManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -60,7 +58,6 @@
import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.systemui.Dependency;
import com.android.systemui.Dumpable;
-import com.android.systemui.Prefs;
import com.android.systemui.SysUiServiceProvider;
import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
import com.android.systemui.shared.recents.IOverviewProxy;
@@ -102,10 +99,6 @@
// Max backoff caps at 5 mins
private static final long MAX_BACKOFF_MILLIS = 10 * 60 * 1000;
- // Default interaction flags if swipe up is disabled before connecting to launcher
- private static final int DEFAULT_DISABLE_SWIPE_UP_STATE = FLAG_DISABLE_SWIPE_UP
- | FLAG_SHOW_OVERVIEW_BUTTON;
-
private final Context mContext;
private final Handler mHandler;
private final Runnable mConnectionRunnable = this::internalConnectToCurrentUser;
@@ -118,7 +111,6 @@
private IOverviewProxy mOverviewProxy;
private int mConnectionBackoffAttempts;
- private @InteractionType int mInteractionFlags;
private @SystemUiStateFlags int mSysUiStateFlags;
private boolean mBound;
private boolean mIsEnabled;
@@ -151,6 +143,25 @@
}
@Override
+ public void stopScreenPinning() {
+ if (!verifyCaller("stopScreenPinning")) {
+ return;
+ }
+ long token = Binder.clearCallingIdentity();
+ try {
+ mHandler.post(() -> {
+ try {
+ ActivityTaskManager.getService().stopSystemLockTaskMode();
+ } catch (RemoteException e) {
+ Log.e(TAG_OPS, "Failed to stop screen pinning");
+ }
+ });
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
public void onStatusBarMotionEvent(MotionEvent event) {
if (!verifyCaller("onStatusBarMotionEvent")) {
return;
@@ -213,27 +224,6 @@
}
@Override
- public void setInteractionState(@InteractionType int flags) {
- if (!verifyCaller("setInteractionState")) {
- return;
- }
- long token = Binder.clearCallingIdentity();
- try {
- if (mInteractionFlags != flags) {
- mInteractionFlags = flags;
- mHandler.post(() -> {
- for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
- mConnectionCallbacks.get(i).onInteractionFlagsChanged(flags);
- }
- });
- }
- } finally {
- Prefs.putInt(mContext, Prefs.Key.QUICK_STEP_INTERACTION_FLAGS, mInteractionFlags);
- Binder.restoreCallingIdentity(token);
- }
- }
-
- @Override
public Rect getNonMinimizedSplitScreenSecondaryBounds() {
if (!verifyCaller("getNonMinimizedSplitScreenSecondaryBounds")) {
return null;
@@ -360,12 +350,6 @@
public void onReceive(Context context, Intent intent) {
updateEnabledState();
- // When launcher service is disabled, reset interaction flags because it is inactive
- if (!isEnabled()) {
- mInteractionFlags = getDefaultInteractionFlags();
- Prefs.remove(mContext, Prefs.Key.QUICK_STEP_INTERACTION_FLAGS);
- }
-
// Reconnect immediately, instead of waiting for resume to arrive.
startConnectionToCurrentUser();
}
@@ -459,8 +443,6 @@
com.android.internal.R.string.config_recentsComponentName));
mQuickStepIntent = new Intent(ACTION_QUICKSTEP)
.setPackage(mRecentsComponentName.getPackageName());
- mInteractionFlags = Prefs.getInt(mContext, Prefs.Key.QUICK_STEP_INTERACTION_FLAGS,
- getDefaultInteractionFlags());
mWindowCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(mContext.getResources());
mSupportsRoundedCornersOnWindows = ScreenDecorationsUtils
.supportsRoundedCornersOnWindows(mContext.getResources());
@@ -495,7 +477,12 @@
}
}
- public void setSystemUiStateFlag(int flag, boolean enabled) {
+ public void setSystemUiStateFlag(int flag, boolean enabled, int displayId) {
+ if (displayId != DEFAULT_DISPLAY) {
+ // Ignore non-default displays for now
+ return;
+ }
+
int newState = mSysUiStateFlags;
if (enabled) {
newState |= flag;
@@ -520,8 +507,6 @@
&& statusBar.getPanel().isFullyExpanded();
final boolean bouncerShowing = statusBar != null && statusBar.isBouncerShowing();
mSysUiStateFlags = 0;
- mSysUiStateFlags |= ActivityManagerWrapper.getInstance().isScreenPinningActive()
- ? SYSUI_STATE_SCREEN_PINNING : 0;
mSysUiStateFlags |= (navBarFragment != null && !navBarFragment.isNavBarWindowVisible())
? SYSUI_STATE_NAV_BAR_HIDDEN : 0;
mSysUiStateFlags |= panelExpanded
@@ -633,7 +618,6 @@
public void addCallback(OverviewProxyListener listener) {
mConnectionCallbacks.add(listener);
listener.onConnectionChanged(mOverviewProxy != null);
- listener.onInteractionFlagsChanged(mInteractionFlags);
listener.onBackButtonAlphaChanged(mBackButtonAlpha, false);
}
@@ -643,7 +627,7 @@
}
public boolean shouldShowSwipeUpUI() {
- return isEnabled() && ((mInteractionFlags & FLAG_DISABLE_SWIPE_UP) == 0);
+ return isEnabled() && !QuickStepContract.isLegacyMode(mNavBarMode);
}
public boolean isEnabled() {
@@ -654,10 +638,6 @@
return mOverviewProxy;
}
- public int getInteractionFlags() {
- return mInteractionFlags;
- }
-
private void disconnectFromLauncherService() {
if (mBound) {
// Always unbind the service (ie. if called through onNullBinding or onBindingDied)
@@ -673,13 +653,6 @@
}
}
- private int getDefaultInteractionFlags() {
- // If there is no settings available use device default or get it from settings
- return QuickStepContract.isLegacyMode(mNavBarMode)
- ? DEFAULT_DISABLE_SWIPE_UP_STATE
- : 0;
- }
-
private void notifyBackButtonAlphaChanged(float alpha, boolean animate) {
for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
mConnectionCallbacks.get(i).onBackButtonAlphaChanged(alpha, animate);
@@ -745,7 +718,6 @@
pw.print(" isCurrentUserSetup="); pw.println(mDeviceProvisionedController
.isCurrentUserSetup());
pw.print(" connectionBackoffAttempts="); pw.println(mConnectionBackoffAttempts);
- pw.print(" interactionFlags="); pw.println(mInteractionFlags);
pw.print(" quickStepIntent="); pw.println(mQuickStepIntent);
pw.print(" quickStepIntentResolved="); pw.println(isEnabled());
@@ -755,7 +727,6 @@
public interface OverviewProxyListener {
default void onConnectionChanged(boolean isConnected) {}
default void onQuickStepStarted() {}
- default void onInteractionFlagsChanged(@InteractionType int flags) {}
default void onOverviewShown(boolean fromHome) {}
default void onQuickScrubStarted() {}
default void onBackButtonAlphaChanged(float alpha, boolean animate) {}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
index 07391ed..c3c0d63 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
@@ -16,7 +16,6 @@
package com.android.systemui.recents;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
import static com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE;
import static com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE;
@@ -48,14 +47,17 @@
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.SysUiServiceProvider;
+import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.WindowManagerWrapper;
import com.android.systemui.statusbar.phone.NavigationBarView;
+import com.android.systemui.statusbar.phone.NavigationModeController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.util.leak.RotationUtils;
import java.util.ArrayList;
-public class ScreenPinningRequest implements View.OnClickListener {
+public class ScreenPinningRequest implements View.OnClickListener,
+ NavigationModeController.ModeChangedListener {
private final Context mContext;
@@ -64,6 +66,7 @@
private final OverviewProxyService mOverviewProxyService;
private RequestWindowView mRequestWindow;
+ private int mNavBarMode;
// Id of task to be pinned or locked.
private int taskId;
@@ -75,6 +78,7 @@
mWindowManager = (WindowManager)
mContext.getSystemService(Context.WINDOW_SERVICE);
mOverviewProxyService = Dependency.get(OverviewProxyService.class);
+ mNavBarMode = Dependency.get(NavigationModeController.class).addListener(this);
}
public void clearPrompt() {
@@ -103,6 +107,11 @@
mWindowManager.addView(mRequestWindow, lp);
}
+ @Override
+ public void onNavigationModeChanged(int mode) {
+ mNavBarMode = mode;
+ }
+
public void onConfigurationChanged() {
if (mRequestWindow != null) {
mRequestWindow.onConfigurationChanged();
@@ -129,7 +138,6 @@
if (v.getId() == R.id.screen_pinning_ok_button || mRequestWindow == v) {
try {
ActivityTaskManager.getService().startSystemLockTaskMode(taskId);
- mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_SCREEN_PINNING, true);
} catch (RemoteException e) {}
}
clearPrompt();
@@ -224,7 +232,9 @@
mLayout.findViewById(R.id.screen_pinning_text_area)
.setLayoutDirection(View.LAYOUT_DIRECTION_LOCALE);
View buttons = mLayout.findViewById(R.id.screen_pinning_buttons);
- if (WindowManagerWrapper.getInstance().hasSoftNavigationBar(mContext.getDisplayId())) {
+ WindowManagerWrapper wm = WindowManagerWrapper.getInstance();
+ if (!QuickStepContract.isGesturalMode(mNavBarMode)
+ && wm.hasSoftNavigationBar(mContext.getDisplayId())) {
buttons.setLayoutDirection(View.LAYOUT_DIRECTION_LOCALE);
swapChildrenIfRtlAndVertical(buttons);
} else {
@@ -248,7 +258,9 @@
&& navigationBarView.isRecentsButtonVisible();
boolean touchExplorationEnabled = mAccessibilityService.isTouchExplorationEnabled();
int descriptionStringResId;
- if (recentsVisible) {
+ if (QuickStepContract.isGesturalMode(mNavBarMode)) {
+ descriptionStringResId = R.string.screen_pinning_description_gestural;
+ } else if (recentsVisible) {
mLayout.findViewById(R.id.screen_pinning_recents_group).setVisibility(VISIBLE);
mLayout.findViewById(R.id.screen_pinning_home_bg_light).setVisibility(INVISIBLE);
mLayout.findViewById(R.id.screen_pinning_home_bg).setVisibility(INVISIBLE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index a688f36..9f8ab61 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -175,9 +175,11 @@
* @param fullscreenStackBounds The current bounds of the fullscreen stack, in screen
* coordinates.
* @param dockedStackBounds The current bounds of the docked stack, in screen coordinates.
+ * @param navbarColorManagedByIme {@code true} if navigation bar color is managed by IME.
*/
default void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis,
- int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
+ int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds,
+ boolean navbarColorManagedByIme) {
}
/**
@@ -459,7 +461,8 @@
@Override
public void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis,
- int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
+ int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds,
+ boolean navbarColorManagedByIme) {
synchronized (mLock) {
// Don't coalesce these, since it might have one time flags set such as
// STATUS_BAR_UNHIDE which might get lost.
@@ -469,6 +472,7 @@
args.argi3 = fullscreenStackVis;
args.argi4 = dockedStackVis;
args.argi5 = mask;
+ args.argi6 = navbarColorManagedByIme ? 1 : 0;
args.arg1 = fullscreenStackBounds;
args.arg2 = dockedStackBounds;
mHandler.obtainMessage(MSG_SET_SYSTEMUI_VISIBILITY, args).sendToTarget();
@@ -879,7 +883,8 @@
args = (SomeArgs) msg.obj;
for (int i = 0; i < mCallbacks.size(); i++) {
mCallbacks.get(i).setSystemUiVisibility(args.argi1, args.argi2, args.argi3,
- args.argi4, args.argi5, (Rect) args.arg1, (Rect) args.arg2);
+ args.argi4, args.argi5, (Rect) args.arg1, (Rect) args.arg2,
+ args.argi6 == 1);
}
args.recycle();
break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 21f0c1e..fcbb416 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -143,11 +143,6 @@
StatusBarStateController statusBarStateController,
KeyguardUpdateMonitor keyguardUpdateMonitor) {
mContext = context;
- mIndicationArea = indicationArea;
- mTextView = indicationArea.findViewById(R.id.keyguard_indication_text);
- mInitialTextColorState = mTextView != null ?
- mTextView.getTextColors() : ColorStateList.valueOf(Color.WHITE);
- mDisclosure = indicationArea.findViewById(R.id.keyguard_indication_enterprise_disclosure);
mLockIcon = lockIcon;
mShadeController = shadeController;
mAccessibilityController = accessibilityController;
@@ -172,6 +167,7 @@
mDevicePolicyManager = (DevicePolicyManager) context.getSystemService(
Context.DEVICE_POLICY_SERVICE);
+ setIndicationArea(indicationArea);
updateDisclosure();
mKeyguardUpdateMonitor.registerCallback(getKeyguardCallback());
@@ -180,17 +176,13 @@
mUnlockMethodCache.addListener(this);
}
- /**
- * Used by {@link com.android.systemui.statusbar.phone.StatusBar} to give the indication
- * controller a chance to unregister itself as a receiver.
- *
- * //TODO: This can probably be converted to a fragment and not have to be manually recreated
- */
- public void destroy() {
- mKeyguardUpdateMonitor.removeCallback(mTickReceiver);
- mKeyguardUpdateMonitor.removeCallback(getKeyguardCallback());
- mStatusBarStateController.removeCallback(this);
- mUnlockMethodCache.removeListener(this);
+ public void setIndicationArea(ViewGroup indicationArea) {
+ mIndicationArea = indicationArea;
+ mTextView = indicationArea.findViewById(R.id.keyguard_indication_text);
+ mInitialTextColorState = mTextView != null ?
+ mTextView.getTextColors() : ColorStateList.valueOf(Color.WHITE);
+ mDisclosure = indicationArea.findViewById(R.id.keyguard_indication_enterprise_disclosure);
+ updateIndication(false /* animate */);
}
private boolean handleLockLongClick(View view) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
index 85848ca..bd25209 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
@@ -53,7 +53,7 @@
@Singleton
public class NavigationBarController implements Callbacks {
- private static final String TAG = NavigationBarController.class.getName();
+ private static final String TAG = NavigationBarController.class.getSimpleName();
private final Context mContext;
private final Handler mHandler;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index fa22367..1615e65 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -39,6 +39,7 @@
import android.os.Trace;
import android.os.UserHandle;
import android.provider.DeviceConfig;
+import android.provider.DeviceConfig.Properties;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
@@ -118,15 +119,18 @@
private ImageView mBackdropBack;
private boolean mShowCompactMediaSeekbar;
- private final DeviceConfig.OnPropertyChangedListener mPropertyChangedListener =
- new DeviceConfig.OnPropertyChangedListener() {
+ private final DeviceConfig.OnPropertiesChangedListener mPropertiesChangedListener =
+ new DeviceConfig.OnPropertiesChangedListener() {
@Override
- public void onPropertyChanged(String namespace, String name, String value) {
- if (SystemUiDeviceConfigFlags.COMPACT_MEDIA_SEEKBAR_ENABLED.equals(name)) {
- if (DEBUG_MEDIA) {
- Log.v(TAG, "DEBUG_MEDIA: compact media seekbar flag updated: " + value);
+ public void onPropertiesChanged(Properties properties) {
+ for (String name : properties.getKeyset()) {
+ if (SystemUiDeviceConfigFlags.COMPACT_MEDIA_SEEKBAR_ENABLED.equals(name)) {
+ String value = properties.getString(name, null);
+ if (DEBUG_MEDIA) {
+ Log.v(TAG, "DEBUG_MEDIA: compact media seekbar flag updated: " + value);
+ }
+ mShowCompactMediaSeekbar = "true".equals(value);
}
- mShowCompactMediaSeekbar = "true".equals(value);
}
}
};
@@ -189,9 +193,9 @@
DeviceConfig.getProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.COMPACT_MEDIA_SEEKBAR_ENABLED));
- DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI,
+ DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI,
mContext.getMainExecutor(),
- mPropertyChangedListener);
+ mPropertiesChangedListener);
}
public void setUpWithPresenter(NotificationPresenter presenter) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
index 333239e..0d9f4e7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
@@ -30,6 +30,7 @@
import android.view.RemoteAnimationTarget;
import android.view.SyncRtSurfaceTransactionApplier;
import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
+import android.view.View;
import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.systemui.Interpolators;
@@ -79,11 +80,12 @@
}
public RemoteAnimationAdapter getLaunchAnimation(
- ExpandableNotificationRow sourceNotification, boolean occluded) {
- if (!mCallback.areLaunchAnimationsEnabled() || occluded) {
+ View sourceView, boolean occluded) {
+ if (!(sourceView instanceof ExpandableNotificationRow) || !mCallback.areLaunchAnimationsEnabled() || occluded) {
return null;
}
- AnimationRunner animationRunner = new AnimationRunner(sourceNotification);
+ AnimationRunner animationRunner = new AnimationRunner(
+ (ExpandableNotificationRow) sourceView);
return new RemoteAnimationAdapter(animationRunner, ANIMATION_DURATION,
ANIMATION_DURATION - 150 /* statusBarTransitionDelay */);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
index 1f8ca37..d49f168 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
@@ -40,8 +40,11 @@
import android.metrics.LogMaker;
import android.os.Handler;
import android.os.RemoteException;
+import android.provider.Settings;
import android.service.notification.StatusBarNotification;
import android.text.TextUtils;
+import android.transition.AutoTransition;
+import android.transition.TransitionManager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
@@ -88,6 +91,8 @@
// standard controls
private static final int ACTION_ALERT = 5;
+ private static final int BUTTON_ANIM_TIME_MS = 200;
+
private INotificationManager mINotificationManager;
private PackageManager mPm;
private MetricsLogger mMetricsLogger;
@@ -102,6 +107,8 @@
private boolean mWasShownHighPriority;
private boolean mShowOnLockscreen;
private boolean mShowInStatusBar;
+ private boolean mPressedApply;
+
/**
* The last importance level chosen by the user. Null if the user has not chosen an importance
* level; non-null once the user takes an action which indicates an explicit preference.
@@ -132,7 +139,7 @@
private OnClickListener mOnAlert = v -> {
mExitReason = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING;
mChosenImportance = IMPORTANCE_DEFAULT;
- setImportanceSummary(ACTION_ALERT);
+ setImportanceSummary(ACTION_ALERT, true);
updateButtons(ACTION_ALERT);
};
@@ -140,12 +147,13 @@
private OnClickListener mOnSilent = v -> {
mExitReason = NotificationCounters.BLOCKING_HELPER_DELIVER_SILENTLY;
mChosenImportance = IMPORTANCE_LOW;
- setImportanceSummary(ACTION_TOGGLE_SILENT);
+ setImportanceSummary(ACTION_TOGGLE_SILENT, true);
updateButtons(ACTION_TOGGLE_SILENT);
};
// used by standard ui
private OnClickListener mOnDismissSettings = v -> {
+ mPressedApply = true;
closeControls(v);
};
@@ -294,7 +302,8 @@
mShowInStatusBar = !mINotificationManager.shouldHideSilentStatusIcons(
mContext.getPackageName());
- // TODO: b/128445911 use show on lockscreen setting
+ mShowOnLockscreen = Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 0) == 1;
bindHeader();
bindChannelDetails();
@@ -334,6 +343,7 @@
findViewById(R.id.non_configurable_multichannel_text).setVisibility(GONE);
findViewById(R.id.interruptiveness_settings).setVisibility(GONE);
((TextView) findViewById(R.id.done)).setText(R.string.inline_done_button);
+ findViewById(R.id.turn_off_notifications).setVisibility(GONE);
} else if (mNumUniqueChannelsInRow > 1) {
findViewById(R.id.non_configurable_text).setVisibility(GONE);
findViewById(R.id.interruptiveness_settings).setVisibility(GONE);
@@ -360,10 +370,10 @@
if (mWasShownHighPriority) {
updateButtons(ACTION_ALERT);
- setImportanceSummary(ACTION_ALERT);
+ setImportanceSummary(ACTION_ALERT, false);
} else {
updateButtons(ACTION_TOGGLE_SILENT);
- setImportanceSummary(ACTION_TOGGLE_SILENT);
+ setImportanceSummary(ACTION_TOGGLE_SILENT, false);
}
}
@@ -484,14 +494,6 @@
}
}
- private boolean hasImportanceChanged() {
- return mSingleNotificationChannel != null
- && mChosenImportance != null
- && (mStartingChannelImportance == IMPORTANCE_UNSPECIFIED
- || (mWasShownHighPriority && mChosenImportance < IMPORTANCE_DEFAULT)
- || (!mWasShownHighPriority && mChosenImportance >= IMPORTANCE_DEFAULT));
- }
-
private void saveImportance() {
if (!mIsNonblockable
|| mExitReason != NotificationCounters.BLOCKING_HELPER_STOP_NOTIFICATIONS) {
@@ -526,8 +528,8 @@
}
private void updateButtons(int blockState) {
- TextView silence = findViewById(R.id.silence);
- TextView alert = findViewById(R.id.alert);
+ View silence = findViewById(R.id.silence);
+ View alert = findViewById(R.id.alert);
TextView done = findViewById(R.id.done);
switch (blockState) {
case ACTION_TOGGLE_SILENT:
@@ -549,22 +551,28 @@
}
}
- private void updateButtons(TextView selected, TextView unselected) {
+ private void updateButtons(View selected, View unselected) {
selected.setBackground(mSelectedBackground);
selected.setSelected(true);
- selected.setTextAppearance(
- R.style.TextAppearance_NotificationImportanceButton_Selected);
unselected.setBackground(mUnselectedBackground);
unselected.setSelected(false);
- unselected.setTextAppearance(
- R.style.TextAppearance_NotificationImportanceButton_Unselected);
}
- void setImportanceSummary(int blockState) {
- TextView view = findViewById(R.id.description);
+ void setImportanceSummary(int blockState, boolean userTriggered) {
+ if (userTriggered) {
+ AutoTransition transition = new AutoTransition();
+ transition.setDuration(BUTTON_ANIM_TIME_MS);
+ TransitionManager.beginDelayedTransition(this, transition);
+ }
if (blockState == ACTION_ALERT) {
+ TextView view = findViewById(R.id.alert_summary);
+ view.setVisibility(VISIBLE);
+ findViewById(R.id.silence_summary).setVisibility(GONE);
view.setText(R.string.notification_channel_summary_default);
} else {
+ TextView view = findViewById(R.id.silence_summary);
+ view.setVisibility(VISIBLE);
+ findViewById(R.id.alert_summary).setVisibility(GONE);
if (mShowInStatusBar) {
if (mShowOnLockscreen) {
view.setText(R.string.notification_channel_summary_low_status_lock);
@@ -742,12 +750,12 @@
@Override
public boolean willBeRemoved() {
- return hasImportanceChanged();
+ return false;
}
@Override
public boolean shouldBeSaved() {
- return hasImportanceChanged();
+ return mPressedApply;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
index ef7d20c..73f7732 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
@@ -42,7 +42,6 @@
import com.android.systemui.R;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.statusbar.AlphaOptimizedImageView;
-import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.row.NotificationGuts.GutsContent;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
@@ -80,7 +79,7 @@
private OnMenuEventListener mMenuListener;
private boolean mDismissRtl;
private boolean mIsForeground;
- private final boolean mIsUsingNewInterruptionModel;
+ private final boolean mIsUsingBidirectionalSwipe;
private ValueAnimator mFadeAnimator;
private boolean mAnimating;
@@ -113,12 +112,19 @@
private boolean mIsUserTouching;
public NotificationMenuRow(Context context) {
+ //TODO: (b/131242807) not using bidirectional swipe for now
+ this(context, false);
+ }
+
+ // Only needed for testing until we want to turn bidirectional swipe back on
+ @VisibleForTesting
+ NotificationMenuRow(Context context, boolean isUsingBidirectionalSwipe) {
mContext = context;
mShouldShowMenu = context.getResources().getBoolean(R.bool.config_showNotificationGear);
mHandler = new Handler(Looper.getMainLooper());
mLeftMenuItems = new ArrayList<>();
mRightMenuItems = new ArrayList<>();
- mIsUsingNewInterruptionModel = NotificationUtils.useNewInterruptionModel(mContext);
+ mIsUsingBidirectionalSwipe = isUsingBidirectionalSwipe;
}
@Override
@@ -255,13 +261,13 @@
mSnoozeItem = createSnoozeItem(mContext);
}
mAppOpsItem = createAppOpsItem(mContext);
- if (mIsUsingNewInterruptionModel) {
+ if (mIsUsingBidirectionalSwipe) {
mInfoItem = createInfoItem(mContext, !mParent.getEntry().isHighPriority());
} else {
mInfoItem = createInfoItem(mContext);
}
- if (!mIsUsingNewInterruptionModel) {
+ if (!mIsUsingBidirectionalSwipe) {
if (!isForeground) {
mRightMenuItems.add(mSnoozeItem);
}
@@ -618,12 +624,12 @@
@Override
public boolean shouldShowGutsOnSnapOpen() {
- return mIsUsingNewInterruptionModel;
+ return mIsUsingBidirectionalSwipe;
}
@Override
public MenuItem menuItemToExposeOnSnap() {
- return mIsUsingNewInterruptionModel ? mInfoItem : null;
+ return mIsUsingBidirectionalSwipe ? mInfoItem : null;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index ebda585..7a9da6b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -6355,13 +6355,8 @@
@Override
public boolean canChildBeDismissedInDirection(View v, boolean isRightOrDown) {
- boolean isValidDirection;
- if (NotificationUtils.useNewInterruptionModel(mContext)) {
- isValidDirection = mDismissRtl ? !isRightOrDown : isRightOrDown;
- } else {
- isValidDirection = true;
- }
- return isValidDirection && canChildBeDismissed(v);
+ //TODO: b/131242807 for why this doesn't do anything with direction
+ return canChildBeDismissed(v);
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java
index fdf8cce..5912cd7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java
@@ -95,7 +95,8 @@
@Override
public void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis,
- int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
+ int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds,
+ boolean navbarColorManagedByIme) {
if (displayId != mDisplayId) {
return;
}
@@ -119,7 +120,7 @@
if (mSystemUiVisibility != newVal) {
mCommandQueue.setSystemUiVisibility(mDisplayId, mSystemUiVisibility,
fullscreenStackVis, dockedStackVis, mask, fullscreenStackBounds,
- dockedStackBounds);
+ dockedStackBounds, navbarColorManagedByIme);
}
notifySystemUiVisibilityChanged(mSystemUiVisibility);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
index 5f5fad3..6a93c7c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
@@ -47,7 +47,7 @@
private Boolean mLongClickable;
private Float mAlpha;
private Float mDarkIntensity;
- private Integer mVisibility = -1;
+ private Integer mVisibility = View.VISIBLE;
private Boolean mDelayTouchFeedback;
private KeyButtonDrawable mImageDrawable;
private View mCurrentView;
@@ -86,7 +86,7 @@
if (mAlpha != null) {
view.setAlpha(mAlpha);
}
- if (mVisibility != null && mVisibility != -1) {
+ if (mVisibility != null) {
view.setVisibility(mVisibility);
}
if (mAccessibilityDelegate != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java
index 541c142..5bc17f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java
@@ -51,7 +51,7 @@
* Reload the drawable from resource id, should reapply the previous dark intensity.
*/
public void updateIcon() {
- if (getCurrentView() == null || !getCurrentView().isAttachedToWindow()) {
+ if (getCurrentView() == null || !getCurrentView().isAttachedToWindow() || mIconResId == 0) {
return;
}
final KeyButtonDrawable currentDrawable = getImageDrawable();
@@ -92,7 +92,7 @@
setVisibility(View.VISIBLE);
return true;
}
- return mGroup.setButtonVisiblity(getId(), true /* visible */) == View.VISIBLE;
+ return mGroup.setButtonVisibility(getId(), true /* visible */) == View.VISIBLE;
}
/**
@@ -104,7 +104,7 @@
setVisibility(View.INVISIBLE);
return false;
}
- return mGroup.setButtonVisiblity(getId(), false /* visible */) != View.VISIBLE;
+ return mGroup.setButtonVisibility(getId(), false /* visible */) != View.VISIBLE;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButtonGroup.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButtonGroup.java
index 02b660f..9e843f9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButtonGroup.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButtonGroup.java
@@ -37,7 +37,7 @@
/**
* Add a contextual button to the group. The order of adding increases in its priority. The
* priority is used to determine which button should be visible when setting multiple button's
- * visibility {@see setButtonVisiblity}.
+ * visibility {@see setButtonVisibility}.
* @param button the button added to the group
*/
public void addButton(@NonNull ContextualButton button) {
@@ -71,7 +71,7 @@
* @return if the button is visible after operation
* @throws RuntimeException if the input id does not match any of the ids in the group
*/
- public int setButtonVisiblity(@IdRes int buttonResId, boolean visible) {
+ public int setButtonVisibility(@IdRes int buttonResId, boolean visible) {
final int index = getContextButtonIndex(buttonResId);
if (index == INVALID_INDEX) {
throw new RuntimeException("Cannot find the button id of " + buttonResId
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 5b464a9..80d36a1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -133,7 +133,6 @@
private LockPatternUtils mLockPatternUtils;
private FlashlightController mFlashlightController;
private PreviewInflater mPreviewInflater;
- private KeyguardIndicationController mIndicationController;
private AccessibilityController mAccessibilityController;
private StatusBar mStatusBar;
private KeyguardAffordanceHelper mAffordanceHelper;
@@ -221,7 +220,6 @@
};
public void initFrom(KeyguardBottomAreaView oldBottomArea) {
- setKeyguardIndicationController(oldBottomArea.mIndicationController);
setStatusBar(oldBottomArea.mStatusBar);
}
@@ -707,15 +705,6 @@
}
};
- public void setKeyguardIndicationController(
- KeyguardIndicationController keyguardIndicationController) {
- mIndicationController = keyguardIndicationController;
- }
-
- public void showTransientIndication(int id) {
- mIndicationController.showTransientIndication(id);
- }
-
public void updateLeftAffordance() {
updateLeftAffordanceIcon();
updateLeftPreview();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
index b590ca7..b0b656a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
@@ -79,6 +79,9 @@
private final Rect mLastDockedBounds = new Rect();
private boolean mQsCustomizing;
+ private boolean mDirectReplying;
+ private boolean mNavbarColorManagedByIme;
+
@Inject
public LightBarController(Context ctx, DarkIconDispatcher darkIconDispatcher,
BatteryController batteryController) {
@@ -100,7 +103,7 @@
public void onSystemUiVisibilityChanged(int fullscreenStackVis, int dockedStackVis,
int mask, Rect fullscreenStackBounds, Rect dockedStackBounds, boolean sbModeChanged,
- int statusBarMode) {
+ int statusBarMode, boolean navbarColorManagedByIme) {
int oldFullscreen = mFullscreenStackVisibility;
int newFullscreen = (oldFullscreen & ~mask) | (fullscreenStackVis & mask);
int diffFullscreen = newFullscreen ^ oldFullscreen;
@@ -122,12 +125,13 @@
mFullscreenStackVisibility = newFullscreen;
mDockedStackVisibility = newDocked;
mLastStatusBarMode = statusBarMode;
+ mNavbarColorManagedByIme = navbarColorManagedByIme;
mLastFullscreenBounds.set(fullscreenStackBounds);
mLastDockedBounds.set(dockedStackBounds);
}
public void onNavigationVisibilityChanged(int vis, int mask, boolean nbModeChanged,
- int navigationBarMode) {
+ int navigationBarMode, boolean navbarColorManagedByIme) {
int oldVis = mSystemUiVisibility;
int newVis = (oldVis & ~mask) | (vis & mask);
int diffVis = newVis ^ oldVis;
@@ -136,21 +140,24 @@
boolean last = mNavigationLight;
mHasLightNavigationBar = isLight(vis, navigationBarMode,
View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
- mNavigationLight = mHasLightNavigationBar && !mForceDarkForScrim && !mQsCustomizing;
+ mNavigationLight = mHasLightNavigationBar
+ && (mDirectReplying && mNavbarColorManagedByIme || !mForceDarkForScrim)
+ && !mQsCustomizing;
if (mNavigationLight != last) {
updateNavigation();
}
}
mSystemUiVisibility = newVis;
mLastNavigationBarMode = navigationBarMode;
+ mNavbarColorManagedByIme = navbarColorManagedByIme;
}
private void reevaluate() {
onSystemUiVisibilityChanged(mFullscreenStackVisibility,
mDockedStackVisibility, 0 /* mask */, mLastFullscreenBounds, mLastDockedBounds,
- true /* sbModeChange*/, mLastStatusBarMode);
+ true /* sbModeChange*/, mLastStatusBarMode, mNavbarColorManagedByIme);
onNavigationVisibilityChanged(mSystemUiVisibility, 0 /* mask */, true /* nbModeChanged */,
- mLastNavigationBarMode);
+ mLastNavigationBarMode, mNavbarColorManagedByIme);
}
public void setQsCustomizing(boolean customizing) {
@@ -159,6 +166,16 @@
reevaluate();
}
+ /**
+ * Sets whether the direct-reply is in use or not.
+ * @param directReplying {@code true} when the direct-reply is in-use.
+ */
+ public void setDirectReplying(boolean directReplying) {
+ if (mDirectReplying == directReplying) return;
+ mDirectReplying = directReplying;
+ reevaluate();
+ }
+
public void setScrimState(ScrimState scrimState, float scrimBehindAlpha,
GradientColors scrimInFrontColor) {
boolean forceDarkForScrimLast = mForceDarkForScrim;
@@ -260,7 +277,9 @@
pw.print(" mLastNavigationBarMode="); pw.println(mLastNavigationBarMode);
pw.print(" mForceDarkForScrim="); pw.print(mForceDarkForScrim);
- pw.print(" mQsCustomizing="); pw.println(mQsCustomizing);
+ pw.print(" mQsCustomizing="); pw.print(mQsCustomizing);
+ pw.print(" mDirectReplying="); pw.println(mDirectReplying);
+ pw.print(" mNavbarColorManagedByIme="); pw.println(mNavbarColorManagedByIme);
pw.println();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index 586e82c..a831a5d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -31,10 +31,13 @@
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityNodeInfo;
+import androidx.annotation.Nullable;
+
import com.android.internal.graphics.ColorUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.R;
+import com.android.systemui.dock.DockManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.KeyguardAffordanceView;
import com.android.systemui.statusbar.policy.AccessibilityController;
@@ -62,6 +65,7 @@
private final UnlockMethodCache mUnlockMethodCache;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final AccessibilityController mAccessibilityController;
+ private final DockManager mDockManager;
private int mLastState = 0;
private boolean mTransientBiometricsError;
@@ -72,13 +76,26 @@
private boolean mPulsing;
private boolean mDozing;
private boolean mBouncerVisible;
+ private boolean mDocked;
private boolean mLastDozing;
private boolean mLastPulsing;
private boolean mLastBouncerVisible;
private int mIconColor;
+ private float mDozeAmount;
private final Runnable mDrawOffTimeout = () -> update(true /* forceUpdate */);
- private float mDozeAmount;
+ private final DockManager.DockEventListener mDockEventListener =
+ new DockManager.DockEventListener() {
+ @Override
+ public void onEvent(int event) {
+ boolean docked = event == DockManager.STATE_DOCKED
+ || event == DockManager.STATE_DOCKED_HIDE;
+ if (docked != mDocked) {
+ mDocked = docked;
+ update(true /* force */);
+ }
+ }
+ };
private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
new KeyguardUpdateMonitorCallback() {
@@ -115,7 +132,8 @@
public LockIcon(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
StatusBarStateController statusBarStateController,
ConfigurationController configurationController,
- AccessibilityController accessibilityController) {
+ AccessibilityController accessibilityController,
+ @Nullable DockManager dockManager) {
super(context, attrs);
mContext = context;
mUnlockMethodCache = UnlockMethodCache.getInstance(context);
@@ -123,6 +141,7 @@
mAccessibilityController = accessibilityController;
mConfigurationController = configurationController;
mStatusBarStateController = statusBarStateController;
+ mDockManager = dockManager;
}
@Override
@@ -132,6 +151,9 @@
mConfigurationController.addCallback(this);
mKeyguardUpdateMonitor.registerCallback(mUpdateMonitorCallback);
mUnlockMethodCache.addListener(this);
+ if (mDockManager != null) {
+ mDockManager.addListener(mDockEventListener);
+ }
onThemeChanged();
}
@@ -142,6 +164,9 @@
mConfigurationController.removeCallback(this);
mKeyguardUpdateMonitor.removeCallback(mUpdateMonitorCallback);
mUnlockMethodCache.removeListener(this);
+ if (mDockManager != null) {
+ mDockManager.removeListener(mDockEventListener);
+ }
}
@Override
@@ -237,7 +262,8 @@
mLastBouncerVisible = mBouncerVisible;
}
- setVisibility(mDozing && !mPulsing ? INVISIBLE : VISIBLE);
+ boolean invisible = mDozing && (!mPulsing || mDocked);
+ setVisibility(invisible ? INVISIBLE : VISIBLE);
updateClickability();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java
index 79c7ab1..4603ba6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java
@@ -23,6 +23,7 @@
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
+import android.os.SystemClock;
import android.os.VibrationEffect;
import android.util.MathUtils;
import android.view.ContextThemeWrapper;
@@ -51,6 +52,11 @@
private static final long DISAPPEAR_ARROW_ANIMATION_DURATION_MS = 100;
/**
+ * The minimum time required since the first vibration effect to receive a second one
+ */
+ private static final int MIN_TIME_BETWEEN_EFFECTS_MS = 120;
+
+ /**
* The size of the protection of the arrow in px. Only used if this is not background protected
*/
private static final int PROTECTION_WIDTH_PX = 2;
@@ -182,6 +188,7 @@
private int mArrowStartColor;
private int mCurrentArrowColor;
private float mDisappearAmount;
+ private long mVibrationTime;
private DynamicAnimation.OnAnimationEndListener mSetGoneEndListener
= new DynamicAnimation.OnAnimationEndListener() {
@@ -394,7 +401,7 @@
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL: {
if (mTriggerBack) {
- triggerBackAnimation();
+ triggerBack();
} else {
if (mTranslationAnimation.isRunning()) {
mTranslationAnimation.addEndListener(mSetGoneEndListener);
@@ -521,8 +528,10 @@
return mCurrentTranslation;
}
- private void triggerBackAnimation() {
-
+ private void triggerBack() {
+ if (SystemClock.uptimeMillis() - mVibrationTime >= MIN_TIME_BETWEEN_EFFECTS_MS) {
+ mVibratorHelper.vibrate(VibrationEffect.EFFECT_CLICK);
+ }
mVelocityTracker.computeCurrentVelocity(1000);
// Only do the extra translation if we're not already flinging
boolean doExtraTranslation = Math.abs(mVelocityTracker.getXVelocity()) < 1000;
@@ -577,6 +586,7 @@
setCurrentTranslation(0);
mPreviousTouchTranslation = 0;
mTotalTouchDelta = 0;
+ mVibrationTime = 0;
setDesiredVerticalTransition(0, false /* animated */);
}
@@ -599,6 +609,7 @@
if (!mDragSlopPassed && touchTranslation > mSwipeThreshold) {
mDragSlopPassed = true;
mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
+ mVibrationTime = SystemClock.uptimeMillis();
// Let's show the arrow and animate it in!
mDisappearAmount = 0.0f;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index de57066..38eed16 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -24,11 +24,9 @@
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
import static com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
-import static com.android.systemui.shared.system.NavigationBarCompat.InteractionType;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
@@ -197,12 +195,6 @@
}
@Override
- public void onInteractionFlagsChanged(@InteractionType int flags) {
- mNavigationBarView.updateStates();
- updateScreenPinningGestures();
- }
-
- @Override
public void startAssistant(Bundle bundle) {
mAssistManager.startAssist(bundle);
}
@@ -335,7 +327,10 @@
filter.addAction(Intent.ACTION_USER_SWITCHED);
getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
notifyNavigationBarScreenOn();
+
mOverviewProxyService.addCallback(mOverviewProxyListener);
+ mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_NAV_BAR_HIDDEN,
+ !isNavBarWindowVisible(), mDisplayId);
// Currently there is no accelerometer sensor on non-default display.
if (mIsOnDefaultDisplay) {
@@ -471,7 +466,7 @@
if (DEBUG_WINDOW_STATE) Log.d(TAG, "Navigation bar " + windowStateToString(state));
mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_NAV_BAR_HIDDEN,
- !isNavBarWindowVisible());
+ !isNavBarWindowVisible(), mDisplayId);
mNavigationBarView.getRotateSuggestionButton()
.onNavigationBarWindowVisibilityChange(isNavBarWindowVisible());
}
@@ -512,12 +507,13 @@
mAutoHideController.touchAutoHide();
mLightBarController.onNavigationVisibilityChanged(mSystemUiVisibility, 0 /* mask */,
- true /* nbModeChanged */, mNavigationBarMode);
+ true /* nbModeChanged */, mNavigationBarMode, false /* navbarColorManagedByIme */);
}
@Override
public void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis,
- int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
+ int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds,
+ boolean navbarColorManagedByIme) {
if (displayId != mDisplayId) {
return;
}
@@ -545,7 +541,7 @@
}
}
mLightBarController.onNavigationVisibilityChanged(
- vis, mask, nbModeChanged, mNavigationBarMode);
+ vis, mask, nbModeChanged, mNavigationBarMode, navbarColorManagedByIme);
}
private @TransitionMode int computeBarMode(int oldVis, int newVis) {
@@ -831,7 +827,6 @@
activityManager.stopSystemLockTaskMode();
// When exiting refresh disabled flags.
mNavigationBarView.updateNavButtonIcons();
- mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_SCREEN_PINNING, false);
}
}
@@ -883,9 +878,10 @@
boolean clickable = (flags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0;
boolean longClickable = (flags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0;
mNavigationBarView.setAccessibilityButtonState(clickable, longClickable);
- mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_A11Y_BUTTON_CLICKABLE, clickable);
mOverviewProxyService.setSystemUiStateFlag(
- SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE, longClickable);
+ SYSUI_STATE_A11Y_BUTTON_CLICKABLE, clickable, mDisplayId);
+ mOverviewProxyService.setSystemUiStateFlag(
+ SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE, longClickable, mDisplayId);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
index 404c07b..963fc54 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
@@ -71,6 +71,7 @@
public static final String RIGHT = "right";
public static final String CONTEXTUAL = "contextual";
public static final String IME_SWITCHER = "ime_switcher";
+ public static final String START_CONTEXTUAL = "start_contextual";
public static final String GRAVITY_SEPARATOR = ";";
public static final String BUTTON_SEPARATOR = ",";
@@ -419,6 +420,8 @@
v = inflater.inflate(R.layout.home_handle, parent, false);
} else if (IME_SWITCHER.equals(button)) {
v = inflater.inflate(R.layout.ime_switcher, parent, false);
+ } else if (START_CONTEXTUAL.equals(button)) {
+ v = inflater.inflate(R.layout.start_contextual, parent, false);
} else if (button.startsWith(KEY)) {
String uri = extractImage(button);
int code = extractKeycode(button);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 6f1e161..1c03844 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -19,7 +19,6 @@
import static android.view.WindowManagerPolicyConstants.NAV_BAR_INVALID;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
-import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_SHOW_OVERVIEW_BUTTON;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
@@ -49,6 +48,8 @@
import android.view.Surface;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewTreeObserver.InternalInsetsInfo;
+import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
@@ -135,6 +136,7 @@
private boolean mImeVisible;
private final SparseArray<ButtonDispatcher> mButtonDispatchers = new SparseArray<>();
+ private final ContextualButtonGroup mStartContextualButtonGroup;
private final ContextualButtonGroup mContextualButtonGroup;
private Configuration mConfiguration;
private Configuration mTmpLastConfiguration;
@@ -233,11 +235,36 @@
}
};
+ private final OnComputeInternalInsetsListener mOnComputeInternalInsetsListener = info -> {
+ // When the nav bar is in 2-button or 3-button mode, or when IME is visible in fully
+ // gestural mode, the entire nav bar should be touchable.
+ if (!QuickStepContract.isGesturalMode(mNavBarMode) || mImeVisible) {
+ info.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_FRAME);
+ return;
+ }
+ info.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
+ RotationContextButton rotationContextButton = getRotateSuggestionButton();
+ // If the rotate suggestion button is not visible in fully gestural mode, the entire nav bar
+ // is not touchable so that the app underneath can be clicked through.
+ if (rotationContextButton.getVisibility() != VISIBLE) {
+ info.touchableRegion.setEmpty();
+ } else {
+ // Set the rotate suggestion button area to be touchable.
+ rotationContextButton.getCurrentView().getLocationInWindow(mTmpPosition);
+ Rect rect = new Rect(mTmpPosition[0], mTmpPosition[1],
+ mTmpPosition[0] + mRotationButtonBounds.width(),
+ mTmpPosition[1] + mRotationButtonBounds.height());
+ info.touchableRegion.union(rect);
+ }
+ };
+
public NavigationBarView(Context context, AttributeSet attrs) {
super(context, attrs);
mIsVertical = false;
mLongClickableAccessibilityButton = false;
+ mNavBarMode = Dependency.get(NavigationModeController.class).addListener(this);
+ boolean isGesturalMode = QuickStepContract.isGesturalMode(mNavBarMode);
// Set up the context group of buttons
mContextualButtonGroup = new ContextualButtonGroup(R.id.menu_container);
@@ -253,12 +280,21 @@
R.drawable.ic_sysbar_accessibility_button);
mContextualButtonGroup.addButton(menuButton);
mContextualButtonGroup.addButton(imeSwitcherButton);
- mContextualButtonGroup.addButton(rotateSuggestionButton);
+ if (!isGesturalMode) {
+ mContextualButtonGroup.addButton(rotateSuggestionButton);
+ }
mContextualButtonGroup.addButton(accessibilityButton);
mOverviewProxyService = Dependency.get(OverviewProxyService.class);
mRecentsOnboarding = new RecentsOnboarding(context, mOverviewProxyService);
+ final ContextualButton backButton = new ContextualButton(R.id.back, 0);
+ mStartContextualButtonGroup = new ContextualButtonGroup(R.id.start_menu_container);
+ if (isGesturalMode) {
+ mStartContextualButtonGroup.addButton(rotateSuggestionButton);
+ }
+ mStartContextualButtonGroup.addButton(backButton);
+
mConfiguration = new Configuration();
mTmpLastConfiguration = new Configuration();
mConfiguration.updateFrom(context.getResources().getConfiguration());
@@ -266,7 +302,7 @@
mScreenPinningNotify = new ScreenPinningNotify(mContext);
mBarTransitions = new NavigationBarTransitions(this);
- mButtonDispatchers.put(R.id.back, new ButtonDispatcher(R.id.back));
+ mButtonDispatchers.put(R.id.back, backButton);
mButtonDispatchers.put(R.id.home, new ButtonDispatcher(R.id.home));
mButtonDispatchers.put(R.id.home_handle, new ButtonDispatcher(R.id.home_handle));
mButtonDispatchers.put(R.id.recent_apps, new ButtonDispatcher(R.id.recent_apps));
@@ -275,6 +311,7 @@
mButtonDispatchers.put(R.id.accessibility_button, accessibilityButton);
mButtonDispatchers.put(R.id.rotate_suggestion, rotateSuggestionButton);
mButtonDispatchers.put(R.id.menu_container, mContextualButtonGroup);
+ mButtonDispatchers.put(R.id.start_menu_container, mStartContextualButtonGroup);
mDeadZone = new DeadZone(this);
mEdgeBackGestureHandler = new EdgeBackGestureHandler(context, mOverviewProxyService);
@@ -390,8 +427,11 @@
}
public RotationContextButton getRotateSuggestionButton() {
- return (RotationContextButton) mContextualButtonGroup
- .getContextButton(R.id.rotate_suggestion);
+ return (RotationContextButton) mButtonDispatchers.get(R.id.rotate_suggestion);
+ }
+
+ public ContextualButtonGroup getStartContextualButtonGroup() {
+ return mStartContextualButtonGroup;
}
public ButtonDispatcher getHomeHandle() {
@@ -430,6 +470,7 @@
if (densityChange || dirChange) {
mRecentIcon = getDrawable(R.drawable.ic_sysbar_recent);
mContextualButtonGroup.updateIcons();
+ mStartContextualButtonGroup.updateIcons();
}
if (orientationChange || densityChange || dirChange) {
mBackIcon = getBackDrawable();
@@ -437,12 +478,16 @@
}
public KeyButtonDrawable getBackDrawable() {
- KeyButtonDrawable drawable = chooseNavigationIconDrawable(R.drawable.ic_sysbar_back,
- R.drawable.ic_sysbar_back_quick_step);
+ KeyButtonDrawable drawable = getDrawable(getBackDrawableRes());
orientBackButton(drawable);
return drawable;
}
+ public @DrawableRes int getBackDrawableRes() {
+ return chooseNavigationIconDrawableRes(R.drawable.ic_sysbar_back,
+ R.drawable.ic_sysbar_back_quick_step);
+ }
+
public KeyButtonDrawable getHomeDrawable() {
final boolean quickStepEnabled = mOverviewProxyService.shouldShowSwipeUpUI();
KeyButtonDrawable drawable = quickStepEnabled
@@ -485,8 +530,13 @@
private KeyButtonDrawable chooseNavigationIconDrawable(@DrawableRes int icon,
@DrawableRes int quickStepIcon) {
+ return getDrawable(chooseNavigationIconDrawableRes(icon, quickStepIcon));
+ }
+
+ private @DrawableRes int chooseNavigationIconDrawableRes(@DrawableRes int icon,
+ @DrawableRes int quickStepIcon) {
final boolean quickStepEnabled = mOverviewProxyService.shouldShowSwipeUpUI();
- return quickStepEnabled ? getDrawable(quickStepIcon) : getDrawable(icon);
+ return quickStepEnabled ? quickStepIcon : icon;
}
private KeyButtonDrawable getDrawable(@DrawableRes int icon) {
@@ -527,7 +577,6 @@
mTransitionListener.onBackAltCleared();
}
mImeVisible = visible;
- updateWindowTouchable();
}
public void setDisabledFlags(int disabledFlags) {
@@ -564,7 +613,7 @@
updateRecentsIcon();
// Update IME button visibility, a11y and rotate button always overrides the appearance
- mContextualButtonGroup.setButtonVisiblity(R.id.ime_switcher,
+ mContextualButtonGroup.setButtonVisibility(R.id.ime_switcher,
(mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) != 0);
mBarTransitions.reapplyDarkIntensity();
@@ -587,10 +636,6 @@
// as they are used for exiting.
final boolean pinningActive = ActivityManagerWrapper.getInstance().isScreenPinningActive();
if (mOverviewProxyService.isEnabled()) {
- // Use interaction flags to show/hide navigation buttons but will be shown if required
- // to exit screen pinning.
- final int flags = mOverviewProxyService.getInteractionFlags();
- disableRecent |= (flags & FLAG_SHOW_OVERVIEW_BUTTON) == 0;
if (pinningActive) {
disableBack = disableHome = false;
}
@@ -609,6 +654,7 @@
}
getBackButton().setVisibility(disableBack ? View.INVISIBLE : View.VISIBLE);
+ mStartContextualButtonGroup.setButtonVisibility(R.id.back, !disableBack);
getHomeButton().setVisibility(disableHome ? View.INVISIBLE : View.VISIBLE);
getRecentsButton().setVisibility(disableRecent ? View.INVISIBLE : View.VISIBLE);
}
@@ -679,7 +725,7 @@
public void onPanelExpandedChange(boolean expanded) {
updateSlippery();
mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED,
- expanded);
+ expanded, getContext().getDisplayId());
}
public void updateStates() {
@@ -714,11 +760,6 @@
setWindowFlag(WindowManager.LayoutParams.FLAG_SLIPPERY, slippery);
}
- public void updateWindowTouchable() {
- boolean touchable = mImeVisible || !QuickStepContract.isGesturalMode(mNavBarMode);
- setWindowFlag(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, !touchable);
- }
-
private void setWindowFlag(int flags, boolean enable) {
final ViewGroup navbarView = ((ViewGroup) getParent());
if (navbarView == null) {
@@ -743,6 +784,7 @@
mBarTransitions.onNavigationModeChanged(mNavBarMode);
mEdgeBackGestureHandler.onNavigationModeChanged(mNavBarMode);
mRecentsOnboarding.onNavigationModeChanged(mNavBarMode);
+ getRotateSuggestionButton().onNavigationModeChanged(mNavBarMode);
// Color adaption is tied with showing home handle, only avaliable if visible
mTintController.onNavigationModeChanged(mNavBarMode);
@@ -751,17 +793,16 @@
} else {
mTintController.stop();
}
- updateWindowTouchable();
}
public void setMenuVisibility(final boolean show) {
- mContextualButtonGroup.setButtonVisiblity(R.id.menu, show);
+ mContextualButtonGroup.setButtonVisibility(R.id.menu, show);
}
public void setAccessibilityButtonState(final boolean visible, final boolean longClickable) {
mLongClickableAccessibilityButton = longClickable;
getAccessibilityButton().setLongClickable(longClickable);
- mContextualButtonGroup.setButtonVisiblity(R.id.accessibility_button, visible);
+ mContextualButtonGroup.setButtonVisibility(R.id.accessibility_button, visible);
}
void hideRecentsOnboarding() {
@@ -1044,12 +1085,11 @@
onPluginDisconnected(null); // Create default gesture helper
Dependency.get(PluginManager.class).addPluginListener(this,
NavGesture.class, false /* Only one */);
- int navBarMode = Dependency.get(NavigationModeController.class).addListener(this);
- onNavigationModeChanged(navBarMode);
+ onNavigationModeChanged(mNavBarMode);
setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled());
mEdgeBackGestureHandler.onNavBarAttached();
- updateWindowTouchable();
+ getViewTreeObserver().addOnComputeInternalInsetsListener(mOnComputeInternalInsetsListener);
}
@Override
@@ -1065,6 +1105,8 @@
mButtonDispatchers.valueAt(i).onDestroy();
}
mEdgeBackGestureHandler.onNavBarDetached();
+ getViewTreeObserver().removeOnComputeInternalInsetsListener(
+ mOnComputeInternalInsetsListener);
}
private void setUpSwipeUpOnboarding(boolean connectedToOverviewProxy) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java
index a00feeb..fa2263f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java
@@ -17,8 +17,10 @@
package com.android.systemui.statusbar.phone;
import static android.content.Intent.ACTION_OVERLAY_CHANGED;
-import static android.content.Intent.ACTION_USER_SWITCHED;
+import static android.os.UserHandle.USER_CURRENT;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -28,16 +30,21 @@
import android.content.pm.PackageManager;
import android.content.res.ApkAssets;
import android.os.PatternMatcher;
+import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.util.Log;
+import android.util.SparseBooleanArray;
import com.android.systemui.Dumpable;
+import com.android.systemui.UiOffloadThread;
import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -48,7 +55,7 @@
@Singleton
public class NavigationModeController implements Dumpable {
- private static final String TAG = NavigationModeController.class.getName();
+ private static final String TAG = NavigationModeController.class.getSimpleName();
private static final boolean DEBUG = true;
public interface ModeChangedListener {
@@ -57,6 +64,10 @@
private final Context mContext;
private final IOverlayManager mOverlayManager;
+ private final DeviceProvisionedController mDeviceProvisionedController;
+ private final UiOffloadThread mUiOffloadThread;
+
+ private SparseBooleanArray mRestoreGesturalNavBarMode = new SparseBooleanArray();
private int mMode = NAV_BAR_MODE_3BUTTON;
private ArrayList<ModeChangedListener> mListeners = new ArrayList<>();
@@ -64,36 +75,90 @@
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- context = getCurrentUserContext();
- int mode = getCurrentInteractionMode(context);
- mMode = mode;
- if (DEBUG) {
- Log.e(TAG, "ACTION_OVERLAY_CHANGED: mode=" + mMode
- + " contextUser=" + context.getUserId());
- dumpAssetPaths(context);
- }
-
- for (int i = 0; i < mListeners.size(); i++) {
- mListeners.get(i).onNavigationModeChanged(mode);
+ if (intent.getAction().equals(ACTION_OVERLAY_CHANGED)) {
+ if (DEBUG) {
+ Log.d(TAG, "ACTION_OVERLAY_CHANGED");
+ }
+ updateCurrentInteractionMode(true /* notify */);
}
}
};
+ private final DeviceProvisionedController.DeviceProvisionedListener mDeviceProvisionedCallback =
+ new DeviceProvisionedController.DeviceProvisionedListener() {
+ @Override
+ public void onDeviceProvisionedChanged() {
+ if (DEBUG) {
+ Log.d(TAG, "onDeviceProvisionedChanged: "
+ + mDeviceProvisionedController.isDeviceProvisioned());
+ }
+ // Once the device has been provisioned, check if we can restore gestural nav
+ restoreGesturalNavOverlayIfNecessary();
+ }
+
+ @Override
+ public void onUserSetupChanged() {
+ if (DEBUG) {
+ Log.d(TAG, "onUserSetupChanged: "
+ + mDeviceProvisionedController.isCurrentUserSetup());
+ }
+ // Once the user has been setup, check if we can restore gestural nav
+ restoreGesturalNavOverlayIfNecessary();
+ }
+
+ @Override
+ public void onUserSwitched() {
+ if (DEBUG) {
+ Log.d(TAG, "onUserSwitched: "
+ + ActivityManagerWrapper.getInstance().getCurrentUserId());
+ }
+
+ // Update the nav mode for the current user
+ updateCurrentInteractionMode(true /* notify */);
+
+ // When switching users, defer enabling the gestural nav overlay until the user
+ // is all set up
+ deferGesturalNavOverlayIfNecessary();
+ }
+ };
+
@Inject
- public NavigationModeController(Context context) {
+ public NavigationModeController(Context context,
+ DeviceProvisionedController deviceProvisionedController,
+ UiOffloadThread uiOffloadThread) {
mContext = context;
mOverlayManager = IOverlayManager.Stub.asInterface(
ServiceManager.getService(Context.OVERLAY_SERVICE));
+ mUiOffloadThread = uiOffloadThread;
+ mDeviceProvisionedController = deviceProvisionedController;
+ mDeviceProvisionedController.addCallback(mDeviceProvisionedCallback);
IntentFilter overlayFilter = new IntentFilter(ACTION_OVERLAY_CHANGED);
overlayFilter.addDataScheme("package");
overlayFilter.addDataSchemeSpecificPart("android", PatternMatcher.PATTERN_LITERAL);
mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, overlayFilter, null, null);
- IntentFilter userFilter = new IntentFilter(ACTION_USER_SWITCHED);
- mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, userFilter, null, null);
+ updateCurrentInteractionMode(false /* notify */);
- mMode = getCurrentInteractionMode(getCurrentUserContext());
+ // Check if we need to defer enabling gestural nav
+ deferGesturalNavOverlayIfNecessary();
+ }
+
+ public void updateCurrentInteractionMode(boolean notify) {
+ Context context = getCurrentUserContext();
+ int mode = getCurrentInteractionMode(context);
+ mMode = mode;
+ if (DEBUG) {
+ Log.e(TAG, "updateCurrentInteractionMode: mode=" + mMode
+ + " contextUser=" + context.getUserId());
+ dumpAssetPaths(context);
+ }
+
+ if (notify) {
+ for (int i = 0; i < mListeners.size(); i++) {
+ mListeners.get(i).onNavigationModeChanged(mode);
+ }
+ }
}
public int addListener(ModeChangedListener listener) {
@@ -129,10 +194,77 @@
}
}
+ private void deferGesturalNavOverlayIfNecessary() {
+ final int userId = mDeviceProvisionedController.getCurrentUser();
+ mRestoreGesturalNavBarMode.put(userId, false);
+ if (mDeviceProvisionedController.isDeviceProvisioned()
+ && mDeviceProvisionedController.isCurrentUserSetup()) {
+ // User is already setup and device is provisioned, nothing to do
+ if (DEBUG) {
+ Log.d(TAG, "deferGesturalNavOverlayIfNecessary: device is provisioned and user is "
+ + "setup");
+ }
+ return;
+ }
+
+ ArrayList<String> defaultOverlays = new ArrayList<>();
+ try {
+ defaultOverlays.addAll(Arrays.asList(mOverlayManager.getDefaultOverlayPackages()));
+ } catch (RemoteException e) {
+ Log.e(TAG, "deferGesturalNavOverlayIfNecessary: failed to fetch default overlays");
+ }
+ if (!defaultOverlays.contains(NAV_BAR_MODE_GESTURAL_OVERLAY)) {
+ // No default gesture nav overlay
+ if (DEBUG) {
+ Log.d(TAG, "deferGesturalNavOverlayIfNecessary: no default gestural overlay, "
+ + "default=" + defaultOverlays);
+ }
+ return;
+ }
+
+ // If the default is gestural, force-enable three button mode until the device is
+ // provisioned
+ setModeOverlay(NAV_BAR_MODE_3BUTTON_OVERLAY, USER_CURRENT);
+ mRestoreGesturalNavBarMode.put(userId, true);
+ if (DEBUG) {
+ Log.d(TAG, "deferGesturalNavOverlayIfNecessary: setting to 3 button mode");
+ }
+ }
+
+ private void restoreGesturalNavOverlayIfNecessary() {
+ if (DEBUG) {
+ Log.d(TAG, "restoreGesturalNavOverlayIfNecessary: needs restore="
+ + mRestoreGesturalNavBarMode);
+ }
+ final int userId = mDeviceProvisionedController.getCurrentUser();
+ if (mRestoreGesturalNavBarMode.get(userId)) {
+ // Restore the gestural state if necessary
+ setModeOverlay(NAV_BAR_MODE_GESTURAL_OVERLAY, USER_CURRENT);
+ mRestoreGesturalNavBarMode.put(userId, false);
+ }
+ }
+
+ public void setModeOverlay(String overlayPkg, int userId) {
+ mUiOffloadThread.submit(() -> {
+ try {
+ mOverlayManager.setEnabledExclusiveInCategory(overlayPkg, userId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to enable overlay " + overlayPkg + " for user " + userId);
+ }
+ });
+ }
+
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("NavigationModeController:");
pw.println(" mode=" + mMode);
+ String defaultOverlays = "";
+ try {
+ defaultOverlays = String.join(", ", mOverlayManager.getDefaultOverlayPackages());
+ } catch (RemoteException e) {
+ defaultOverlays = "failed_to_fetch";
+ }
+ pw.println(" defaultOverlays=" + defaultOverlays);
dumpAssetPaths(getCurrentUserContext());
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index c39a494..7b3ddf7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -337,6 +337,7 @@
* work, check the current id with the cached id.
*/
private int mThemeResId;
+ private KeyguardIndicationController mKeyguardIndicationController;
@Inject
public NotificationPanelView(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
@@ -516,6 +517,7 @@
mKeyguardBottomArea.initFrom(oldBottomArea);
addView(mKeyguardBottomArea, index);
initBottomArea();
+ mKeyguardIndicationController.setIndicationArea(mKeyguardBottomArea);
onDozeAmountChanged(mStatusBarStateController.getDozeAmount(),
mStatusBarStateController.getInterpolatedDozeAmount());
@@ -535,7 +537,8 @@
}
public void setKeyguardIndicationController(KeyguardIndicationController indicationController) {
- mKeyguardBottomArea.setKeyguardIndicationController(indicationController);
+ mKeyguardIndicationController = indicationController;
+ mKeyguardIndicationController.setIndicationArea(mKeyguardBottomArea);
}
@Override
@@ -3045,7 +3048,7 @@
}
public void showTransientIndication(int id) {
- mKeyguardBottomArea.showTransientIndication(id);
+ mKeyguardIndicationController.showTransientIndication(id);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index d5706e3..27368de 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -44,6 +44,7 @@
import com.android.systemui.UiOffloadThread;
import com.android.systemui.privacy.PrivacyItem;
import com.android.systemui.privacy.PrivacyItemController;
+import com.android.systemui.privacy.PrivacyType;
import com.android.systemui.qs.tiles.DndTile;
import com.android.systemui.qs.tiles.RotationLockTile;
import com.android.systemui.statusbar.CommandQueue;
@@ -229,9 +230,11 @@
mIconController.setIconVisibility(mSlotDataSaver, false);
// privacy items
- mIconController.setIcon(mSlotMicrophone, R.drawable.stat_sys_mic_none, null);
+ mIconController.setIcon(mSlotMicrophone, R.drawable.stat_sys_mic_none,
+ PrivacyType.TYPE_MICROPHONE.getName(mContext));
mIconController.setIconVisibility(mSlotMicrophone, false);
- mIconController.setIcon(mSlotCamera, R.drawable.stat_sys_camera, null);
+ mIconController.setIcon(mSlotCamera, R.drawable.stat_sys_camera,
+ PrivacyType.TYPE_CAMERA.getName(mContext));
mIconController.setIconVisibility(mSlotCamera, false);
mIconController.setIcon(mSlotLocation, LOCATION_STATUS_ICON_ID,
mContext.getString(R.string.accessibility_location_active));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java
index e887f5b..7203e57 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.phone;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
+
import static com.android.internal.view.RotationPolicy.NATURAL_ROTATION;
import android.animation.Animator;
@@ -45,6 +47,7 @@
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.statusbar.policy.KeyButtonDrawable;
import com.android.systemui.statusbar.policy.RotationLockController;
@@ -52,7 +55,9 @@
import java.util.Optional;
import java.util.function.Consumer;
-public class RotationContextButton extends ContextualButton {
+/** Containing logic for the rotation button in nav bar. */
+public class RotationContextButton extends ContextualButton implements
+ NavigationModeController.ModeChangedListener {
public static final boolean DEBUG_ROTATION = false;
private static final int BUTTON_FADE_IN_OUT_DURATION_MS = 100;
@@ -76,6 +81,7 @@
() -> mPendingRotationSuggestion = false;
private Animator mRotateHideAnimator;
private boolean mAccessibilityFeedbackEnabled;
+ private int mNavBarMode = NAV_BAR_MODE_3BUTTON;
private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
private final ViewRippler mViewRippler = new ViewRippler();
@@ -304,7 +310,8 @@
@Override
protected KeyButtonDrawable getNewDrawable() {
Context context = new ContextThemeWrapper(getContext().getApplicationContext(), mStyleRes);
- return KeyButtonDrawable.create(context, mIconResId, false /* shadow */);
+ return KeyButtonDrawable.create(context, mIconResId, false /* shadow */,
+ QuickStepContract.isGesturalMode(mNavBarMode));
}
@Override
@@ -390,9 +397,9 @@
}
private int computeRotationProposalTimeout() {
- if (mAccessibilityFeedbackEnabled) return 20000;
- if (mHoveringRotationSuggestion) return 16000;
- return 10000;
+ if (mAccessibilityFeedbackEnabled) return 10000;
+ if (mHoveringRotationSuggestion) return 8000;
+ return 5000;
}
private boolean isRotateSuggestionIntroduced() {
@@ -414,6 +421,11 @@
}
}
+ @Override
+ public void onNavigationModeChanged(int mode) {
+ mNavBarMode = mode;
+ }
+
private class TaskStackListenerImpl extends TaskStackChangeListener {
// Invalidate any rotation suggestion on task change or activity orientation change
// Note: all callbacks happen on main thread
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 2babfe3..5c16972 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -593,6 +593,7 @@
updateScrimController();
};
private ActivityIntentHelper mActivityIntentHelper;
+ private ShadeController mShadeController;
@Override
public void onActiveStateChanged(int code, int uid, String packageName, boolean active) {
@@ -710,7 +711,8 @@
setSystemUiVisibility(mDisplayId, result.mSystemUiVisibility,
result.mFullscreenStackSysUiVisibility, result.mDockedStackSysUiVisibility,
- 0xffffffff, result.mFullscreenStackBounds, result.mDockedStackBounds);
+ 0xffffffff, result.mFullscreenStackBounds, result.mDockedStackBounds,
+ result.mNavbarColorManagedByIme);
topAppWindowChanged(mDisplayId, result.mMenuVisible);
// StatusBarManagerService has a back up of IME token and it's restored here.
setImeWindowStatus(mDisplayId, result.mImeToken, result.mImeWindowVis,
@@ -1062,7 +1064,7 @@
final StatusBarRemoteInputCallback mStatusBarRemoteInputCallback =
(StatusBarRemoteInputCallback) Dependency.get(
NotificationRemoteInputManager.Callback.class);
- final ShadeController shadeController = Dependency.get(ShadeController.class);
+ mShadeController = Dependency.get(ShadeController.class);
final ActivityStarter activityStarter = Dependency.get(ActivityStarter.class);
mNotificationActivityStarter = new StatusBarNotificationActivityStarter(mContext,
@@ -1070,7 +1072,7 @@
mHeadsUpManager, activityStarter, mActivityLaunchAnimator,
mBarService, mStatusBarStateController, mKeyguardManager, mDreamManager,
mRemoteInputManager, mStatusBarRemoteInputCallback, mGroupManager,
- mLockscreenUserManager, shadeController, mKeyguardMonitor,
+ mLockscreenUserManager, mShadeController, mKeyguardMonitor,
mNotificationInterruptionStateProvider, mMetricsLogger,
new LockPatternUtils(mContext), Dependency.get(MAIN_HANDLER),
Dependency.get(BG_HANDLER), mActivityIntentHelper, mBubbleController);
@@ -1166,18 +1168,6 @@
@Override
public void onThemeChanged() {
- // Recreate Indication controller because internal references changed
- if (mKeyguardIndicationController != null) {
- mKeyguardIndicationController.destroy();
- }
- mKeyguardIndicationController =
- SystemUIFactory.getInstance().createKeyguardIndicationController(mContext,
- mStatusBarWindow.findViewById(R.id.keyguard_indication_area),
- mStatusBarWindow.findViewById(R.id.lock_icon));
- mNotificationPanel.setKeyguardIndicationController(mKeyguardIndicationController);
- mKeyguardIndicationController
- .setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
- mKeyguardIndicationController.setVisible(mState == StatusBarState.KEYGUARD);
if (mStatusBarKeyguardViewManager != null) {
mStatusBarKeyguardViewManager.onThemeChanged();
}
@@ -2089,7 +2079,8 @@
@Override // CommandQueue
public void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis,
- int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
+ int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds,
+ boolean navbarColorManagedByIme) {
if (displayId != mDisplayId) {
return;
}
@@ -2126,7 +2117,8 @@
}
}
mLightBarController.onSystemUiVisibilityChanged(fullscreenStackVis, dockedStackVis,
- mask, fullscreenStackBounds, dockedStackBounds, sbModeChanged, mStatusBarMode);
+ mask, fullscreenStackBounds, dockedStackBounds, sbModeChanged, mStatusBarMode,
+ navbarColorManagedByIme);
}
@Override
@@ -2247,11 +2239,12 @@
Log.v(TAG, "setLightsOn(" + on + ")");
if (on) {
setSystemUiVisibility(mDisplayId, 0, 0, 0, View.SYSTEM_UI_FLAG_LOW_PROFILE,
- mLastFullscreenStackBounds, mLastDockedStackBounds);
+ mLastFullscreenStackBounds, mLastDockedStackBounds,
+ false /* navbarColorManagedByIme */);
} else {
setSystemUiVisibility(mDisplayId, View.SYSTEM_UI_FLAG_LOW_PROFILE, 0, 0,
View.SYSTEM_UI_FLAG_LOW_PROFILE, mLastFullscreenStackBounds,
- mLastDockedStackBounds);
+ mLastDockedStackBounds, false /* navbarColorManagedByIme */);
}
}
@@ -3596,7 +3589,7 @@
// Notify overview proxy service of the new states
Dependency.get(OverviewProxyService.class).setSystemUiStateFlag(SYSUI_STATE_BOUNCER_SHOWING,
- isBouncerShowing());
+ isBouncerShowing(), mContext.getDisplayId());
}
/**
@@ -4356,6 +4349,13 @@
@Override
public void startPendingIntentDismissingKeyguard(
final PendingIntent intent, @Nullable final Runnable intentSentUiThreadCallback) {
+ startPendingIntentDismissingKeyguard(intent, intentSentUiThreadCallback, null /* row */);
+ }
+
+ @Override
+ public void startPendingIntentDismissingKeyguard(
+ final PendingIntent intent, @Nullable final Runnable intentSentUiThreadCallback,
+ View associatedView) {
final boolean afterKeyguardGone = intent.isActivity()
&& mActivityIntentHelper.wouldLaunchResolverActivity(intent.getIntent(),
mLockscreenUserManager.getCurrentUserId());
@@ -4363,7 +4363,8 @@
executeActionDismissingKeyguard(() -> {
try {
intent.send(null, 0, null, null, null, null, getActivityOptions(
- null /* animationAdapter */));
+ mActivityLaunchAnimator.getLaunchAnimation(associatedView,
+ mShadeController.isOccluded())));
} catch (PendingIntent.CanceledException e) {
// the stack trace isn't very helpful here.
// Just log the exception message.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 002313c..7fe8906 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -25,8 +25,6 @@
import android.content.res.ColorStateList;
import android.os.Bundle;
import android.os.SystemClock;
-import android.transition.Fade;
-import android.transition.TransitionManager;
import android.util.StatsLog;
import android.view.KeyEvent;
import android.view.View;
@@ -40,10 +38,8 @@
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.ViewMediatorCallback;
import com.android.settingslib.animation.AppearAnimationUtils;
-import com.android.settingslib.animation.DisappearAnimationUtils;
import com.android.systemui.DejankUtils;
import com.android.systemui.Dependency;
-import com.android.systemui.Interpolators;
import com.android.systemui.SysUiServiceProvider;
import com.android.systemui.SystemUIFactory;
import com.android.systemui.dock.DockManager;
@@ -51,6 +47,7 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarState;
@@ -158,7 +155,7 @@
private boolean mLastPulsing;
private int mLastBiometricMode;
private boolean mGoingToSleepVisibleNotOccluded;
- private int mLastLockVisibility = -1;
+ private boolean mLastLockVisible;
private OnDismissAction mAfterKeyguardGoneAction;
private final ArrayList<Runnable> mAfterKeyguardGoneRunnables = new ArrayList<>();
@@ -213,6 +210,9 @@
mStatusBar = statusBar;
mContainer = container;
mLockIconContainer = lockIconContainer;
+ if (mLockIconContainer != null) {
+ mLastLockVisible = mLockIconContainer.getVisibility() == View.VISIBLE;
+ }
mBiometricUnlockController = biometricUnlockController;
mBouncer = SystemUIFactory.getInstance().createKeyguardBouncer(mContext,
mViewMediatorCallback, mLockPatternUtils, container, dismissCallbackRegistry,
@@ -261,21 +261,20 @@
}
boolean keyguardWithoutQs = mStatusBarStateController.getState() == StatusBarState.KEYGUARD
&& !mNotificationPanelView.isQsExpanded();
- int lockVisibility = (mBouncer.isShowing() || keyguardWithoutQs)
- && !mBouncer.isAnimatingAway() ? View.VISIBLE : View.INVISIBLE;
+ boolean lockVisible = (mBouncer.isShowing() || keyguardWithoutQs)
+ && !mBouncer.isAnimatingAway();
- if (mLastLockVisibility != lockVisibility) {
- mLastLockVisibility = lockVisibility;
-
- Fade transition = new Fade();
- boolean appearing = lockVisibility == View.VISIBLE;
- transition.setDuration(appearing ? AppearAnimationUtils.DEFAULT_APPEAR_DURATION
- : DisappearAnimationUtils.DEFAULT_APPEAR_DURATION / 2);
- transition.setInterpolator(appearing ? Interpolators.ALPHA_IN
- : Interpolators.ALPHA_OUT);
- TransitionManager.beginDelayedTransition((ViewGroup) mLockIconContainer.getParent(),
- transition);
- mLockIconContainer.setVisibility(lockVisibility);
+ if (mLastLockVisible != lockVisible) {
+ mLastLockVisible = lockVisible;
+ if (lockVisible) {
+ CrossFadeHelper.fadeIn(mLockIconContainer,
+ AppearAnimationUtils.DEFAULT_APPEAR_DURATION /* duration */,
+ 0 /* delay */);
+ } else {
+ CrossFadeHelper.fadeOut(mLockIconContainer,
+ AppearAnimationUtils.DEFAULT_APPEAR_DURATION / 2 /* duration */,
+ 0 /* delay */, null /* runnable */);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java
index dd0c344..2bfc311 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java
@@ -30,9 +30,11 @@
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
+import android.graphics.PorterDuff;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.Drawable;
import android.util.FloatProperty;
@@ -77,13 +79,14 @@
private final Paint mIconPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
private final Paint mShadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
+ private final Paint mOvalBgPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
private final ShadowDrawableState mState;
private AnimatedVectorDrawable mAnimatedDrawable;
public KeyButtonDrawable(Drawable d, @ColorInt int lightColor, @ColorInt int darkColor,
- boolean horizontalFlip) {
+ boolean horizontalFlip, boolean hasOvalBg) {
this(d, new ShadowDrawableState(lightColor, darkColor,
- d instanceof AnimatedVectorDrawable, horizontalFlip));
+ d instanceof AnimatedVectorDrawable, horizontalFlip, hasOvalBg));
}
private KeyButtonDrawable(Drawable d, ShadowDrawableState state) {
@@ -98,6 +101,7 @@
mAnimatedDrawable = (AnimatedVectorDrawable) mState.mChildState.newDrawable().mutate();
setDrawableBounds(mAnimatedDrawable);
}
+ mOvalBgPaint.setColor(mState.mDarkColor);
}
public void setDarkIntensity(float intensity) {
@@ -165,7 +169,12 @@
public void setColorFilter(ColorFilter colorFilter) {
mIconPaint.setColorFilter(colorFilter);
if (mAnimatedDrawable != null) {
- mAnimatedDrawable.setColorFilter(colorFilter);
+ if (mState.mHasOvalBg) {
+ mAnimatedDrawable.setColorFilter(
+ new PorterDuffColorFilter(mState.mLightColor, PorterDuff.Mode.SRC_IN));
+ } else {
+ mAnimatedDrawable.setColorFilter(colorFilter);
+ }
}
invalidateSelf();
}
@@ -235,6 +244,10 @@
return;
}
+ if (mState.mHasOvalBg) {
+ canvas.drawOval(new RectF(bounds), mOvalBgPaint);
+ }
+
if (mAnimatedDrawable != null) {
mAnimatedDrawable.draw(canvas);
} else {
@@ -379,14 +392,16 @@
final int mLightColor;
final int mDarkColor;
final boolean mSupportsAnimation;
+ final boolean mHasOvalBg;
public ShadowDrawableState(@ColorInt int lightColor, @ColorInt int darkColor,
- boolean animated, boolean horizontalFlip) {
+ boolean animated, boolean horizontalFlip, boolean hasOvalBg) {
mLightColor = lightColor;
mDarkColor = darkColor;
mSupportsAnimation = animated;
mAlpha = 255;
mHorizontalFlip = horizontalFlip;
+ mHasOvalBg = hasOvalBg;
}
@Override
@@ -411,32 +426,51 @@
* @param ctx Context to get the drawable and determine the dark and light theme
* @param icon the icon resource id
* @param hasShadow if a shadow will appear with the drawable
+ * @param hasOvalBg if an oval bg will be drawn
* @return KeyButtonDrawable
*/
public static KeyButtonDrawable create(@NonNull Context ctx, @DrawableRes int icon,
- boolean hasShadow) {
+ boolean hasShadow, boolean hasOvalBg) {
final int dualToneDarkTheme = Utils.getThemeAttr(ctx, R.attr.darkIconTheme);
final int dualToneLightTheme = Utils.getThemeAttr(ctx, R.attr.lightIconTheme);
Context lightContext = new ContextThemeWrapper(ctx, dualToneLightTheme);
Context darkContext = new ContextThemeWrapper(ctx, dualToneDarkTheme);
- return KeyButtonDrawable.create(lightContext, darkContext, icon, hasShadow);
+ return KeyButtonDrawable.create(lightContext, darkContext, icon, hasShadow, hasOvalBg);
}
+ /**
+ * Creates a KeyButtonDrawable with a shadow given its icon. For more information, see
+ * {@link #create(Context, int, boolean, boolean)}.
+ */
+ public static KeyButtonDrawable create(@NonNull Context ctx, @DrawableRes int icon,
+ boolean hasShadow) {
+ return create(ctx, icon, hasShadow, false /* hasOvalBg */);
+ }
+
+ /**
+ * Creates a KeyButtonDrawable with a shadow given its icon. For more information, see
+ * {@link #create(Context, int, boolean, boolean)}.
+ */
public static KeyButtonDrawable create(Context lightContext, Context darkContext,
- @DrawableRes int iconResId, boolean hasShadow) {
+ @DrawableRes int iconResId, boolean hasShadow, boolean hasOvalBg) {
return create(lightContext,
Utils.getColorAttrDefaultColor(lightContext, R.attr.singleToneColor),
Utils.getColorAttrDefaultColor(darkContext, R.attr.singleToneColor),
- iconResId, hasShadow);
+ iconResId, hasShadow, hasOvalBg);
}
+ /**
+ * Creates a KeyButtonDrawable with a shadow given its icon. For more information, see
+ * {@link #create(Context, int, boolean, boolean)}.
+ */
public static KeyButtonDrawable create(Context context, @ColorInt int lightColor,
- @ColorInt int darkColor, @DrawableRes int iconResId, boolean hasShadow) {
+ @ColorInt int darkColor, @DrawableRes int iconResId, boolean hasShadow,
+ boolean hasOvalBg) {
final Resources res = context.getResources();
boolean isRtl = res.getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
Drawable d = context.getDrawable(iconResId);
final KeyButtonDrawable drawable = new KeyButtonDrawable(d, lightColor, darkColor,
- isRtl && d.isAutoMirrored());
+ isRtl && d.isAutoMirrored(), hasOvalBg);
if (hasShadow) {
int offsetX = res.getDimensionPixelSize(R.dimen.nav_key_button_shadow_offset_x);
int offsetY = res.getDimensionPixelSize(R.dimen.nav_key_button_shadow_offset_y);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 9923ec9..41fa346 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -56,7 +56,7 @@
import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.plugins.statusbar.phone.NavBarButtonProvider.ButtonInterface;
import com.android.systemui.recents.OverviewProxyService;
-import com.android.systemui.shared.system.NavigationBarCompat;
+import com.android.systemui.shared.system.QuickStepContract;
public class KeyButtonView extends ImageView implements ButtonInterface {
private static final String TAG = KeyButtonView.class.getSimpleName();
@@ -244,11 +244,11 @@
y = (int)ev.getRawY();
boolean exceededTouchSlopX = Math.abs(x - mTouchDownX) > (mIsVertical
- ? NavigationBarCompat.getQuickScrubTouchSlopPx()
- : NavigationBarCompat.getQuickStepTouchSlopPx());
+ ? QuickStepContract.getQuickScrubTouchSlopPx()
+ : QuickStepContract.getQuickStepTouchSlopPx());
boolean exceededTouchSlopY = Math.abs(y - mTouchDownY) > (mIsVertical
- ? NavigationBarCompat.getQuickStepTouchSlopPx()
- : NavigationBarCompat.getQuickScrubTouchSlopPx());
+ ? QuickStepContract.getQuickStepTouchSlopPx()
+ : QuickStepContract.getQuickScrubTouchSlopPx());
if (exceededTouchSlopX || exceededTouchSlopY) {
// When quick step is enabled, prevent animating the ripple triggered by
// setPressed and decide to run it on touch up
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index 11e5625..c398ad8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -94,8 +94,7 @@
mPhone = phone;
mDefaults = defaults;
mSubscriptionInfo = info;
- mPhoneStateListener = new MobilePhoneStateListener(info.getSubscriptionId(),
- receiverLooper);
+ mPhoneStateListener = new MobilePhoneStateListener(receiverLooper);
mNetworkNameSeparator = getStringIfExists(R.string.status_bar_network_name_separator);
mNetworkNameDefault = getStringIfExists(
com.android.internal.R.string.lockscreen_carrier_default);
@@ -574,8 +573,8 @@
}
class MobilePhoneStateListener extends PhoneStateListener {
- public MobilePhoneStateListener(int subId, Looper looper) {
- super(subId, looper);
+ public MobilePhoneStateListener(Looper looper) {
+ super(looper);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index faf63c8..950f07d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -662,8 +662,9 @@
cachedControllers.remove(subId);
} else {
MobileSignalController controller = new MobileSignalController(mContext, mConfig,
- mHasMobileDataFeature, mPhone, mCallbackHandler,
- this, subscriptions.get(i), mSubDefaults, mReceiverHandler.getLooper());
+ mHasMobileDataFeature, mPhone.createForSubscriptionId(subId),
+ mCallbackHandler, this, subscriptions.get(i),
+ mSubDefaults, mReceiverHandler.getLooper());
controller.setUserSetupComplete(mUserSetup);
mMobileSignalControllers.put(subId, controller);
if (subscriptions.get(i).getSimSlotIndex() == 0) {
@@ -1049,7 +1050,8 @@
SubscriptionInfo info = new SubscriptionInfo(id, "", simSlotIndex, "", "", 0, 0, "", 0,
null, null, null, "", false, null, null);
MobileSignalController controller = new MobileSignalController(mContext,
- mConfig, mHasMobileDataFeature, mPhone, mCallbackHandler, this, info,
+ mConfig, mHasMobileDataFeature,
+ mPhone.createForSubscriptionId(info.getSubscriptionId()), mCallbackHandler, this, info,
mSubDefaults, mReceiverHandler.getLooper());
mMobileSignalControllers.put(id, controller);
controller.getState().userSetup = true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index c1950a2..43795dc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -63,6 +63,7 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntry.EditedSuggestionInfo;
import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
+import com.android.systemui.statusbar.phone.LightBarController;
import java.util.function.Consumer;
@@ -516,10 +517,12 @@
private final Drawable mBackground;
private RemoteInputView mRemoteInputView;
boolean mShowImeOnInputConnection;
+ private LightBarController mLightBarController;
public RemoteEditText(Context context, AttributeSet attrs) {
super(context, attrs);
mBackground = getBackground();
+ mLightBarController = Dependency.get(LightBarController.class);
}
private void defocusIfNeeded(boolean animate) {
@@ -558,6 +561,9 @@
if (!focused) {
defocusIfNeeded(true /* animate */);
}
+ if (!mRemoteInputView.mRemoved) {
+ mLightBarController.setDirectReplying(focused);
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java
index f02b544..655c29c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java
@@ -93,10 +93,10 @@
}
private void registerDeviceConfigListener() {
- DeviceConfig.addOnPropertyChangedListener(
+ DeviceConfig.addOnPropertiesChangedListener(
DeviceConfig.NAMESPACE_SYSTEMUI,
this::postToHandler,
- this::onDeviceConfigPropertyChanged);
+ (properties) -> onDeviceConfigPropertiesChanged(properties.getNamespace()));
}
private void postToHandler(Runnable r) {
@@ -104,10 +104,10 @@
}
@VisibleForTesting
- void onDeviceConfigPropertyChanged(String namespace, String name, String value) {
+ void onDeviceConfigPropertiesChanged(String namespace) {
if (!DeviceConfig.NAMESPACE_SYSTEMUI.equals(namespace)) {
Log.e(TAG, "Received update from DeviceConfig for unrelated namespace: "
- + namespace + " " + name + "=" + value);
+ + namespace);
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
index 0f7a0f0..640f0f0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
@@ -349,7 +349,7 @@
smartReplyController.smartActionClicked(
entry, actionIndex, action, smartActions.fromAssistant);
headsUpManager.removeNotification(entry.key, true);
- });
+ }, entry.getRow());
if (useDelayedOnClickListener) {
onClickListener = new DelayedOnClickListener(onClickListener,
smartReplyView.mConstants.getOnClickInitDelay());
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
index 212c8f5..e312990 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
@@ -189,10 +189,6 @@
when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY);
when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
- // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the
- // same answer as KeyguardUpdateMonitor. Remove when this is addressed
- when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list);
-
mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor =
@@ -217,10 +213,6 @@
when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY);
when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
- // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the
- // same answer as KeyguardUpdateMonitor. Remove when this is addressed
- when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list);
-
mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor =
@@ -243,11 +235,6 @@
when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(
new ArrayList<>());
- // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the
- // same answer as KeyguardUpdateMonitor. Remove when this is addressed
- when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(
- new ArrayList<>());
-
ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor =
ArgumentCaptor.forClass(
CarrierTextController.CarrierTextCallbackInfo.class);
@@ -271,10 +258,6 @@
when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY);
when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
- // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the
- // same answer as KeyguardUpdateMonitor. Remove when this is addressed
- when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list);
-
mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor =
@@ -300,10 +283,6 @@
.thenReturn(IccCardConstants.State.NOT_READY);
when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
- // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the
- // same answer as KeyguardUpdateMonitor. Remove when this is addressed
- when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list);
-
mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor =
@@ -329,10 +308,6 @@
.thenReturn(IccCardConstants.State.READY);
when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
- // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the
- // same answer as KeyguardUpdateMonitor. Remove when this is addressed
- when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list);
-
mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor =
@@ -361,10 +336,6 @@
when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
- // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the
- // same answer as KeyguardUpdateMonitor. Remove when this is addressed
- when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list);
-
ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor =
ArgumentCaptor.forClass(
CarrierTextController.CarrierTextCallbackInfo.class);
@@ -385,12 +356,9 @@
list.add(TEST_SUBSCRIPTION_2);
when(mKeyguardUpdateMonitor.getSimState(anyInt()))
.thenReturn(IccCardConstants.State.READY);
- when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
+
mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
mCarrierTextController.updateDisplayOpportunisticSubscriptionCarrierText();
-
- // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the
- // same answer as KeyguardUpdateMonitor. Remove when this is addressed
when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list);
ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
new file mode 100644
index 0000000..d6dac2f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
@@ -0,0 +1,707 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.bubbles;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.graphics.drawable.Icon;
+import android.os.UserHandle;
+import android.service.notification.StatusBarNotification;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.bubbles.BubbleData.TimeSource;
+import com.android.systemui.statusbar.NotificationTestHelper;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+
+import com.google.common.collect.ImmutableList;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+public class BubbleDataTest extends SysuiTestCase {
+
+ private NotificationEntry mEntryA1;
+ private NotificationEntry mEntryA2;
+ private NotificationEntry mEntryA3;
+ private NotificationEntry mEntryB1;
+ private NotificationEntry mEntryB2;
+ private NotificationEntry mEntryB3;
+ private NotificationEntry mEntryC1;
+
+ private Bubble mBubbleA1;
+ private Bubble mBubbleA2;
+ private Bubble mBubbleA3;
+ private Bubble mBubbleB1;
+ private Bubble mBubbleB2;
+ private Bubble mBubbleB3;
+ private Bubble mBubbleC1;
+
+ private BubbleData mBubbleData;
+
+ @Mock
+ private TimeSource mTimeSource;
+ @Mock
+ private BubbleData.Listener mListener;
+ @Mock
+ private PendingIntent mExpandIntent;
+ @Mock
+ private PendingIntent mDeleteIntent;
+
+ private NotificationTestHelper mNotificationTestHelper;
+
+ @Before
+ public void setUp() throws Exception {
+ mNotificationTestHelper = new NotificationTestHelper(mContext);
+ MockitoAnnotations.initMocks(this);
+
+ mEntryA1 = createBubbleEntry(1, "a1", "package.a");
+ mEntryA2 = createBubbleEntry(1, "a2", "package.a");
+ mEntryA3 = createBubbleEntry(1, "a3", "package.a");
+ mEntryB1 = createBubbleEntry(1, "b1", "package.b");
+ mEntryB2 = createBubbleEntry(1, "b2", "package.b");
+ mEntryB3 = createBubbleEntry(1, "b3", "package.b");
+ mEntryC1 = createBubbleEntry(1, "c1", "package.c");
+
+ mBubbleA1 = new Bubble(mEntryA1);
+ mBubbleA2 = new Bubble(mEntryA2);
+ mBubbleA3 = new Bubble(mEntryA3);
+ mBubbleB1 = new Bubble(mEntryB1);
+ mBubbleB2 = new Bubble(mEntryB2);
+ mBubbleB3 = new Bubble(mEntryB3);
+ mBubbleC1 = new Bubble(mEntryC1);
+
+ mBubbleData = new BubbleData(getContext());
+
+ // Used by BubbleData to set lastAccessedTime
+ when(mTimeSource.currentTimeMillis()).thenReturn(1000L);
+ mBubbleData.setTimeSource(mTimeSource);
+ }
+
+ private NotificationEntry createBubbleEntry(int userId, String notifKey, String packageName) {
+ return createBubbleEntry(userId, notifKey, packageName, 1000);
+ }
+
+ private void setPostTime(NotificationEntry entry, long postTime) {
+ when(entry.notification.getPostTime()).thenReturn(postTime);
+ }
+
+ private void setOngoing(NotificationEntry entry, boolean ongoing) {
+ if (ongoing) {
+ entry.notification.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+ } else {
+ entry.notification.getNotification().flags &= ~Notification.FLAG_FOREGROUND_SERVICE;
+ }
+ }
+
+ /**
+ * No ExpandableNotificationRow is required to test BubbleData. This setup is all that is
+ * required for BubbleData functionality and verification. NotificationTestHelper is used only
+ * as a convenience to create a Notification w/BubbleMetadata.
+ */
+ private NotificationEntry createBubbleEntry(int userId, String notifKey, String packageName,
+ long postTime) {
+ // BubbleMetadata
+ Notification.BubbleMetadata bubbleMetadata = new Notification.BubbleMetadata.Builder()
+ .setIntent(mExpandIntent)
+ .setDeleteIntent(mDeleteIntent)
+ .setIcon(Icon.createWithResource("", 0))
+ .build();
+ // Notification -> BubbleMetadata
+ Notification notification = mNotificationTestHelper.createNotification(false,
+ null /* groupKey */, bubbleMetadata);
+
+ // StatusBarNotification
+ StatusBarNotification sbn = mock(StatusBarNotification.class);
+ when(sbn.getKey()).thenReturn(notifKey);
+ when(sbn.getUser()).thenReturn(new UserHandle(userId));
+ when(sbn.getPackageName()).thenReturn(packageName);
+ when(sbn.getPostTime()).thenReturn(postTime);
+ when(sbn.getNotification()).thenReturn(notification);
+
+ // NotificationEntry -> StatusBarNotification -> Notification -> BubbleMetadata
+ return new NotificationEntry(sbn);
+ }
+
+ private void sendUpdatedEntryAtTime(NotificationEntry entry, long postTime) {
+ setPostTime(entry, postTime);
+ mBubbleData.notificationEntryUpdated(entry);
+ }
+
+ private void changeExpandedStateAtTime(boolean shouldBeExpanded, long time) {
+ when(mTimeSource.currentTimeMillis()).thenReturn(time);
+ mBubbleData.setExpanded(shouldBeExpanded);
+ }
+
+ @Test
+ public void testAddBubble() {
+ // Setup
+ mBubbleData.setListener(mListener);
+
+ // Test
+ setPostTime(mEntryA1, 1000);
+ mBubbleData.notificationEntryUpdated(mEntryA1);
+
+ // Verify
+ verify(mListener).onBubbleAdded(eq(mBubbleA1));
+ verify(mListener).onSelectionChanged(eq(mBubbleA1));
+ verify(mListener).apply();
+ }
+
+ @Test
+ public void testRemoveBubble() {
+ // Setup
+ mBubbleData.notificationEntryUpdated(mEntryA1);
+ mBubbleData.notificationEntryUpdated(mEntryA2);
+ mBubbleData.notificationEntryUpdated(mEntryA3);
+ mBubbleData.setListener(mListener);
+
+ // Test
+ mBubbleData.notificationEntryRemoved(mEntryA1, BubbleController.DISMISS_USER_GESTURE);
+
+ // Verify
+ verify(mListener).onBubbleRemoved(eq(mBubbleA1), eq(BubbleController.DISMISS_USER_GESTURE));
+ verify(mListener).onSelectionChanged(eq(mBubbleA2));
+ verify(mListener).apply();
+ }
+
+ @Test
+ public void test_collapsed_addBubble_atMaxBubbles_expiresLeastActive() {
+ // Given
+ sendUpdatedEntryAtTime(mEntryA1, 1000);
+ sendUpdatedEntryAtTime(mEntryA2, 2000);
+ sendUpdatedEntryAtTime(mEntryA3, 3000);
+ sendUpdatedEntryAtTime(mEntryB1, 4000);
+ sendUpdatedEntryAtTime(mEntryB2, 5000);
+ assertThat(mBubbleData.getSelectedBubble()).isEqualTo(mBubbleA1);
+
+ // When
+ sendUpdatedEntryAtTime(mEntryC1, 6000);
+
+ // Then
+ // A2 is removed. A1 is oldest but is the selected bubble.
+ assertThat(mBubbleData.getBubbles()).doesNotContain(mBubbleA2);
+ }
+
+ @Test
+ public void test_collapsed_expand_whenEmpty_doesNothing() {
+ assertThat(mBubbleData.hasBubbles()).isFalse();
+ changeExpandedStateAtTime(true, 2000L);
+
+ verify(mListener, never()).onExpandedChanged(anyBoolean());
+ verify(mListener, never()).apply();
+ }
+
+ // New bubble while stack is collapsed
+ @Test
+ public void test_collapsed_addBubble() {
+ // Given
+ assertThat(mBubbleData.hasBubbles()).isFalse();
+ assertThat(mBubbleData.isExpanded()).isFalse();
+
+ // When
+ sendUpdatedEntryAtTime(mEntryA1, 1000);
+ sendUpdatedEntryAtTime(mEntryB1, 2000);
+ sendUpdatedEntryAtTime(mEntryB2, 3000);
+ sendUpdatedEntryAtTime(mEntryA2, 4000);
+
+ // Then
+ // New bubbles move to front when collapsed, bringing bubbles from the same app along
+ assertThat(mBubbleData.getBubbles()).isEqualTo(
+ ImmutableList.of(mBubbleA2, mBubbleA1, mBubbleB2, mBubbleB1));
+ }
+
+ // New bubble while collapsed with ongoing bubble present
+ @Test
+ public void test_collapsed_addBubble_withOngoing() {
+ // Given
+ assertThat(mBubbleData.hasBubbles()).isFalse();
+ assertThat(mBubbleData.isExpanded()).isFalse();
+
+ // When
+ setOngoing(mEntryA1, true);
+ setPostTime(mEntryA1, 1000);
+ mBubbleData.notificationEntryUpdated(mEntryA1);
+ setPostTime(mEntryB1, 2000);
+ mBubbleData.notificationEntryUpdated(mEntryB1);
+ setPostTime(mEntryB2, 3000);
+ mBubbleData.notificationEntryUpdated(mEntryB2);
+ setPostTime(mEntryA2, 4000);
+ mBubbleData.notificationEntryUpdated(mEntryA2);
+
+ // Then
+ // New bubbles move to front, but stay behind any ongoing bubbles.
+ assertThat(mBubbleData.getBubbles()).isEqualTo(
+ ImmutableList.of(mBubbleA1, mBubbleA2, mBubbleB2, mBubbleB1));
+ }
+
+ // Remove the selected bubble (middle bubble), while the stack is collapsed.
+ @Test
+ public void test_collapsed_removeBubble_selected() {
+ // Given
+ assertThat(mBubbleData.hasBubbles()).isFalse();
+ assertThat(mBubbleData.isExpanded()).isFalse();
+
+ setPostTime(mEntryA1, 1000);
+ mBubbleData.notificationEntryUpdated(mEntryA1);
+
+ setPostTime(mEntryB1, 2000);
+ mBubbleData.notificationEntryUpdated(mEntryB1);
+
+ setPostTime(mEntryB2, 3000);
+ mBubbleData.notificationEntryUpdated(mEntryB2);
+
+ setPostTime(mEntryA2, 4000);
+ mBubbleData.notificationEntryUpdated(mEntryA2);
+
+ mBubbleData.setSelectedBubble(mBubbleB2);
+ assertThat(mBubbleData.getBubbles()).isEqualTo(
+ ImmutableList.of(mBubbleA2, mBubbleA1, mBubbleB2, mBubbleB1));
+
+ // When
+ mBubbleData.notificationEntryRemoved(mEntryB2, BubbleController.DISMISS_USER_GESTURE);
+
+ // Then
+ // (Selection remains in the same position)
+ assertThat(mBubbleData.getSelectedBubble()).isEqualTo(mBubbleB1);
+ }
+
+ // Remove the selected bubble (last bubble), while the stack is collapsed.
+ @Test
+ public void test_collapsed_removeSelectedBubble_inLastPosition() {
+ // Given
+ assertThat(mBubbleData.hasBubbles()).isFalse();
+ assertThat(mBubbleData.isExpanded()).isFalse();
+
+ sendUpdatedEntryAtTime(mEntryA1, 1000);
+ sendUpdatedEntryAtTime(mEntryB1, 2000);
+ sendUpdatedEntryAtTime(mEntryB2, 3000);
+ sendUpdatedEntryAtTime(mEntryA2, 4000);
+
+ mBubbleData.setSelectedBubble(mBubbleB1);
+ assertThat(mBubbleData.getBubbles()).isEqualTo(
+ ImmutableList.of(mBubbleA2, mBubbleA1, mBubbleB2, mBubbleB1));
+
+ // When
+ mBubbleData.notificationEntryRemoved(mEntryB1, BubbleController.DISMISS_USER_GESTURE);
+
+ // Then
+ // (Selection is forced to move to previous)
+ assertThat(mBubbleData.getSelectedBubble()).isEqualTo(mBubbleB2);
+ }
+
+ @Test
+ public void test_collapsed_addBubble_ongoing() {
+ // Given
+ assertThat(mBubbleData.hasBubbles()).isFalse();
+ assertThat(mBubbleData.isExpanded()).isFalse();
+
+ // When
+ setPostTime(mEntryA1, 1000);
+ mBubbleData.notificationEntryUpdated(mEntryA1);
+
+ setPostTime(mEntryB1, 2000);
+ mBubbleData.notificationEntryUpdated(mEntryB1);
+
+ setPostTime(mEntryB2, 3000);
+ setOngoing(mEntryB2, true);
+ mBubbleData.notificationEntryUpdated(mEntryB2);
+
+ setPostTime(mEntryA2, 4000);
+ mBubbleData.notificationEntryUpdated(mEntryA2);
+
+ // Then
+ // New bubbles move to front, but stay behind any ongoing bubbles.
+ // Does not break grouping. (A2 is inserted after B1, even though it's newer).
+ assertThat(mBubbleData.getBubbles()).isEqualTo(
+ ImmutableList.of(mBubbleB2, mBubbleB1, mBubbleA2, mBubbleA1));
+ }
+
+ @Test
+ public void test_collapsed_removeBubble() {
+ // Given
+ assertThat(mBubbleData.hasBubbles()).isFalse();
+ assertThat(mBubbleData.isExpanded()).isFalse();
+
+ sendUpdatedEntryAtTime(mEntryA1, 1000);
+ sendUpdatedEntryAtTime(mEntryB1, 2000);
+ sendUpdatedEntryAtTime(mEntryB2, 3000);
+ sendUpdatedEntryAtTime(mEntryA2, 4000);
+
+ // When
+ mBubbleData.notificationEntryRemoved(mEntryB2, BubbleController.DISMISS_USER_GESTURE);
+
+ // Then
+ assertThat(mBubbleData.getBubbles()).isEqualTo(
+ ImmutableList.of(mBubbleA2, mBubbleA1, mBubbleB1));
+ }
+
+ @Test
+ public void test_collapsed_updateBubble() {
+ // Given
+ assertThat(mBubbleData.hasBubbles()).isFalse();
+ assertThat(mBubbleData.isExpanded()).isFalse();
+
+ sendUpdatedEntryAtTime(mEntryA1, 1000);
+ sendUpdatedEntryAtTime(mEntryB1, 2000);
+ sendUpdatedEntryAtTime(mEntryB2, 3000);
+ sendUpdatedEntryAtTime(mEntryA2, 4000);
+
+ assertThat(mBubbleData.getBubbles()).isEqualTo(
+ ImmutableList.of(mBubbleA2, mBubbleA1, mBubbleB2, mBubbleB1));
+
+ // When
+ sendUpdatedEntryAtTime(mEntryB2, 5000);
+
+ // Then
+ assertThat(mBubbleData.getBubbles()).isEqualTo(
+ ImmutableList.of(mBubbleB2, mBubbleB1, mBubbleA2, mBubbleA1));
+ }
+
+ @Test
+ public void test_collapsed_updateBubble_withOngoing() {
+ // Given
+ assertThat(mBubbleData.hasBubbles()).isFalse();
+ assertThat(mBubbleData.isExpanded()).isFalse();
+
+ setPostTime(mEntryA1, 1000);
+ mBubbleData.notificationEntryUpdated(mEntryA1);
+
+ setPostTime(mEntryB1, 2000);
+ mBubbleData.notificationEntryUpdated(mEntryB1);
+
+ setPostTime(mEntryB2, 3000);
+ mBubbleData.notificationEntryUpdated(mEntryB2);
+
+ setOngoing(mEntryA2, true);
+ setPostTime(mEntryA2, 4000);
+ mBubbleData.notificationEntryUpdated(mEntryA2);
+
+ assertThat(mBubbleData.getBubbles()).isEqualTo(
+ ImmutableList.of(mBubbleA2, mBubbleA1, mBubbleB2, mBubbleB1));
+
+ // When
+ setPostTime(mEntryB1, 5000);
+ mBubbleData.notificationEntryUpdated(mEntryB1);
+
+ // Then
+ // A2 remains in first position, due to being ongoing. B1 moves before B2, Group A
+ // remains before group B.
+ assertThat(mBubbleData.getBubbles()).isEqualTo(
+ ImmutableList.of(mBubbleA2, mBubbleA1, mBubbleB1, mBubbleB2));
+ }
+
+ @Test
+ public void test_collapse_afterUpdateWhileExpanded() {
+ // Given
+ assertThat(mBubbleData.hasBubbles()).isFalse();
+ assertThat(mBubbleData.isExpanded()).isFalse();
+
+ sendUpdatedEntryAtTime(mEntryA1, 1000);
+ sendUpdatedEntryAtTime(mEntryB1, 2000);
+ sendUpdatedEntryAtTime(mEntryB2, 3000);
+ sendUpdatedEntryAtTime(mEntryA2, 4000);
+
+ assertThat(mBubbleData.getSelectedBubble()).isEqualTo(mBubbleA1);
+
+ changeExpandedStateAtTime(true, 5000L);
+ assertThat(mBubbleData.getBubbles()).isEqualTo(
+ ImmutableList.of(mBubbleA2, mBubbleA1, mBubbleB2, mBubbleB1));
+
+ sendUpdatedEntryAtTime(mEntryB1, 6000);
+
+ // (No reordering while expanded)
+ assertThat(mBubbleData.getBubbles()).isEqualTo(
+ ImmutableList.of(mBubbleA2, mBubbleA1, mBubbleB2, mBubbleB1));
+
+ // When
+ changeExpandedStateAtTime(false, 7000L);
+
+ // Then
+ // A1 moves to front on collapse, since it is the selected bubble (and most recently
+ // accessed).
+ // A2 moves next to A1 to maintain grouping.
+ // B1 moves in front of B2, since it received an update while expanded
+ assertThat(mBubbleData.getBubbles()).isEqualTo(
+ ImmutableList.of(mBubbleA1, mBubbleA2, mBubbleB1, mBubbleB2));
+ }
+
+ @Test
+ public void test_collapse_afterUpdateWhileExpanded_withOngoing() {
+ // Given
+ assertThat(mBubbleData.hasBubbles()).isFalse();
+ assertThat(mBubbleData.isExpanded()).isFalse();
+
+ sendUpdatedEntryAtTime(mEntryA1, 1000);
+ sendUpdatedEntryAtTime(mEntryB1, 2000);
+
+ setOngoing(mEntryB2, true);
+ sendUpdatedEntryAtTime(mEntryB2, 3000);
+
+ sendUpdatedEntryAtTime(mEntryA2, 4000);
+
+ assertThat(mBubbleData.getSelectedBubble()).isEqualTo(mBubbleA1);
+
+ changeExpandedStateAtTime(true, 5000L);
+ assertThat(mBubbleData.getBubbles()).isEqualTo(
+ ImmutableList.of(mBubbleB2, mBubbleB1, mBubbleA2, mBubbleA1));
+
+ sendUpdatedEntryAtTime(mEntryA1, 6000);
+
+ // No reordering if expanded
+ assertThat(mBubbleData.getBubbles()).isEqualTo(
+ ImmutableList.of(mBubbleB2, mBubbleB1, mBubbleA2, mBubbleA1));
+
+ // When
+ changeExpandedStateAtTime(false, 7000L);
+
+ // Then
+ // B2 remains in first position because it is ongoing.
+ // B1 remains grouped with B2
+ // A1 moves in front of A2, since it is more recently updated (and is selected).
+ // B1 moves in front of B2, since it has more recent activity.
+ assertThat(mBubbleData.getBubbles()).isEqualTo(
+ ImmutableList.of(mBubbleB2, mBubbleB1, mBubbleA1, mBubbleA2));
+ }
+
+ @Test
+ public void test_collapsed_removeLastBubble_clearsSelectedBubble() {
+ // Given
+ assertThat(mBubbleData.hasBubbles()).isFalse();
+ assertThat(mBubbleData.isExpanded()).isFalse();
+
+ sendUpdatedEntryAtTime(mEntryA1, 1000);
+ sendUpdatedEntryAtTime(mEntryB1, 2000);
+ sendUpdatedEntryAtTime(mEntryB2, 3000);
+ sendUpdatedEntryAtTime(mEntryA2, 4000);
+
+ assertThat(mBubbleData.getSelectedBubble()).isEqualTo(mBubbleA1);
+
+ mBubbleData.notificationEntryRemoved(mEntryA1, BubbleController.DISMISS_USER_GESTURE);
+ mBubbleData.notificationEntryRemoved(mEntryB1, BubbleController.DISMISS_USER_GESTURE);
+ mBubbleData.notificationEntryRemoved(mEntryB2, BubbleController.DISMISS_USER_GESTURE);
+ mBubbleData.notificationEntryRemoved(mEntryA2, BubbleController.DISMISS_USER_GESTURE);
+
+ assertThat(mBubbleData.getSelectedBubble()).isNull();
+ }
+
+ @Test
+ public void test_expanded_addBubble_atMaxBubbles_expiresLeastActive() {
+ // Given
+ sendUpdatedEntryAtTime(mEntryA1, 1000);
+ assertThat(mBubbleData.getSelectedBubble()).isEqualTo(mBubbleA1);
+
+ changeExpandedStateAtTime(true, 2000L);
+ assertThat(mBubbleData.getSelectedBubble().getLastActivity()).isEqualTo(2000);
+
+ sendUpdatedEntryAtTime(mEntryA2, 3000);
+ sendUpdatedEntryAtTime(mEntryA3, 4000);
+ sendUpdatedEntryAtTime(mEntryB1, 5000);
+ sendUpdatedEntryAtTime(mEntryB2, 6000);
+ sendUpdatedEntryAtTime(mEntryB3, 7000);
+
+
+ // Then
+ // A1 would be removed, but it is selected and expanded, so it should not go away.
+ // Instead, fall through to removing A2 (the next oldest).
+ assertThat(mBubbleData.getBubbles()).doesNotContain(mEntryA2);
+ }
+
+ @Test
+ public void test_expanded_removeLastBubble_collapsesStack() {
+ // Given
+ setPostTime(mEntryA1, 1000);
+ mBubbleData.notificationEntryUpdated(mEntryA1);
+
+ setPostTime(mEntryB1, 2000);
+ mBubbleData.notificationEntryUpdated(mEntryB1);
+
+ setPostTime(mEntryB2, 3000);
+ mBubbleData.notificationEntryUpdated(mEntryC1);
+
+ mBubbleData.setExpanded(true);
+
+ mBubbleData.notificationEntryRemoved(mEntryA1, BubbleController.DISMISS_USER_GESTURE);
+ mBubbleData.notificationEntryRemoved(mEntryB1, BubbleController.DISMISS_USER_GESTURE);
+ mBubbleData.notificationEntryRemoved(mEntryC1, BubbleController.DISMISS_USER_GESTURE);
+
+ assertThat(mBubbleData.isExpanded()).isFalse();
+ assertThat(mBubbleData.getSelectedBubble()).isNull();
+ }
+
+ // Bubbles do not reorder while expanded
+ @Test
+ public void test_expanded_selection_collapseToTop() {
+ // Given
+ assertThat(mBubbleData.hasBubbles()).isFalse();
+ assertThat(mBubbleData.isExpanded()).isFalse();
+
+ sendUpdatedEntryAtTime(mEntryA1, 1000);
+ sendUpdatedEntryAtTime(mEntryA2, 2000);
+ sendUpdatedEntryAtTime(mEntryB1, 3000);
+
+ assertThat(mBubbleData.getBubbles()).isEqualTo(
+ ImmutableList.of(mBubbleB1, mBubbleA2, mBubbleA1));
+
+ changeExpandedStateAtTime(true, 4000L);
+
+ // regrouping only happens when collapsed (after new or update) or expanded->collapsed
+ assertThat(mBubbleData.getBubbles()).isEqualTo(
+ ImmutableList.of(mBubbleB1, mBubbleA2, mBubbleA1));
+
+ changeExpandedStateAtTime(false, 6000L);
+
+ // A1 is still selected and it's lastAccessed time has been updated
+ // on collapse, sorting is applied, keeping the selected bubble at the front
+ assertThat(mBubbleData.getSelectedBubble()).isEqualTo(mBubbleA1);
+ assertThat(mBubbleData.getBubbles()).isEqualTo(
+ ImmutableList.of(mBubbleA1, mBubbleA2, mBubbleB1));
+ }
+
+ // New bubble from new app while stack is expanded
+ @Test
+ public void test_expanded_addBubble_newApp() {
+ // Given
+ sendUpdatedEntryAtTime(mEntryA1, 1000);
+ sendUpdatedEntryAtTime(mEntryA2, 2000);
+ sendUpdatedEntryAtTime(mEntryA3, 3000);
+ sendUpdatedEntryAtTime(mEntryB1, 4000);
+ sendUpdatedEntryAtTime(mEntryB2, 5000);
+
+ assertThat(mBubbleData.getSelectedBubble()).isEqualTo(mBubbleA1);
+
+ changeExpandedStateAtTime(true, 6000L);
+
+ assertThat(mBubbleData.getSelectedBubble()).isEqualTo(mBubbleA1);
+ assertThat(mBubbleData.getSelectedBubble().getLastActivity()).isEqualTo(6000L);
+
+ // regrouping only happens when collapsed (after new or update) or expanded->collapsed
+ assertThat(mBubbleData.getBubbles()).isEqualTo(
+ ImmutableList.of(mBubbleB2, mBubbleB1, mBubbleA3, mBubbleA2, mBubbleA1));
+
+ // When
+ sendUpdatedEntryAtTime(mEntryC1, 7000);
+
+ // Then
+ // A2 is expired. A1 was oldest, but lastActivityTime is reset when expanded, since A1 is
+ // selected.
+ // C1 is added at the end since bubbles are expanded.
+ assertThat(mBubbleData.getBubbles()).isEqualTo(
+ ImmutableList.of(mBubbleB2, mBubbleB1, mBubbleA3, mBubbleA1, mBubbleC1));
+ }
+
+ // New bubble from existing app while stack is expanded
+ @Test
+ public void test_expanded_addBubble_existingApp() {
+ // Given
+ sendUpdatedEntryAtTime(mEntryB1, 1000);
+ sendUpdatedEntryAtTime(mEntryB2, 2000);
+ sendUpdatedEntryAtTime(mEntryA1, 3000);
+ sendUpdatedEntryAtTime(mEntryA2, 4000);
+ sendUpdatedEntryAtTime(mEntryA3, 5000);
+
+ assertThat(mBubbleData.getSelectedBubble()).isEqualTo(mBubbleB1);
+
+ changeExpandedStateAtTime(true, 6000L);
+
+ // B1 is first (newest, since it's just been expanded and is selected)
+ assertThat(mBubbleData.getSelectedBubble()).isEqualTo(mBubbleB1);
+ assertThat(mBubbleData.getSelectedBubble().getLastActivity()).isEqualTo(6000L);
+
+ // regrouping only happens when collapsed (after new or update) or while collapsing
+ assertThat(mBubbleData.getBubbles()).isEqualTo(
+ ImmutableList.of(mBubbleA3, mBubbleA2, mBubbleA1, mBubbleB2, mBubbleB1));
+
+ // When
+ sendUpdatedEntryAtTime(mEntryB3, 7000);
+
+ // Then
+ // (B2 is expired, B1 was oldest, but it's lastActivityTime is updated at the point when
+ // the stack was expanded, since it is the selected bubble.
+ assertThat(mBubbleData.getBubbles()).isEqualTo(
+ ImmutableList.of(mBubbleA3, mBubbleA2, mBubbleA1, mBubbleB3, mBubbleB1));
+ }
+
+ // Updated bubble from existing app while stack is expanded
+ @Test
+ public void test_expanded_updateBubble_existingApp() {
+ sendUpdatedEntryAtTime(mEntryA1, 1000);
+ sendUpdatedEntryAtTime(mEntryA2, 2000);
+ sendUpdatedEntryAtTime(mEntryB1, 3000);
+ sendUpdatedEntryAtTime(mEntryB2, 4000);
+
+ assertThat(mBubbleData.getBubbles()).isEqualTo(
+ ImmutableList.of(mBubbleB2, mBubbleB1, mBubbleA2, mBubbleA1));
+ mBubbleData.setExpanded(true);
+
+ sendUpdatedEntryAtTime(mEntryA1, 5000);
+
+ // Does not reorder while expanded (for an update).
+ assertThat(mBubbleData.getBubbles()).isEqualTo(
+ ImmutableList.of(mBubbleB2, mBubbleB1, mBubbleA2, mBubbleA1));
+ }
+
+ @Test
+ public void test_expanded_updateBubble() {
+ // Given
+ assertThat(mBubbleData.hasBubbles()).isFalse();
+ assertThat(mBubbleData.isExpanded()).isFalse();
+
+ setPostTime(mEntryA1, 1000);
+ mBubbleData.notificationEntryUpdated(mEntryA1);
+
+ setPostTime(mEntryB1, 2000);
+ mBubbleData.notificationEntryUpdated(mEntryB1);
+
+ setPostTime(mEntryB2, 3000);
+ mBubbleData.notificationEntryUpdated(mEntryB2);
+
+ setPostTime(mEntryA2, 4000);
+ mBubbleData.notificationEntryUpdated(mEntryA2);
+
+ mBubbleData.setExpanded(true);
+ assertThat(mBubbleData.getBubbles()).isEqualTo(
+ ImmutableList.of(mBubbleA2, mBubbleA1, mBubbleB2, mBubbleB1));
+
+ // When
+ setPostTime(mEntryB1, 5000);
+ mBubbleData.notificationEntryUpdated(mEntryB1);
+
+ // Then
+ // B1 remains in the same place due to being expanded
+ assertThat(mBubbleData.getBubbles()).isEqualTo(
+ ImmutableList.of(mBubbleA2, mBubbleA1, mBubbleB2, mBubbleB1));
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsColumnLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsColumnLayoutTest.java
new file mode 100644
index 0000000..16d665c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsColumnLayoutTest.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.globalactions;
+
+import static junit.framework.Assert.assertEquals;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.testing.AndroidTestingRunner;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.util.leak.RotationUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for {@link ListGridLayout}.
+ */
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class GlobalActionsColumnLayoutTest extends SysuiTestCase {
+
+ private GlobalActionsColumnLayout mColumnLayout;
+
+ @Before
+ public void setUp() throws Exception {
+ mColumnLayout = spy((GlobalActionsColumnLayout)
+ LayoutInflater.from(mContext).inflate(R.layout.global_actions_column, null));
+ }
+
+ @Test
+ public void testShouldReverseListItems() {
+ doReturn(View.LAYOUT_DIRECTION_LTR).when(mColumnLayout).getCurrentLayoutDirection();
+
+ doReturn(RotationUtils.ROTATION_LANDSCAPE).when(mColumnLayout).getCurrentRotation();
+ assertEquals(false, mColumnLayout.shouldReverseListItems());
+
+ doReturn(RotationUtils.ROTATION_NONE).when(mColumnLayout).getCurrentRotation();
+ assertEquals(false, mColumnLayout.shouldReverseListItems());
+
+ doReturn(RotationUtils.ROTATION_SEASCAPE).when(mColumnLayout).getCurrentRotation();
+ assertEquals(true, mColumnLayout.shouldReverseListItems());
+
+ doReturn(View.LAYOUT_DIRECTION_RTL).when(mColumnLayout).getCurrentLayoutDirection();
+
+ doReturn(RotationUtils.ROTATION_LANDSCAPE).when(mColumnLayout).getCurrentRotation();
+ assertEquals(true, mColumnLayout.shouldReverseListItems());
+
+ doReturn(RotationUtils.ROTATION_NONE).when(mColumnLayout).getCurrentRotation();
+ assertEquals(false, mColumnLayout.shouldReverseListItems());
+
+ doReturn(RotationUtils.ROTATION_SEASCAPE).when(mColumnLayout).getCurrentRotation();
+ assertEquals(false, mColumnLayout.shouldReverseListItems());
+ }
+
+ @Test
+ public void testGetAnimationOffsetX() {
+ doReturn(50f).when(mColumnLayout).getAnimationDistance();
+
+ doReturn(RotationUtils.ROTATION_NONE).when(mColumnLayout).getCurrentRotation();
+ assertEquals(50f, mColumnLayout.getAnimationOffsetX(), .01);
+
+ doReturn(RotationUtils.ROTATION_LANDSCAPE).when(mColumnLayout).getCurrentRotation();
+ assertEquals(0, mColumnLayout.getAnimationOffsetX(), .01);
+
+ doReturn(RotationUtils.ROTATION_SEASCAPE).when(mColumnLayout).getCurrentRotation();
+ assertEquals(0, mColumnLayout.getAnimationOffsetX(), .01);
+ }
+
+ @Test
+ public void testGetAnimationOffsetY() {
+ doReturn(50f).when(mColumnLayout).getAnimationDistance();
+
+ doReturn(RotationUtils.ROTATION_NONE).when(mColumnLayout).getCurrentRotation();
+ assertEquals(0, mColumnLayout.getAnimationOffsetY(), .01);
+
+ doReturn(RotationUtils.ROTATION_LANDSCAPE).when(mColumnLayout).getCurrentRotation();
+ assertEquals(-50f, mColumnLayout.getAnimationOffsetY(), .01);
+
+ doReturn(RotationUtils.ROTATION_SEASCAPE).when(mColumnLayout).getCurrentRotation();
+ assertEquals(50f, mColumnLayout.getAnimationOffsetY(), .01);
+ }
+
+ @Test
+ public void testSnapToPowerButton_portrait() {
+ doReturn(RotationUtils.ROTATION_NONE).when(mColumnLayout).getCurrentRotation();
+ doReturn(50).when(mColumnLayout).getPowerButtonOffsetDistance();
+
+ mColumnLayout.snapToPowerButton();
+ assertEquals(Gravity.TOP | Gravity.RIGHT, mColumnLayout.getGravity());
+ assertEquals(50, mColumnLayout.getPaddingTop(), .01);
+ }
+
+ @Test
+ public void testCenterAlongEdge_portrait() {
+ doReturn(RotationUtils.ROTATION_NONE).when(mColumnLayout).getCurrentRotation();
+
+ mColumnLayout.centerAlongEdge();
+ assertEquals(Gravity.CENTER_VERTICAL | Gravity.RIGHT, mColumnLayout.getGravity());
+ assertEquals(0, mColumnLayout.getPaddingTop(), .01);
+ }
+
+ @Test
+ public void testUpdateSnap_initialState() {
+ doReturn(false).when(mColumnLayout).shouldSnapToPowerButton();
+
+ mColumnLayout.updateSnap(); // should do nothing, since snap has not changed from init state
+
+ verify(mColumnLayout, times(0)).snapToPowerButton();
+ verify(mColumnLayout, times(0)).centerAlongEdge();
+ }
+
+ @Test
+ public void testUpdateSnap_snapThenSnap() {
+ doReturn(true).when(mColumnLayout).shouldSnapToPowerButton();
+
+ mColumnLayout.updateSnap(); // should snap to power button
+
+ verify(mColumnLayout, times(1)).snapToPowerButton();
+ verify(mColumnLayout, times(0)).centerAlongEdge();
+
+ mColumnLayout.updateSnap(); // should do nothing, since this is the same state as last time
+
+ verify(mColumnLayout, times(1)).snapToPowerButton();
+ verify(mColumnLayout, times(0)).centerAlongEdge();
+ }
+
+ @Test
+ public void testUpdateSnap_snapThenCenter() {
+ doReturn(true).when(mColumnLayout).shouldSnapToPowerButton();
+
+ mColumnLayout.updateSnap(); // should snap to power button
+
+ verify(mColumnLayout, times(1)).snapToPowerButton();
+ verify(mColumnLayout, times(0)).centerAlongEdge();
+
+ doReturn(false).when(mColumnLayout).shouldSnapToPowerButton();
+
+ mColumnLayout.updateSnap(); // should center to edge
+
+ verify(mColumnLayout, times(1)).snapToPowerButton();
+ verify(mColumnLayout, times(1)).centerAlongEdge();
+ }
+
+ @Test
+ public void testShouldSnapToPowerButton_vertical() {
+ doReturn(RotationUtils.ROTATION_NONE).when(mColumnLayout).getCurrentRotation();
+ doReturn(300).when(mColumnLayout).getPowerButtonOffsetDistance();
+ doReturn(1000).when(mColumnLayout).getMeasuredHeight();
+ View wrapper = spy(new View(mContext, null));
+ doReturn(wrapper).when(mColumnLayout).getWrapper();
+ doReturn(500).when(wrapper).getMeasuredHeight();
+
+ assertEquals(true, mColumnLayout.shouldSnapToPowerButton());
+
+ doReturn(600).when(mColumnLayout).getMeasuredHeight();
+
+ assertEquals(false, mColumnLayout.shouldSnapToPowerButton());
+ }
+
+ @Test
+ public void testShouldSnapToPowerButton_horizontal() {
+ doReturn(RotationUtils.ROTATION_LANDSCAPE).when(mColumnLayout).getCurrentRotation();
+ doReturn(300).when(mColumnLayout).getPowerButtonOffsetDistance();
+ doReturn(1000).when(mColumnLayout).getMeasuredWidth();
+ View wrapper = spy(new View(mContext, null));
+ doReturn(wrapper).when(mColumnLayout).getWrapper();
+ doReturn(500).when(wrapper).getMeasuredWidth();
+
+ assertEquals(true, mColumnLayout.shouldSnapToPowerButton());
+
+ doReturn(600).when(mColumnLayout).getMeasuredWidth();
+
+ assertEquals(false, mColumnLayout.shouldSnapToPowerButton());
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsGridLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsGridLayoutTest.java
index 3c52e9d..a396f3e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsGridLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsGridLayoutTest.java
@@ -18,12 +18,8 @@
import static junit.framework.Assert.assertEquals;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
import android.testing.AndroidTestingRunner;
import android.view.LayoutInflater;
@@ -32,7 +28,6 @@
import androidx.test.filters.SmallTest;
-import com.android.systemui.MultiListLayout;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.util.leak.RotationUtils;
@@ -49,61 +44,12 @@
public class GlobalActionsGridLayoutTest extends SysuiTestCase {
private GlobalActionsGridLayout mGridLayout;
- private TestAdapter mAdapter;
private ListGridLayout mListGrid;
- private class TestAdapter extends MultiListLayout.MultiListAdapter {
- @Override
- public void onClickItem(int index) { }
-
- @Override
- public boolean onLongClickItem(int index) {
- return true;
- }
-
- @Override
- public int countSeparatedItems() {
- return -1;
- }
-
- @Override
- public int countListItems() {
- return -1;
- }
-
- @Override
- public boolean shouldBeSeparated(int position) {
- return false;
- }
-
- @Override
- public int getCount() {
- return countSeparatedItems() + countListItems();
- }
-
- @Override
- public Object getItem(int position) {
- return null;
- }
-
- @Override
- public long getItemId(int position) {
- return -1;
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- return null;
- }
- }
-
-
@Before
public void setUp() throws Exception {
mGridLayout = spy((GlobalActionsGridLayout)
LayoutInflater.from(mContext).inflate(R.layout.global_actions_grid, null));
- mAdapter = spy(new TestAdapter());
- mGridLayout.setAdapter(mAdapter);
mListGrid = spy(mGridLayout.getListView());
doReturn(mListGrid).when(mGridLayout).getListView();
}
@@ -122,7 +68,7 @@
@Test
public void testShouldReverseListItems() {
- doReturn(View.LAYOUT_DIRECTION_LTR).when(mGridLayout).getLayoutDirection();
+ doReturn(View.LAYOUT_DIRECTION_LTR).when(mGridLayout).getCurrentLayoutDirection();
doReturn(RotationUtils.ROTATION_LANDSCAPE).when(mGridLayout).getCurrentRotation();
assertEquals(false, mGridLayout.shouldReverseListItems());
@@ -133,7 +79,7 @@
doReturn(RotationUtils.ROTATION_SEASCAPE).when(mGridLayout).getCurrentRotation();
assertEquals(true, mGridLayout.shouldReverseListItems());
- doReturn(View.LAYOUT_DIRECTION_RTL).when(mGridLayout).getLayoutDirection();
+ doReturn(View.LAYOUT_DIRECTION_RTL).when(mGridLayout).getCurrentLayoutDirection();
doReturn(RotationUtils.ROTATION_LANDSCAPE).when(mGridLayout).getCurrentRotation();
assertEquals(true, mGridLayout.shouldReverseListItems());
@@ -185,123 +131,26 @@
assertEquals(0f, mGridLayout.getAnimationOffsetY(), .01);
}
- @Test(expected = IllegalStateException.class)
- public void testOnUpdateList_noAdapter() {
- mGridLayout.setAdapter(null);
- mGridLayout.updateList();
- }
-
@Test
- public void testOnUpdateList_noItems() {
- doReturn(0).when(mAdapter).countSeparatedItems();
- doReturn(0).when(mAdapter).countListItems();
- mGridLayout.updateList();
-
- ViewGroup separatedView = mGridLayout.getSeparatedView();
- ListGridLayout listView = mGridLayout.getListView();
-
- assertEquals(0, separatedView.getChildCount());
- assertEquals(View.GONE, separatedView.getVisibility());
-
- verify(mListGrid, times(0)).addItem(any());
- }
-
- @Test
- public void testOnUpdateList_resizesFirstSeparatedItem() {
- doReturn(1).when(mAdapter).countSeparatedItems();
- doReturn(0).when(mAdapter).countListItems();
+ public void testUpdateSeparatedItemSize() {
View firstView = new View(mContext, null);
View secondView = new View(mContext, null);
- doReturn(firstView).when(mAdapter).getView(eq(0), any(), any());
- doReturn(true).when(mAdapter).shouldBeSeparated(0);
+ ViewGroup separatedView = mGridLayout.getSeparatedView();
+ separatedView.addView(firstView);
- mGridLayout.updateList();
+ mGridLayout.updateSeparatedItemSize();
ViewGroup.LayoutParams childParams = firstView.getLayoutParams();
assertEquals(ViewGroup.LayoutParams.MATCH_PARENT, childParams.width);
assertEquals(ViewGroup.LayoutParams.MATCH_PARENT, childParams.height);
- doReturn(2).when(mAdapter).countSeparatedItems();
- doReturn(secondView).when(mAdapter).getView(eq(1), any(), any());
- doReturn(true).when(mAdapter).shouldBeSeparated(1);
+ separatedView.addView(secondView);
- mGridLayout.updateList();
+ mGridLayout.updateSeparatedItemSize();
childParams = firstView.getLayoutParams();
assertEquals(ViewGroup.LayoutParams.WRAP_CONTENT, childParams.width);
assertEquals(ViewGroup.LayoutParams.WRAP_CONTENT, childParams.height);
-
-
- }
-
- @Test
- public void testOnUpdateList_onlySeparatedItems() {
- doReturn(1).when(mAdapter).countSeparatedItems();
- doReturn(0).when(mAdapter).countListItems();
- View testView = new View(mContext, null);
- doReturn(testView).when(mAdapter).getView(eq(0), any(), any());
- doReturn(true).when(mAdapter).shouldBeSeparated(0);
-
- mGridLayout.updateList();
-
- verify(mListGrid, times(0)).addItem(any());
- }
-
- @Test
- public void testOnUpdateList_oneSeparatedOneList() {
- doReturn(1).when(mAdapter).countSeparatedItems();
- doReturn(1).when(mAdapter).countListItems();
- View view1 = new View(mContext, null);
- View view2 = new View(mContext, null);
-
- doReturn(view1).when(mAdapter).getView(eq(0), any(), any());
- doReturn(true).when(mAdapter).shouldBeSeparated(0);
-
- doReturn(view2).when(mAdapter).getView(eq(1), any(), any());
- doReturn(false).when(mAdapter).shouldBeSeparated(1);
-
- mGridLayout.updateList();
-
- ViewGroup separatedView = mGridLayout.getSeparatedView();
-
- assertEquals(1, separatedView.getChildCount());
- assertEquals(View.VISIBLE, separatedView.getVisibility());
- assertEquals(view1, separatedView.getChildAt(0));
-
- verify(mListGrid, times(1)).addItem(view2);
- }
-
- @Test
- public void testOnUpdateList_fourInList() {
- doReturn(0).when(mAdapter).countSeparatedItems();
- doReturn(4).when(mAdapter).countListItems();
- View view1 = new View(mContext, null);
- View view2 = new View(mContext, null);
- View view3 = new View(mContext, null);
- View view4 = new View(mContext, null);
-
- doReturn(view1).when(mAdapter).getView(eq(0), any(), any());
- doReturn(false).when(mAdapter).shouldBeSeparated(0);
-
- doReturn(view2).when(mAdapter).getView(eq(1), any(), any());
- doReturn(false).when(mAdapter).shouldBeSeparated(1);
-
- doReturn(view3).when(mAdapter).getView(eq(2), any(), any());
- doReturn(false).when(mAdapter).shouldBeSeparated(2);
-
- doReturn(view4).when(mAdapter).getView(eq(3), any(), any());
- doReturn(false).when(mAdapter).shouldBeSeparated(3);
-
- mGridLayout.updateList();
-
- ViewGroup separatedView = mGridLayout.getSeparatedView();
- assertEquals(0, separatedView.getChildCount());
- assertEquals(View.GONE, separatedView.getVisibility());
-
- verify(mListGrid, times(1)).addItem(view1);
- verify(mListGrid, times(1)).addItem(view2);
- verify(mListGrid, times(1)).addItem(view3);
- verify(mListGrid, times(1)).addItem(view4);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsLayoutTest.java
new file mode 100644
index 0000000..16dcd65
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsLayoutTest.java
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.globalactions;
+
+import static junit.framework.Assert.assertEquals;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+
+import android.content.Context;
+import android.testing.AndroidTestingRunner;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.MultiListLayout;
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+
+/**
+ * Tests for {@link ListGridLayout}.
+ */
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class GlobalActionsLayoutTest extends SysuiTestCase {
+
+ private TestLayout mLayout;
+ private TestAdapter mAdapter;
+
+ private class TestAdapter extends MultiListLayout.MultiListAdapter {
+ @Override
+ public void onClickItem(int index) { }
+
+ @Override
+ public boolean onLongClickItem(int index) {
+ return true;
+ }
+
+ @Override
+ public int countSeparatedItems() {
+ return -1;
+ }
+
+ @Override
+ public int countListItems() {
+ return -1;
+ }
+
+ @Override
+ public boolean shouldBeSeparated(int position) {
+ return false;
+ }
+
+ @Override
+ public int getCount() {
+ return countSeparatedItems() + countListItems();
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return null;
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return -1;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ return null;
+ }
+ }
+
+ private class TestLayout extends GlobalActionsLayout {
+ ArrayList<View> mSeparatedViews = new ArrayList<>();
+ ArrayList<View> mListViews = new ArrayList<>();
+ boolean mSeparatedViewVisible = false;
+
+ TestLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected boolean shouldReverseListItems() {
+ return false;
+ }
+
+ @Override
+ public float getAnimationOffsetX() {
+ return 0;
+ }
+
+ @Override
+ public float getAnimationOffsetY() {
+ return 0;
+ }
+
+ @Override
+ protected void addToListView(View v, boolean reverse) {
+ if (reverse) {
+ mListViews.add(0, v);
+ } else {
+ mListViews.add(v);
+ }
+ }
+
+ @Override
+ protected void addToSeparatedView(View v, boolean reverse) {
+ if (reverse) {
+ mSeparatedViews.add(0, v);
+ } else {
+ mSeparatedViews.add(v);
+ }
+ }
+
+ @Override
+ protected void setSeparatedViewVisibility(boolean visible) {
+ mSeparatedViewVisible = visible;
+ }
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ mLayout = spy(new TestLayout(mContext, null));
+ mAdapter = spy(new TestAdapter());
+ mLayout.setAdapter(mAdapter);
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testOnUpdateList_noAdapter() {
+ mLayout.setAdapter(null);
+ mLayout.updateList();
+ }
+
+ @Test
+ public void testOnUpdateList_noItems() {
+ doReturn(0).when(mAdapter).countSeparatedItems();
+ doReturn(0).when(mAdapter).countListItems();
+ mLayout.updateList();
+
+ assertEquals(0, mLayout.mSeparatedViews.size());
+ assertEquals(0, mLayout.mListViews.size());
+
+ assertEquals(false, mLayout.mSeparatedViewVisible);
+ }
+
+ @Test
+ public void testOnUpdateList_oneSeparatedOneList() {
+ doReturn(1).when(mAdapter).countSeparatedItems();
+ doReturn(1).when(mAdapter).countListItems();
+ View view1 = new View(mContext, null);
+ View view2 = new View(mContext, null);
+
+ doReturn(view1).when(mAdapter).getView(eq(0), any(), any());
+ doReturn(true).when(mAdapter).shouldBeSeparated(0);
+
+ doReturn(view2).when(mAdapter).getView(eq(1), any(), any());
+ doReturn(false).when(mAdapter).shouldBeSeparated(1);
+
+ mLayout.updateList();
+
+ assertEquals(1, mLayout.mSeparatedViews.size());
+ assertEquals(1, mLayout.mListViews.size());
+ assertEquals(view1, mLayout.mSeparatedViews.get(0));
+ assertEquals(view2, mLayout.mListViews.get(0));
+ }
+
+
+ @Test
+ public void testOnUpdateList_twoSeparatedItems() {
+ doReturn(2).when(mAdapter).countSeparatedItems();
+ doReturn(0).when(mAdapter).countListItems();
+ View view1 = new View(mContext, null);
+ View view2 = new View(mContext, null);
+
+ doReturn(view1).when(mAdapter).getView(eq(0), any(), any());
+ doReturn(true).when(mAdapter).shouldBeSeparated(0);
+ doReturn(view2).when(mAdapter).getView(eq(1), any(), any());
+ doReturn(true).when(mAdapter).shouldBeSeparated(1);
+
+ mLayout.updateList();
+
+ assertEquals(2, mLayout.mSeparatedViews.size());
+ assertEquals(0, mLayout.mListViews.size());
+
+ assertEquals(view1, mLayout.mSeparatedViews.get(0));
+ assertEquals(view2, mLayout.mSeparatedViews.get(1));
+
+ // if separated view has items in it, should be made visible
+ assertEquals(true, mLayout.mSeparatedViewVisible);
+ }
+
+ @Test
+ public void testOnUpdateList_twoSeparatedItems_reverse() {
+ doReturn(2).when(mAdapter).countSeparatedItems();
+ doReturn(0).when(mAdapter).countListItems();
+ doReturn(true).when(mLayout).shouldReverseListItems();
+ View view1 = new View(mContext, null);
+ View view2 = new View(mContext, null);
+
+ doReturn(view1).when(mAdapter).getView(eq(0), any(), any());
+ doReturn(true).when(mAdapter).shouldBeSeparated(0);
+
+ doReturn(view2).when(mAdapter).getView(eq(1), any(), any());
+ doReturn(true).when(mAdapter).shouldBeSeparated(1);
+
+ mLayout.updateList();
+
+ assertEquals(2, mLayout.mSeparatedViews.size());
+ assertEquals(0, mLayout.mListViews.size());
+
+ // separated view items are not reversed in current implementation, and this is intentional!
+ assertEquals(view1, mLayout.mSeparatedViews.get(0));
+ assertEquals(view2, mLayout.mSeparatedViews.get(1));
+ }
+
+ @Test
+ public void testOnUpdateList_fourInList() {
+ doReturn(0).when(mAdapter).countSeparatedItems();
+ doReturn(4).when(mAdapter).countListItems();
+ View view1 = new View(mContext, null);
+ View view2 = new View(mContext, null);
+ View view3 = new View(mContext, null);
+ View view4 = new View(mContext, null);
+
+ doReturn(view1).when(mAdapter).getView(eq(0), any(), any());
+ doReturn(false).when(mAdapter).shouldBeSeparated(0);
+
+ doReturn(view2).when(mAdapter).getView(eq(1), any(), any());
+ doReturn(false).when(mAdapter).shouldBeSeparated(1);
+
+ doReturn(view3).when(mAdapter).getView(eq(2), any(), any());
+ doReturn(false).when(mAdapter).shouldBeSeparated(2);
+
+ doReturn(view4).when(mAdapter).getView(eq(3), any(), any());
+ doReturn(false).when(mAdapter).shouldBeSeparated(3);
+
+ mLayout.updateList();
+
+ assertEquals(0, mLayout.mSeparatedViews.size());
+ assertEquals(4, mLayout.mListViews.size());
+ assertEquals(view1, mLayout.mListViews.get(0));
+ assertEquals(view2, mLayout.mListViews.get(1));
+ assertEquals(view3, mLayout.mListViews.get(2));
+ assertEquals(view4, mLayout.mListViews.get(3));
+ }
+
+ @Test
+ public void testOnUpdateList_fourInList_reverse() {
+ doReturn(0).when(mAdapter).countSeparatedItems();
+ doReturn(4).when(mAdapter).countListItems();
+ doReturn(true).when(mLayout).shouldReverseListItems();
+ View view1 = new View(mContext, null);
+ View view2 = new View(mContext, null);
+ View view3 = new View(mContext, null);
+ View view4 = new View(mContext, null);
+
+ doReturn(view1).when(mAdapter).getView(eq(0), any(), any());
+ doReturn(false).when(mAdapter).shouldBeSeparated(0);
+
+ doReturn(view2).when(mAdapter).getView(eq(1), any(), any());
+ doReturn(false).when(mAdapter).shouldBeSeparated(1);
+
+ doReturn(view3).when(mAdapter).getView(eq(2), any(), any());
+ doReturn(false).when(mAdapter).shouldBeSeparated(2);
+
+ doReturn(view4).when(mAdapter).getView(eq(3), any(), any());
+ doReturn(false).when(mAdapter).shouldBeSeparated(3);
+
+ mLayout.updateList();
+
+ assertEquals(0, mLayout.mSeparatedViews.size());
+ assertEquals(4, mLayout.mListViews.size());
+ assertEquals(view1, mLayout.mListViews.get(3));
+ assertEquals(view2, mLayout.mListViews.get(2));
+ assertEquals(view3, mLayout.mListViews.get(1));
+ assertEquals(view4, mLayout.mListViews.get(0));
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
index c2f55e2..2bde5f6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -112,19 +112,19 @@
@Test
public void testSetSystemUiVisibility() {
Rect r = new Rect();
- mCommandQueue.setSystemUiVisibility(DEFAULT_DISPLAY, 1, 2, 3, 4, null, r);
+ mCommandQueue.setSystemUiVisibility(DEFAULT_DISPLAY, 1, 2, 3, 4, null, r, false);
waitForIdleSync();
verify(mCallbacks).setSystemUiVisibility(eq(DEFAULT_DISPLAY), eq(1), eq(2), eq(3), eq(4),
- eq(null), eq(r));
+ eq(null), eq(r), eq(false));
}
@Test
public void testSetSystemUiVisibilityForSecondaryDisplay() {
Rect r = new Rect();
- mCommandQueue.setSystemUiVisibility(SECONDARY_DISPLAY, 1, 2, 3, 4, null, r);
+ mCommandQueue.setSystemUiVisibility(SECONDARY_DISPLAY, 1, 2, 3, 4, null, r, false);
waitForIdleSync();
verify(mCallbacks).setSystemUiVisibility(eq(SECONDARY_DISPLAY), eq(1), eq(2), eq(3), eq(4),
- eq(null), eq(r));
+ eq(null), eq(r), eq(false));
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index ac536a5b..2858ba9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -284,10 +284,5 @@
verify(mUnlockMethodCache).addListener(eq(mController));
verify(mStatusBarStateController).addCallback(eq(mController));
verify(mKeyguardUpdateMonitor, times(2)).registerCallback(any());
-
- mController.destroy();
- verify(mUnlockMethodCache).removeListener(eq(mController));
- verify(mStatusBarStateController).removeCallback(eq(mController));
- verify(mKeyguardUpdateMonitor, times(2)).removeCallback(any());
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
index e4b90c5..028fd7a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
@@ -234,7 +234,7 @@
* @param bubbleMetadata the bubble metadata to use for this notification if it exists.
* @return a notification that is in the group specified or standalone if unspecified
*/
- private Notification createNotification(boolean isGroupSummary,
+ public Notification createNotification(boolean isGroupSummary,
@Nullable String groupKey, @Nullable BubbleMetadata bubbleMetadata) {
Notification publicVersion = new Notification.Builder(mContext).setSmallIcon(
R.drawable.ic_person)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
index 25995eb..7bd2580 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
@@ -891,7 +891,31 @@
}
@Test
- public void testWillBeRemovedReturnsFalseBeforeBind() throws Exception {
+ public void testCloseControls_withoutHittingApply() throws Exception {
+ mNotificationChannel.setImportance(IMPORTANCE_LOW);
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn,
+ (Runnable saveImportance, StatusBarNotification sbn) -> {
+ saveImportance.run();
+ }, null, null, true, false, IMPORTANCE_LOW, false
+ );
+
+ mNotificationInfo.findViewById(R.id.alert).performClick();
+
+ assertFalse(mNotificationInfo.shouldBeSaved());
+ }
+
+ @Test
+ public void testWillBeRemovedReturnsFalse() throws Exception {
+ assertFalse(mNotificationInfo.willBeRemoved());
+
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn,
+ (Runnable saveImportance, StatusBarNotification sbn) -> {
+ saveImportance.run();
+ }, null, null, true, false, IMPORTANCE_LOW, false
+ );
+
assertFalse(mNotificationInfo.willBeRemoved());
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java
index c62a802..43ea92f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java
@@ -112,11 +112,8 @@
}
@Test
- public void testNoAppOpsInSlowSwipe_newInterruptionModel() {
- Settings.Secure.putInt(mContext.getContentResolver(),
- NOTIFICATION_NEW_INTERRUPTION_MODEL, 1);
-
- NotificationMenuRow row = new NotificationMenuRow(mContext);
+ public void testNoAppOpsInSlowSwipe_biDirectionalSwipe() {
+ NotificationMenuRow row = new NotificationMenuRow(mContext, true);
row.createMenu(mRow, null);
ViewGroup container = (ViewGroup) row.getMenuView();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoHideControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoHideControllerTest.java
index 1b34a75..f614354 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoHideControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoHideControllerTest.java
@@ -70,7 +70,7 @@
@Test
public void testSetSystemUiVisibilityEarlyReturnWithDifferentDisplay() {
- mAutoHideController.setSystemUiVisibility(1, 1, 2, 3, 4, null, new Rect());
+ mAutoHideController.setSystemUiVisibility(1, 1, 2, 3, 4, null, new Rect(), false);
verify(mAutoHideController, never()).notifySystemUiVisibilityChanged(anyInt());
}
@@ -78,7 +78,8 @@
@Test
public void testSetSystemUiVisibilityEarlyReturnWithSameVisibility() {
mAutoHideController
- .setSystemUiVisibility(DEFAULT_DISPLAY, View.VISIBLE, 2, 3, 4, null, new Rect());
+ .setSystemUiVisibility(
+ DEFAULT_DISPLAY, View.VISIBLE, 2, 3, 4, null, new Rect(), false);
verify(mAutoHideController, never()).notifySystemUiVisibilityChanged(anyInt());
}
@@ -92,7 +93,7 @@
View.SYSTEM_UI_FLAG_FULLSCREEN | View.STATUS_BAR_UNHIDE;
mAutoHideController.setSystemUiVisibility(
- DEFAULT_DISPLAY, expectedStatus, 2, 3, FULL_MASK, null, new Rect());
+ DEFAULT_DISPLAY, expectedStatus, 2, 3, FULL_MASK, null, new Rect(), false);
assertEquals("System UI visibility should not be changed",
expectedStatus, mAutoHideController.mSystemUiVisibility);
@@ -109,7 +110,7 @@
mAutoHideController.setSystemUiVisibility(
DEFAULT_DISPLAY, View.STATUS_BAR_UNHIDE | View.NAVIGATION_BAR_UNHIDE,
- 2, 3, FULL_MASK, null, new Rect());
+ 2, 3, FULL_MASK, null, new Rect(), false);
int expectedStatus = View.VISIBLE;
assertEquals(expectedStatus, mAutoHideController.mSystemUiVisibility);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaTest.kt
index b95bb0a..688a6fb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaTest.kt
@@ -22,8 +22,6 @@
@Mock
private lateinit var mStatusBar: StatusBar
- @Mock
- private lateinit var mKeyguardIndicationController: KeyguardIndicationController
private lateinit var mKeyguardBottomArea: KeyguardBottomAreaView
@Before
@@ -32,7 +30,6 @@
mKeyguardBottomArea = LayoutInflater.from(mContext).inflate(
R.layout.keyguard_bottom_area, null, false) as KeyguardBottomAreaView
mKeyguardBottomArea.setStatusBar(mStatusBar)
- mKeyguardBottomArea.setKeyguardIndicationController(mKeyguardIndicationController)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarContextTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarContextTest.java
index c837c9c..cb70a1f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarContextTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarContextTest.java
@@ -80,7 +80,7 @@
@Test
public void testSetButtonVisibility() throws Exception {
- assertFalse("By default the group should be invisible.", mGroup.isVisible());
+ assertTrue("By default the group should be visible.", mGroup.isVisible());
// Set button 1 to be visible, make sure it is the only visible button
showButton(mBtn1);
@@ -89,7 +89,7 @@
assertFalse(mBtn2.isVisible());
// Hide button 1 and make sure the group is also invisible
- assertNotEquals(mGroup.setButtonVisiblity(BUTTON_1_ID, false /* visible */), View.VISIBLE);
+ assertNotEquals(mGroup.setButtonVisibility(BUTTON_1_ID, false /* visible */), View.VISIBLE);
assertFalse("No buttons are visible, group should also be hidden", mGroup.isVisible());
assertNull("No buttons should be visible", mGroup.getVisibleContextButton());
}
@@ -97,7 +97,7 @@
@Test(expected = RuntimeException.class)
public void testSetButtonVisibilityUnaddedButton() throws Exception {
int id = mBtn2.getId() + 1;
- mGroup.setButtonVisiblity(id, true /* visible */);
+ mGroup.setButtonVisibility(id, true /* visible */);
fail("Did not throw when setting a button with an invalid id");
}
@@ -120,17 +120,17 @@
assertTrue(mGroup.isButtonVisibleWithinGroup(mBtn2.getId()));
// Hide button 2
- assertNotEquals(mGroup.setButtonVisiblity(BUTTON_2_ID, false /* visible */), View.VISIBLE);
+ assertNotEquals(mGroup.setButtonVisibility(BUTTON_2_ID, false /* visible */), View.VISIBLE);
assertEquals("Hiding button 2 should show button 1", mBtn1,
mGroup.getVisibleContextButton());
// Hide button 1
- assertNotEquals(mGroup.setButtonVisiblity(BUTTON_1_ID, false /* visible */), View.VISIBLE);
+ assertNotEquals(mGroup.setButtonVisibility(BUTTON_1_ID, false /* visible */), View.VISIBLE);
assertEquals("Hiding button 1 should show button 0", mBtn0,
mGroup.getVisibleContextButton());
// Hide button 0, all buttons are now invisible
- assertNotEquals(mGroup.setButtonVisiblity(BUTTON_0_ID, false /* visible */), View.VISIBLE);
+ assertNotEquals(mGroup.setButtonVisibility(BUTTON_0_ID, false /* visible */), View.VISIBLE);
assertFalse("No buttons are visible, group should also be invisible", mGroup.isVisible());
assertNull(mGroup.getVisibleContextButton());
assertFalse(mGroup.isButtonVisibleWithinGroup(mBtn0.getId()));
@@ -144,7 +144,7 @@
showButton(mBtn2);
// Show button 1
- assertNotEquals(mGroup.setButtonVisiblity(BUTTON_1_ID, true /* visible */), View.VISIBLE);
+ assertNotEquals(mGroup.setButtonVisibility(BUTTON_1_ID, true /* visible */), View.VISIBLE);
assertTrue("Showing button 1 lower priority should be hidden but visible underneath",
mGroup.isButtonVisibleWithinGroup(BUTTON_1_ID));
assertFalse(mBtn0.isVisible());
@@ -152,7 +152,7 @@
assertTrue(mBtn2.isVisible());
// Hide button 1
- assertNotEquals(mGroup.setButtonVisiblity(BUTTON_1_ID, false /* visible */), View.VISIBLE);
+ assertNotEquals(mGroup.setButtonVisibility(BUTTON_1_ID, false /* visible */), View.VISIBLE);
assertFalse("Hiding button 1 with lower priority hides itself underneath",
mGroup.isButtonVisibleWithinGroup(BUTTON_1_ID));
assertTrue("A button still visible, group should also be visible", mGroup.isVisible());
@@ -180,9 +180,9 @@
final Drawable d = mock(Drawable.class);
final ContextualButton button = spy(mBtn0);
final KeyButtonDrawable kbd1 = spy(new KeyButtonDrawable(d, unusedColor, unusedColor,
- false /* horizontalFlip */));
+ false /* horizontalFlip */, false /* hasOvalBg */));
final KeyButtonDrawable kbd2 = spy(new KeyButtonDrawable(d, unusedColor, unusedColor,
- false /* horizontalFlip */));
+ false /* horizontalFlip */, false /* hasOvalBg */));
kbd1.setDarkIntensity(TEST_DARK_INTENSITY);
kbd2.setDarkIntensity(0f);
@@ -198,7 +198,7 @@
}
private void showButton(ContextualButton button) {
- assertEquals(View.VISIBLE, mGroup.setButtonVisiblity(button.getId(), true /* visible */));
+ assertEquals(View.VISIBLE, mGroup.setButtonVisibility(button.getId(), true /* visible */));
assertTrue("After set a button visible, group should also be visible", mGroup.isVisible());
assertEquals(button, mGroup.getVisibleContextButton());
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index d09cea5..1c6e3b0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -28,7 +28,6 @@
import android.content.Context;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
-import android.view.View;
import android.view.ViewGroup;
import androidx.test.filters.SmallTest;
@@ -39,7 +38,6 @@
import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.StatusBarState;
import org.junit.Before;
import org.junit.Test;
@@ -198,29 +196,6 @@
verify(mBouncer, never()).setExpansion(anyFloat());
}
- @Test
- public void onQsExpansionChanged_lockVisibleOnlyWhenCollapsed() {
- when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
- mStatusBarKeyguardViewManager.onQsExpansionChanged(0);
- verify(mLockIconContainer).setVisibility(eq(View.VISIBLE));
-
- reset(mNotificationPanelView);
- when(mNotificationPanelView.isQsExpanded()).thenReturn(true);
- mStatusBarKeyguardViewManager.onQsExpansionChanged(1f);
- verify(mLockIconContainer).setVisibility(eq(View.INVISIBLE));
- }
-
- @Test
- public void onQsExpansionChanged_lockInvisibleWhenAnimatingAway() {
- when(mBouncer.isShowing()).thenReturn(true);
- mStatusBarKeyguardViewManager.onQsExpansionChanged(0);
- verify(mLockIconContainer).setVisibility(eq(View.VISIBLE));
-
- when(mBouncer.isAnimatingAway()).thenReturn(true);
- mStatusBarKeyguardViewManager.onQsExpansionChanged(0f);
- verify(mLockIconContainer).setVisibility(eq(View.INVISIBLE));
- }
-
private class TestableStatusBarKeyguardViewManager extends StatusBarKeyguardViewManager {
public TestableStatusBarKeyguardViewManager(Context context,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index ce5bfce..616b46a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -130,6 +130,7 @@
when(mMockCm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(true);
when(mMockCm.getDefaultNetworkCapabilitiesForUser(0)).thenReturn(
new NetworkCapabilities[] { mNetCapabilities });
+ when(mMockTm.createForSubscriptionId(anyInt())).thenReturn(mMockTm);
mSignalStrength = mock(SignalStrength.class);
mServiceState = mock(ServiceState.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
index 8bf1606..bc468bf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
@@ -42,6 +42,7 @@
import com.android.systemui.statusbar.NotificationTestHelper;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.phone.LightBarController;
import com.android.systemui.util.Assert;
import org.junit.After;
@@ -67,6 +68,7 @@
@Mock private RemoteInputController mController;
@Mock private ShortcutManager mShortcutManager;
@Mock private RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
+ @Mock private LightBarController mLightBarController;
private BlockingQueueIntentReceiver mReceiver;
private RemoteInputView mView;
@@ -77,6 +79,8 @@
mDependency.injectTestDependency(RemoteInputQuickSettingsDisabler.class,
mRemoteInputQuickSettingsDisabler);
+ mDependency.injectTestDependency(LightBarController.class,
+ mLightBarController);
mReceiver = new BlockingQueueIntentReceiver();
mContext.registerReceiver(mReceiver, new IntentFilter(TEST_ACTION), null,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java
index fb2b7dc..c761a44 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java
@@ -229,8 +229,7 @@
}
private void triggerConstantsOnChange() {
- mConstants.onDeviceConfigPropertyChanged(DeviceConfig.NAMESPACE_SYSTEMUI,
- "" /* name */, "" /* value */);
+ mConstants.onDeviceConfigPropertiesChanged(DeviceConfig.NAMESPACE_SYSTEMUI);
}
private void resetAllDeviceConfigFlags() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
index 01f3c92..8c5fac4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
@@ -634,7 +634,8 @@
mView.getChildAt(2).performClick();
- verify(mActivityStarter, times(1)).startPendingIntentDismissingKeyguard(any(), any());
+ verify(mActivityStarter, times(1)).startPendingIntentDismissingKeyguard(any(), any(),
+ any());
}
@Test
@@ -645,7 +646,7 @@
mView.getChildAt(2).performClick();
- verify(mActivityStarter, never()).startPendingIntentDismissingKeyguard(any(), any());
+ verify(mActivityStarter, never()).startPendingIntentDismissingKeyguard(any(), any(), any());
}
@Test
@@ -657,7 +658,8 @@
Thread.sleep(delayMs);
mView.getChildAt(2).performClick();
- verify(mActivityStarter, times(1)).startPendingIntentDismissingKeyguard(any(), any());
+ verify(mActivityStarter, times(1)).startPendingIntentDismissingKeyguard(any(), any(),
+ any());
}
@Test
@@ -668,7 +670,8 @@
mView.getChildAt(2).performClick();
- verify(mActivityStarter, times(1)).startPendingIntentDismissingKeyguard(any(), any());
+ verify(mActivityStarter, times(1)).startPendingIntentDismissingKeyguard(any(), any(),
+ any());
}
@Test
diff --git a/packages/overlays/AccentColorBlackOverlay/Android.mk b/packages/overlays/AccentColorBlackOverlay/Android.mk
index b81ae5bb..a689def 100644
--- a/packages/overlays/AccentColorBlackOverlay/Android.mk
+++ b/packages/overlays/AccentColorBlackOverlay/Android.mk
@@ -18,7 +18,7 @@
include $(CLEAR_VARS)
LOCAL_RRO_THEME := AccentColorBlack
-LOCAL_CERTIFICATE := platform
+
LOCAL_PRODUCT_MODULE := true
LOCAL_SRC_FILES := $(call all-subdir-java-files)
diff --git a/packages/overlays/AccentColorCinnamonOverlay/Android.mk b/packages/overlays/AccentColorCinnamonOverlay/Android.mk
index d53c114..3a6cbe3 100644
--- a/packages/overlays/AccentColorCinnamonOverlay/Android.mk
+++ b/packages/overlays/AccentColorCinnamonOverlay/Android.mk
@@ -18,7 +18,7 @@
include $(CLEAR_VARS)
LOCAL_RRO_THEME := AccentColorCinnamon
-LOCAL_CERTIFICATE := platform
+
LOCAL_PRODUCT_MODULE := true
LOCAL_SRC_FILES := $(call all-subdir-java-files)
diff --git a/packages/overlays/AccentColorGreenOverlay/Android.mk b/packages/overlays/AccentColorGreenOverlay/Android.mk
index db92157..d96dbe1 100644
--- a/packages/overlays/AccentColorGreenOverlay/Android.mk
+++ b/packages/overlays/AccentColorGreenOverlay/Android.mk
@@ -18,7 +18,7 @@
include $(CLEAR_VARS)
LOCAL_RRO_THEME := AccentColorGreen
-LOCAL_CERTIFICATE := platform
+
LOCAL_PRODUCT_MODULE := true
LOCAL_SRC_FILES := $(call all-subdir-java-files)
diff --git a/packages/overlays/AccentColorOceanOverlay/Android.mk b/packages/overlays/AccentColorOceanOverlay/Android.mk
index a28fc72..cf0c6b3 100644
--- a/packages/overlays/AccentColorOceanOverlay/Android.mk
+++ b/packages/overlays/AccentColorOceanOverlay/Android.mk
@@ -18,7 +18,7 @@
include $(CLEAR_VARS)
LOCAL_RRO_THEME := AccentColorOcean
-LOCAL_CERTIFICATE := platform
+
LOCAL_PRODUCT_MODULE := true
LOCAL_SRC_FILES := $(call all-subdir-java-files)
diff --git a/packages/overlays/AccentColorOrchidOverlay/Android.mk b/packages/overlays/AccentColorOrchidOverlay/Android.mk
index c635890..fc55bef 100644
--- a/packages/overlays/AccentColorOrchidOverlay/Android.mk
+++ b/packages/overlays/AccentColorOrchidOverlay/Android.mk
@@ -18,7 +18,7 @@
include $(CLEAR_VARS)
LOCAL_RRO_THEME := AccentColorOrchid
-LOCAL_CERTIFICATE := platform
+
LOCAL_PRODUCT_MODULE := true
LOCAL_SRC_FILES := $(call all-subdir-java-files)
diff --git a/packages/overlays/AccentColorPurpleOverlay/Android.mk b/packages/overlays/AccentColorPurpleOverlay/Android.mk
index d7dc497..3a28efa 100644
--- a/packages/overlays/AccentColorPurpleOverlay/Android.mk
+++ b/packages/overlays/AccentColorPurpleOverlay/Android.mk
@@ -18,7 +18,7 @@
include $(CLEAR_VARS)
LOCAL_RRO_THEME := AccentColorPurple
-LOCAL_CERTIFICATE := platform
+
LOCAL_PRODUCT_MODULE := true
LOCAL_SRC_FILES := $(call all-subdir-java-files)
diff --git a/packages/overlays/AccentColorSpaceOverlay/Android.mk b/packages/overlays/AccentColorSpaceOverlay/Android.mk
index a0edb96..78cbf73 100644
--- a/packages/overlays/AccentColorSpaceOverlay/Android.mk
+++ b/packages/overlays/AccentColorSpaceOverlay/Android.mk
@@ -18,7 +18,7 @@
include $(CLEAR_VARS)
LOCAL_RRO_THEME := AccentColorSpace
-LOCAL_CERTIFICATE := platform
+
LOCAL_PRODUCT_MODULE := true
LOCAL_SRC_FILES := $(call all-subdir-java-files)
diff --git a/packages/overlays/DisplayCutoutEmulationCornerOverlay/Android.mk b/packages/overlays/DisplayCutoutEmulationCornerOverlay/Android.mk
index bf2b631..b73aea3 100644
--- a/packages/overlays/DisplayCutoutEmulationCornerOverlay/Android.mk
+++ b/packages/overlays/DisplayCutoutEmulationCornerOverlay/Android.mk
@@ -2,7 +2,7 @@
include $(CLEAR_VARS)
LOCAL_RRO_THEME := DisplayCutoutEmulationCorner
-LOCAL_CERTIFICATE := platform
+
LOCAL_PRODUCT_MODULE := true
diff --git a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/Android.mk b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/Android.mk
index 7042906..8ca2dad 100644
--- a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/Android.mk
+++ b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/Android.mk
@@ -2,7 +2,7 @@
include $(CLEAR_VARS)
LOCAL_RRO_THEME := DisplayCutoutEmulationDouble
-LOCAL_CERTIFICATE := platform
+
LOCAL_PRODUCT_MODULE := true
diff --git a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/Android.mk b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/Android.mk
index ae69e11..7458cb5 100644
--- a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/Android.mk
+++ b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/Android.mk
@@ -2,7 +2,7 @@
include $(CLEAR_VARS)
LOCAL_RRO_THEME := DisplayCutoutEmulationNarrow
-LOCAL_CERTIFICATE := platform
+
LOCAL_PRODUCT_MODULE := true
diff --git a/packages/overlays/DisplayCutoutEmulationTallOverlay/Android.mk b/packages/overlays/DisplayCutoutEmulationTallOverlay/Android.mk
index 7dcadfb..1a405e2 100644
--- a/packages/overlays/DisplayCutoutEmulationTallOverlay/Android.mk
+++ b/packages/overlays/DisplayCutoutEmulationTallOverlay/Android.mk
@@ -2,7 +2,7 @@
include $(CLEAR_VARS)
LOCAL_RRO_THEME := DisplayCutoutEmulationTall
-LOCAL_CERTIFICATE := platform
+
LOCAL_PRODUCT_MODULE := true
diff --git a/packages/overlays/DisplayCutoutEmulationWideOverlay/Android.mk b/packages/overlays/DisplayCutoutEmulationWideOverlay/Android.mk
index 3f7be73..3ebc540 100644
--- a/packages/overlays/DisplayCutoutEmulationWideOverlay/Android.mk
+++ b/packages/overlays/DisplayCutoutEmulationWideOverlay/Android.mk
@@ -2,7 +2,7 @@
include $(CLEAR_VARS)
LOCAL_RRO_THEME := DisplayCutoutEmulationWide
-LOCAL_CERTIFICATE := platform
+
LOCAL_PRODUCT_MODULE := true
diff --git a/packages/overlays/FontNotoSerifSourceOverlay/Android.mk b/packages/overlays/FontNotoSerifSourceOverlay/Android.mk
index 6f3c4f7..f4eedaf 100644
--- a/packages/overlays/FontNotoSerifSourceOverlay/Android.mk
+++ b/packages/overlays/FontNotoSerifSourceOverlay/Android.mk
@@ -18,7 +18,7 @@
include $(CLEAR_VARS)
LOCAL_RRO_THEME := FontNotoSerifSource
-LOCAL_CERTIFICATE := platform
+
LOCAL_PRODUCT_MODULE := true
LOCAL_SRC_FILES := $(call all-subdir-java-files)
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/Android.mk b/packages/overlays/IconPackCircularAndroidOverlay/Android.mk
index 60f525b6..8f3baa5 100644
--- a/packages/overlays/IconPackCircularAndroidOverlay/Android.mk
+++ b/packages/overlays/IconPackCircularAndroidOverlay/Android.mk
@@ -17,7 +17,7 @@
include $(CLEAR_VARS)
LOCAL_RRO_THEME := IconPackCircularAndroid
-LOCAL_CERTIFICATE := platform
+
LOCAL_PRODUCT_MODULE := true
LOCAL_SRC_FILES := $(call all-subdir-java-files)
diff --git a/packages/overlays/IconPackCircularLauncherOverlay/Android.mk b/packages/overlays/IconPackCircularLauncherOverlay/Android.mk
index a5277fa..310bdef 100644
--- a/packages/overlays/IconPackCircularLauncherOverlay/Android.mk
+++ b/packages/overlays/IconPackCircularLauncherOverlay/Android.mk
@@ -18,7 +18,7 @@
include $(CLEAR_VARS)
LOCAL_RRO_THEME := IconPackCircularLauncher
-LOCAL_CERTIFICATE := platform
+
LOCAL_PRODUCT_MODULE := true
LOCAL_SRC_FILES := $(call all-subdir-java-files)
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/Android.mk b/packages/overlays/IconPackCircularSettingsOverlay/Android.mk
index ad7324d..d067322 100644
--- a/packages/overlays/IconPackCircularSettingsOverlay/Android.mk
+++ b/packages/overlays/IconPackCircularSettingsOverlay/Android.mk
@@ -18,7 +18,7 @@
include $(CLEAR_VARS)
LOCAL_RRO_THEME := IconPackCircularSettings
-LOCAL_CERTIFICATE := platform
+
LOCAL_PRODUCT_MODULE := true
LOCAL_SRC_FILES := $(call all-subdir-java-files)
diff --git a/packages/overlays/IconPackCircularSystemUIOverlay/Android.mk b/packages/overlays/IconPackCircularSystemUIOverlay/Android.mk
index 711063d..5e0dcbe 100644
--- a/packages/overlays/IconPackCircularSystemUIOverlay/Android.mk
+++ b/packages/overlays/IconPackCircularSystemUIOverlay/Android.mk
@@ -18,7 +18,7 @@
include $(CLEAR_VARS)
LOCAL_RRO_THEME := IconPackCircularSystemUI
-LOCAL_CERTIFICATE := platform
+
LOCAL_PRODUCT_MODULE := true
LOCAL_SRC_FILES := $(call all-subdir-java-files)
diff --git a/packages/overlays/IconPackFilledAndroidOverlay/Android.mk b/packages/overlays/IconPackFilledAndroidOverlay/Android.mk
index e0db3a2..3036f7d 100644
--- a/packages/overlays/IconPackFilledAndroidOverlay/Android.mk
+++ b/packages/overlays/IconPackFilledAndroidOverlay/Android.mk
@@ -17,7 +17,7 @@
include $(CLEAR_VARS)
LOCAL_RRO_THEME := IconPackFilledAndroid
-LOCAL_CERTIFICATE := platform
+
LOCAL_PRODUCT_MODULE := true
LOCAL_SRC_FILES := $(call all-subdir-java-files)
diff --git a/packages/overlays/IconPackFilledLauncherOverlay/Android.mk b/packages/overlays/IconPackFilledLauncherOverlay/Android.mk
index d2e5b60..2460fa4 100644
--- a/packages/overlays/IconPackFilledLauncherOverlay/Android.mk
+++ b/packages/overlays/IconPackFilledLauncherOverlay/Android.mk
@@ -18,7 +18,7 @@
include $(CLEAR_VARS)
LOCAL_RRO_THEME := IconPackFilledLauncher
-LOCAL_CERTIFICATE := platform
+
LOCAL_PRODUCT_MODULE := true
LOCAL_SRC_FILES := $(call all-subdir-java-files)
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/Android.mk b/packages/overlays/IconPackFilledSettingsOverlay/Android.mk
index 0443560..3cc071d 100644
--- a/packages/overlays/IconPackFilledSettingsOverlay/Android.mk
+++ b/packages/overlays/IconPackFilledSettingsOverlay/Android.mk
@@ -18,7 +18,7 @@
include $(CLEAR_VARS)
LOCAL_RRO_THEME := IconPackFilledSettings
-LOCAL_CERTIFICATE := platform
+
LOCAL_PRODUCT_MODULE := true
LOCAL_SRC_FILES := $(call all-subdir-java-files)
diff --git a/packages/overlays/IconPackFilledSystemUIOverlay/Android.mk b/packages/overlays/IconPackFilledSystemUIOverlay/Android.mk
index 2506132..f027692 100644
--- a/packages/overlays/IconPackFilledSystemUIOverlay/Android.mk
+++ b/packages/overlays/IconPackFilledSystemUIOverlay/Android.mk
@@ -18,7 +18,7 @@
include $(CLEAR_VARS)
LOCAL_RRO_THEME := IconPackFilledSystemUI
-LOCAL_CERTIFICATE := platform
+
LOCAL_PRODUCT_MODULE := true
LOCAL_SRC_FILES := $(call all-subdir-java-files)
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/Android.mk b/packages/overlays/IconPackRoundedAndroidOverlay/Android.mk
index 2937fb8..c6ad4ac 100644
--- a/packages/overlays/IconPackRoundedAndroidOverlay/Android.mk
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/Android.mk
@@ -17,7 +17,7 @@
include $(CLEAR_VARS)
LOCAL_RRO_THEME := IconPackRoundedAndroid
-LOCAL_CERTIFICATE := platform
+
LOCAL_PRODUCT_MODULE := true
LOCAL_SRC_FILES := $(call all-subdir-java-files)
diff --git a/packages/overlays/IconPackRoundedLauncherOverlay/Android.mk b/packages/overlays/IconPackRoundedLauncherOverlay/Android.mk
index 7adfe3b..713e281 100644
--- a/packages/overlays/IconPackRoundedLauncherOverlay/Android.mk
+++ b/packages/overlays/IconPackRoundedLauncherOverlay/Android.mk
@@ -18,7 +18,7 @@
include $(CLEAR_VARS)
LOCAL_RRO_THEME := IconPackRoundedLauncher
-LOCAL_CERTIFICATE := platform
+
LOCAL_PRODUCT_MODULE := true
LOCAL_SRC_FILES := $(call all-subdir-java-files)
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/Android.mk b/packages/overlays/IconPackRoundedSettingsOverlay/Android.mk
index 44ac6dd..6c77519 100644
--- a/packages/overlays/IconPackRoundedSettingsOverlay/Android.mk
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/Android.mk
@@ -18,7 +18,7 @@
include $(CLEAR_VARS)
LOCAL_RRO_THEME := IconPackRoundedSettings
-LOCAL_CERTIFICATE := platform
+
LOCAL_PRODUCT_MODULE := true
LOCAL_SRC_FILES := $(call all-subdir-java-files)
diff --git a/packages/overlays/IconPackRoundedSystemUIOverlay/Android.mk b/packages/overlays/IconPackRoundedSystemUIOverlay/Android.mk
index 2d34a54..4e21b41 100644
--- a/packages/overlays/IconPackRoundedSystemUIOverlay/Android.mk
+++ b/packages/overlays/IconPackRoundedSystemUIOverlay/Android.mk
@@ -18,7 +18,7 @@
include $(CLEAR_VARS)
LOCAL_RRO_THEME := IconPackRoundedSystemUI
-LOCAL_CERTIFICATE := platform
+
LOCAL_PRODUCT_MODULE := true
LOCAL_SRC_FILES := $(call all-subdir-java-files)
diff --git a/packages/overlays/IconShapeRoundedRectOverlay/Android.mk b/packages/overlays/IconShapeRoundedRectOverlay/Android.mk
index 08428d1..21cd011 100644
--- a/packages/overlays/IconShapeRoundedRectOverlay/Android.mk
+++ b/packages/overlays/IconShapeRoundedRectOverlay/Android.mk
@@ -18,7 +18,7 @@
include $(CLEAR_VARS)
LOCAL_RRO_THEME := IconShapeRoundedRect
-LOCAL_CERTIFICATE := platform
+
LOCAL_PRODUCT_MODULE := true
LOCAL_SRC_FILES := $(call all-subdir-java-files)
diff --git a/packages/overlays/IconShapeSquareOverlay/Android.mk b/packages/overlays/IconShapeSquareOverlay/Android.mk
index ceb745a..c872883 100644
--- a/packages/overlays/IconShapeSquareOverlay/Android.mk
+++ b/packages/overlays/IconShapeSquareOverlay/Android.mk
@@ -18,7 +18,7 @@
include $(CLEAR_VARS)
LOCAL_RRO_THEME := IconShapeSquare
-LOCAL_CERTIFICATE := platform
+
LOCAL_PRODUCT_MODULE := true
LOCAL_SRC_FILES := $(call all-subdir-java-files)
diff --git a/packages/overlays/IconShapeSquircleOverlay/Android.mk b/packages/overlays/IconShapeSquircleOverlay/Android.mk
index 34edc3b..fa5fe69 100644
--- a/packages/overlays/IconShapeSquircleOverlay/Android.mk
+++ b/packages/overlays/IconShapeSquircleOverlay/Android.mk
@@ -18,7 +18,7 @@
include $(CLEAR_VARS)
LOCAL_RRO_THEME := IconShapeSquircle
-LOCAL_CERTIFICATE := platform
+
LOCAL_PRODUCT_MODULE := true
LOCAL_SRC_FILES := $(call all-subdir-java-files)
diff --git a/packages/overlays/IconShapeTeardropOverlay/Android.mk b/packages/overlays/IconShapeTeardropOverlay/Android.mk
index 834a1c3..d5f01f3 100644
--- a/packages/overlays/IconShapeTeardropOverlay/Android.mk
+++ b/packages/overlays/IconShapeTeardropOverlay/Android.mk
@@ -18,7 +18,7 @@
include $(CLEAR_VARS)
LOCAL_RRO_THEME := IconShapeTeardrop
-LOCAL_CERTIFICATE := platform
+
LOCAL_PRODUCT_MODULE := true
LOCAL_SRC_FILES := $(call all-subdir-java-files)
diff --git a/packages/overlays/NavigationBarMode2ButtonOverlay/Android.mk b/packages/overlays/NavigationBarMode2ButtonOverlay/Android.mk
index 410d6d8..be86ef2 100644
--- a/packages/overlays/NavigationBarMode2ButtonOverlay/Android.mk
+++ b/packages/overlays/NavigationBarMode2ButtonOverlay/Android.mk
@@ -18,7 +18,7 @@
include $(CLEAR_VARS)
LOCAL_RRO_THEME := NavigationBarMode2Button
-LOCAL_CERTIFICATE := platform
+
LOCAL_SRC_FILES := $(call all-subdir-java-files)
diff --git a/packages/overlays/NavigationBarMode3ButtonOverlay/Android.mk b/packages/overlays/NavigationBarMode3ButtonOverlay/Android.mk
index 2bc9a6a..f44a362 100644
--- a/packages/overlays/NavigationBarMode3ButtonOverlay/Android.mk
+++ b/packages/overlays/NavigationBarMode3ButtonOverlay/Android.mk
@@ -18,7 +18,7 @@
include $(CLEAR_VARS)
LOCAL_RRO_THEME := NavigationBarMode3Button
-LOCAL_CERTIFICATE := platform
+
LOCAL_SRC_FILES := $(call all-subdir-java-files)
diff --git a/packages/overlays/NavigationBarModeGesturalOverlay/Android.mk b/packages/overlays/NavigationBarModeGesturalOverlay/Android.mk
index 5f7e0eb..02e2074 100644
--- a/packages/overlays/NavigationBarModeGesturalOverlay/Android.mk
+++ b/packages/overlays/NavigationBarModeGesturalOverlay/Android.mk
@@ -18,7 +18,7 @@
include $(CLEAR_VARS)
LOCAL_RRO_THEME := NavigationBarModeGestural
-LOCAL_CERTIFICATE := platform
+
LOCAL_SRC_FILES := $(call all-subdir-java-files)
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index 21c6035..fe92d45 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -7206,6 +7206,13 @@
// ACTION: Share Wi-Fi hotspot by generating a QR code
ACTION_SETTINGS_SHARE_WIFI_HOTSPOT_QR_CODE = 1712;
+ // OPEN: Settings > Network & internet > Mobile network > Delete sim
+ DIALOG_DELETE_SIM_CONFIRMATION = 1713;
+
+ // OPEN: Settings > Network & internet > Mobile network > Delete sim > (answer yes to
+ // confirmation)
+ DIALOG_DELETE_SIM_PROGRESS = 1714;
+
// ---- End Q Constants, all Q constants go above this line ----
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index a94d1dc..a64f4e4 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -94,6 +94,7 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Set;
/**
* Entry point service for autofill management.
@@ -192,9 +193,9 @@
mUi = new AutoFillUI(ActivityThread.currentActivityThread().getSystemUiContext());
mAm = LocalServices.getService(ActivityManagerInternal.class);
- DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_AUTOFILL,
+ DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_AUTOFILL,
ActivityThread.currentApplication().getMainExecutor(),
- (namespace, key, value) -> onDeviceConfigChange(key));
+ (properties) -> onDeviceConfigChange(properties.getKeyset()));
setLogLevelFromSettings();
setMaxPartitionsFromSettings();
@@ -270,15 +271,17 @@
}
}
- private void onDeviceConfigChange(@NonNull String key) {
- switch (key) {
- case AutofillManager.DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES:
- case AutofillManager.DEVICE_CONFIG_AUGMENTED_SERVICE_IDLE_UNBIND_TIMEOUT:
- case AutofillManager.DEVICE_CONFIG_AUGMENTED_SERVICE_REQUEST_TIMEOUT:
- setDeviceConfigProperties();
- break;
- default:
- Slog.i(mTag, "Ignoring change on " + key);
+ private void onDeviceConfigChange(@NonNull Set<String> keys) {
+ for (String key : keys) {
+ switch (key) {
+ case AutofillManager.DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES:
+ case AutofillManager.DEVICE_CONFIG_AUGMENTED_SERVICE_IDLE_UNBIND_TIMEOUT:
+ case AutofillManager.DEVICE_CONFIG_AUGMENTED_SERVICE_REQUEST_TIMEOUT:
+ setDeviceConfigProperties();
+ break;
+ default:
+ Slog.i(mTag, "Ignoring change on " + key);
+ }
}
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index f1963b3..386dec4 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -57,6 +57,7 @@
import android.service.autofill.FillEventHistory.Event;
import android.service.autofill.FillResponse;
import android.service.autofill.IAutoFillService;
+import android.service.autofill.SaveInfo;
import android.service.autofill.UserData;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -595,8 +596,8 @@
ArrayList<Session> previousSessions = null;
for (int i = 0; i < size; i++) {
final Session previousSession = mSessions.valueAt(i);
- // TODO(b/113281366): only return sessions asked to be kept alive / add CTS test
- if (previousSession.taskId == session.taskId && previousSession.id != session.id) {
+ if (previousSession.taskId == session.taskId && previousSession.id != session.id
+ && (previousSession.getSaveInfoFlagsLocked() & SaveInfo.FLAG_DELAY_SAVE) != 0) {
if (previousSessions == null) {
previousSessions = new ArrayList<>(size);
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 9e73684d..7b97353 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -33,7 +33,6 @@
import static com.android.server.autofill.Helper.sDebug;
import static com.android.server.autofill.Helper.sVerbose;
import static com.android.server.autofill.Helper.toArray;
-import static com.android.server.autofill.ViewState.STATE_RESTARTED_SESSION;
import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_RECEIVER_EXTRAS;
import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_STRUCTURE;
@@ -564,7 +563,8 @@
* Reads a new structure and then request a new fill response from the fill service.
*/
@GuardedBy("mLock")
- private void requestNewFillResponseLocked(int flags) {
+ private void requestNewFillResponseLocked(@NonNull ViewState viewState, int newState,
+ int flags) {
if (mForAugmentedAutofillOnly || (flags & FLAG_AUGMENTED_AUTOFILL_REQUEST) != 0) {
// TODO(b/122858578): log metrics
if (sVerbose) {
@@ -575,6 +575,7 @@
triggerAugmentedAutofillLocked();
return;
}
+ viewState.setState(newState);
int requestId;
@@ -1202,9 +1203,12 @@
@GuardedBy("mLock")
@Nullable
- private FillResponse getLastResponseLocked(@Nullable String logPrefix) {
+ private FillResponse getLastResponseLocked(@Nullable String logPrefixFmt) {
+ final String logPrefix = sDebug && logPrefixFmt != null
+ ? String.format(logPrefixFmt, this.id)
+ : null;
if (mContexts == null) {
- if (sDebug && logPrefix != null) Slog.d(TAG, logPrefix + ": no contexts");
+ if (logPrefix != null) Slog.d(TAG, logPrefix + ": no contexts");
return null;
}
if (mResponses == null) {
@@ -1240,6 +1244,12 @@
return response == null ? null : response.getSaveInfo();
}
+ @GuardedBy("mLock")
+ int getSaveInfoFlagsLocked() {
+ final SaveInfo saveInfo = getSaveInfoLocked();
+ return saveInfo == null ? 0 : saveInfo.getFlags();
+ }
+
/**
* Generates a {@link android.service.autofill.FillEventHistory.Event#TYPE_CONTEXT_COMMITTED}
* when necessary.
@@ -1251,7 +1261,7 @@
private void handleLogContextCommitted() {
final FillResponse lastResponse;
synchronized (mLock) {
- lastResponse = getLastResponseLocked("logContextCommited()");
+ lastResponse = getLastResponseLocked("logContextCommited(%s)");
}
if (lastResponse == null) {
@@ -1294,7 +1304,7 @@
@GuardedBy("mLock")
private void logContextCommittedLocked(@Nullable ArrayList<AutofillId> detectedFieldIds,
@Nullable ArrayList<FieldClassification> detectedFieldClassifications) {
- final FillResponse lastResponse = getLastResponseLocked("logContextCommited()");
+ final FillResponse lastResponse = getLastResponseLocked("logContextCommited(%s)");
if (lastResponse == null) return;
final int flags = lastResponse.getFlags();
@@ -1609,7 +1619,7 @@
+ id + " destroyed");
return false;
}
- final FillResponse response = getLastResponseLocked("showSaveLocked()");
+ final FillResponse response = getLastResponseLocked("showSaveLocked(%s)");
final SaveInfo saveInfo = response == null ? null : response.getSaveInfo();
/*
@@ -1623,13 +1633,13 @@
* - server didn't ask to keep session alive
*/
if (saveInfo == null) {
- if (sVerbose) Slog.v(TAG, "showSaveLocked(): no saveInfo from service");
+ if (sVerbose) Slog.v(TAG, "showSaveLocked(" + this.id + "): no saveInfo from service");
return true;
}
if ((saveInfo.getFlags() & SaveInfo.FLAG_DELAY_SAVE) != 0) {
// TODO(b/113281366): log metrics
- if (sDebug) Slog.v(TAG, "showSaveLocked(): service asked to delay save");
+ if (sDebug) Slog.v(TAG, "showSaveLocked(" + this.id + "): service asked to delay save");
return false;
}
@@ -1961,7 +1971,8 @@
if (node != null) {
final AutofillValue value = node.getAutofillValue();
if (sDebug) {
- Slog.d(TAG, "getValueFromContexts(" + autofillId + ") at " + i + ": " + value);
+ Slog.d(TAG, "getValueFromContexts(" + this.id + "/" + autofillId + ") at "
+ + i + ": " + value);
}
if (value != null && !value.isEmpty()) {
return value;
@@ -2065,7 +2076,7 @@
return;
}
- if (sVerbose) Slog.v(TAG, "callSaveLocked(): mViewStates=" + mViewStates);
+ if (sVerbose) Slog.v(TAG, "callSaveLocked(" + this.id + "): mViewStates=" + mViewStates);
if (mContexts == null) {
Slog.w(TAG, "callSaveLocked(): no contexts");
@@ -2108,15 +2119,15 @@
final ArrayList<FillContext> contexts;
if (previousSessions != null) {
if (sDebug) {
- Slog.d(TAG, "mergeSessions(): Merging the content of " + previousSessions.size()
- + " sessions for task " + taskId);
+ Slog.d(TAG, "mergeSessions(" + this.id + "): Merging the content of "
+ + previousSessions.size() + " sessions for task " + taskId);
}
contexts = new ArrayList<>();
for (int i = 0; i < previousSessions.size(); i++) {
final Session previousSession = previousSessions.get(i);
final ArrayList<FillContext> previousContexts = previousSession.mContexts;
if (previousContexts == null) {
- Slog.w(TAG, "mergeSessions(): Not merging null contexts from "
+ Slog.w(TAG, "mergeSessions(" + this.id + "): Not merging null contexts from "
+ previousSession.id);
continue;
}
@@ -2124,14 +2135,14 @@
previousSession.updateValuesForSaveLocked();
}
if (sDebug) {
- Slog.d(TAG, "mergeSessions(): adding " + previousContexts.size()
+ Slog.d(TAG, "mergeSessions(" + this.id + "): adding " + previousContexts.size()
+ " context from previous session #" + previousSession.id);
}
contexts.addAll(previousContexts);
if (mClientState == null && previousSession.mClientState != null) {
if (sDebug) {
- Slog.d(TAG, "mergeSessions(): setting client state from previous session"
- + previousSession.id);
+ Slog.d(TAG, "mergeSessions(" + this.id + "): setting client state from "
+ + "previous session" + previousSession.id);
}
mClientState = previousSession.mClientState;
}
@@ -2165,19 +2176,17 @@
@NonNull ViewState viewState, int flags) {
if ((flags & FLAG_MANUAL_REQUEST) != 0) {
if (sDebug) Slog.d(TAG, "Re-starting session on view " + id + " and flags " + flags);
- viewState.setState(STATE_RESTARTED_SESSION);
- requestNewFillResponseLocked(flags);
+ requestNewFillResponseLocked(viewState, ViewState.STATE_RESTARTED_SESSION, flags);
return;
}
// If it's not, then check if it it should start a partition.
if (shouldStartNewPartitionLocked(id)) {
if (sDebug) {
- Slog.d(TAG, "Starting partition for view id " + id + ": "
+ Slog.d(TAG, "Starting partition or augmented request for view id " + id + ": "
+ viewState.getStateAsString());
}
- viewState.setState(ViewState.STATE_STARTED_PARTITION);
- requestNewFillResponseLocked(flags);
+ requestNewFillResponseLocked(viewState, ViewState.STATE_STARTED_PARTITION, flags);
} else {
if (sVerbose) {
Slog.v(TAG, "Not starting new partition for view " + id + ": "
@@ -2251,8 +2260,8 @@
return;
}
if (sVerbose) {
- Slog.v(TAG, "updateLocked(): id=" + id + ", action=" + actionAsString(action)
- + ", flags=" + flags);
+ Slog.v(TAG, "updateLocked(" + this.id + "): id=" + id + ", action="
+ + actionAsString(action) + ", flags=" + flags);
}
ViewState viewState = mViewStates.get(id);
@@ -2283,8 +2292,7 @@
// View is triggering autofill.
mCurrentViewId = viewState.id;
viewState.update(value, virtualBounds, flags);
- viewState.setState(ViewState.STATE_STARTED_SESSION);
- requestNewFillResponseLocked(flags);
+ requestNewFillResponseLocked(viewState, ViewState.STATE_STARTED_SESSION, flags);
break;
case ACTION_VALUE_CHANGED:
if (mCompatMode && (viewState.getState() & ViewState.STATE_URL_BAR) != 0) {
@@ -2386,6 +2394,10 @@
Slog.v(TAG, "entered on virtual child " + id + ": " + virtualBounds);
}
+ // Update the view states first...
+ mCurrentViewId = viewState.id;
+ viewState.setCurrentValue(value);
+
if (mCompatMode && (viewState.getState() & ViewState.STATE_URL_BAR) != 0) {
if (sDebug) Slog.d(TAG, "Ignoring VIEW_ENTERED on URL BAR (id=" + id + ")");
return;
@@ -2397,10 +2409,6 @@
if (sDebug) Slog.d(TAG, "updateLocked(" + id + "): augmented-autofillable");
- // Update the view states first...
- mCurrentViewId = viewState.id;
- viewState.setCurrentValue(value);
-
// ...then trigger the augmented autofill UI
triggerAugmentedAutofillLocked();
return;
@@ -3293,7 +3301,7 @@
*/
@GuardedBy("mLock")
void removeSelfLocked() {
- if (sVerbose) Slog.v(TAG, "removeSelfLocked(): " + mPendingSaveUi);
+ if (sVerbose) Slog.v(TAG, "removeSelfLocked(" + this.id + "): " + mPendingSaveUi);
if (mDestroyed) {
Slog.w(TAG, "Call to Session#removeSelfLocked() rejected - session: "
+ id + " destroyed");
diff --git a/services/autofill/java/com/android/server/autofill/ViewState.java b/services/autofill/java/com/android/server/autofill/ViewState.java
index 33a2e50..e1b089c 100644
--- a/services/autofill/java/com/android/server/autofill/ViewState.java
+++ b/services/autofill/java/com/android/server/autofill/ViewState.java
@@ -214,7 +214,7 @@
if (mDatasetId != null) {
builder.append(", datasetId:" ).append(mDatasetId);
}
- builder.append("state:" ).append(getStateAsString());
+ builder.append(", state:").append(getStateAsString());
if (mCurrentValue != null) {
builder.append(", currentValue:" ).append(mCurrentValue);
}
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index a2d3d4c..5c6258f 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -50,6 +50,7 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.DeviceConfig;
+import android.provider.DeviceConfig.Properties;
import android.provider.Settings;
import android.service.contentcapture.ActivityEvent.ActivityEventType;
import android.util.ArraySet;
@@ -131,9 +132,9 @@
com.android.internal.R.string.config_defaultContentCaptureService),
UserManager.DISALLOW_CONTENT_CAPTURE,
/*packageUpdatePolicy=*/ PACKAGE_UPDATE_POLICY_NO_REFRESH);
- DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
+ DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
ActivityThread.currentApplication().getMainExecutor(),
- (namespace, key, value) -> onDeviceConfigChange(key, value));
+ (properties) -> onDeviceConfigChange(properties));
setDeviceConfigProperties();
if (mDevCfgLogHistorySize > 0) {
@@ -255,23 +256,25 @@
return enabled;
}
- private void onDeviceConfigChange(@NonNull String key, @Nullable String value) {
- switch (key) {
- case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED:
- setDisabledByDeviceConfig(value);
- return;
- case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOGGING_LEVEL:
- setLoggingLevelFromDeviceConfig();
- return;
- case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_MAX_BUFFER_SIZE:
- case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_FLUSH_FREQUENCY:
- case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOG_HISTORY_SIZE:
- case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_TEXT_CHANGE_FLUSH_FREQUENCY:
- case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_UNBIND_TIMEOUT:
- setFineTuneParamsFromDeviceConfig();
- return;
- default:
- Slog.i(mTag, "Ignoring change on " + key);
+ private void onDeviceConfigChange(@NonNull Properties properties) {
+ for (String key : properties.getKeyset()) {
+ switch (key) {
+ case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED:
+ setDisabledByDeviceConfig(properties.getString(key, null));
+ return;
+ case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOGGING_LEVEL:
+ setLoggingLevelFromDeviceConfig();
+ return;
+ case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_MAX_BUFFER_SIZE:
+ case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_FLUSH_FREQUENCY:
+ case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOG_HISTORY_SIZE:
+ case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_TEXT_CHANGE_FLUSH_FREQUENCY:
+ case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_UNBIND_TIMEOUT:
+ setFineTuneParamsFromDeviceConfig();
+ return;
+ default:
+ Slog.i(mTag, "Ignoring change on " + key);
+ }
}
}
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 1fa62ce..1220e82 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -760,7 +760,7 @@
if (predicate.test(alarm)) {
alarms.remove(i);
if (!reOrdering) {
- decrementAlarmCount(alarm.uid);
+ decrementAlarmCount(alarm.uid, 1);
}
didRemove = true;
if (alarm.alarmClock != null) {
@@ -1764,7 +1764,7 @@
+ ", callingPackage: " + callingPackage;
// STOPSHIP (b/128866264): Just to catch breakages. Remove before final release.
Slog.wtf(TAG, errorMsg);
- // TODO b/129995049: Resume throwing once issue is resolved.
+ // TODO b/129995049: Resume throwing after some soak time without errors
// throw new UnsupportedOperationException(errorMsg);
}
setImplLocked(type, triggerAtTime, triggerElapsed, windowLength, maxElapsed,
@@ -3113,17 +3113,21 @@
}
}
for (int i = mPendingWhileIdleAlarms.size() - 1; i >= 0; i--) {
- if (mPendingWhileIdleAlarms.get(i).matches(operation, directReceiver)) {
+ final Alarm alarm = mPendingWhileIdleAlarms.get(i);
+ if (alarm.matches(operation, directReceiver)) {
// Don't set didRemove, since this doesn't impact the scheduled alarms.
mPendingWhileIdleAlarms.remove(i);
+ decrementAlarmCount(alarm.uid, 1);
}
}
for (int i = mPendingBackgroundAlarms.size() - 1; i >= 0; i--) {
final ArrayList<Alarm> alarmsForUid = mPendingBackgroundAlarms.valueAt(i);
for (int j = alarmsForUid.size() - 1; j >= 0; j--) {
- if (alarmsForUid.get(j).matches(operation, directReceiver)) {
+ final Alarm alarm = alarmsForUid.get(j);
+ if (alarm.matches(operation, directReceiver)) {
// Don't set didRemove, since this doesn't impact the scheduled alarms.
alarmsForUid.remove(j);
+ decrementAlarmCount(alarm.uid, 1);
}
}
if (alarmsForUid.size() == 0) {
@@ -3169,6 +3173,7 @@
if (a.uid == uid) {
// Don't set didRemove, since this doesn't impact the scheduled alarms.
mPendingWhileIdleAlarms.remove(i);
+ decrementAlarmCount(uid, 1);
}
}
for (int i = mPendingBackgroundAlarms.size() - 1; i >= 0; i --) {
@@ -3176,6 +3181,7 @@
for (int j = alarmsForUid.size() - 1; j >= 0; j--) {
if (alarmsForUid.get(j).uid == uid) {
alarmsForUid.remove(j);
+ decrementAlarmCount(uid, 1);
}
}
if (alarmsForUid.size() == 0) {
@@ -3221,13 +3227,16 @@
if (a.matches(packageName)) {
// Don't set didRemove, since this doesn't impact the scheduled alarms.
mPendingWhileIdleAlarms.remove(i);
+ decrementAlarmCount(a.uid, 1);
}
}
for (int i = mPendingBackgroundAlarms.size() - 1; i >= 0; i --) {
final ArrayList<Alarm> alarmsForUid = mPendingBackgroundAlarms.valueAt(i);
for (int j = alarmsForUid.size() - 1; j >= 0; j--) {
- if (alarmsForUid.get(j).matches(packageName)) {
+ final Alarm alarm = alarmsForUid.get(j);
+ if (alarm.matches(packageName)) {
alarmsForUid.remove(j);
+ decrementAlarmCount(alarm.uid, 1);
}
}
if (alarmsForUid.size() == 0) {
@@ -3272,10 +3281,15 @@
if (a.uid == uid) {
// Don't set didRemove, since this doesn't impact the scheduled alarms.
mPendingWhileIdleAlarms.remove(i);
+ decrementAlarmCount(uid, 1);
}
}
for (int i = mPendingBackgroundAlarms.size() - 1; i >= 0; i--) {
if (mPendingBackgroundAlarms.keyAt(i) == uid) {
+ final ArrayList<Alarm> toRemove = mPendingBackgroundAlarms.valueAt(i);
+ if (toRemove != null) {
+ decrementAlarmCount(uid, toRemove.size());
+ }
mPendingBackgroundAlarms.removeAt(i);
}
}
@@ -3308,11 +3322,18 @@
if (UserHandle.getUserId(mPendingWhileIdleAlarms.get(i).creatorUid)
== userHandle) {
// Don't set didRemove, since this doesn't impact the scheduled alarms.
- mPendingWhileIdleAlarms.remove(i);
+ final Alarm removed = mPendingWhileIdleAlarms.remove(i);
+ decrementAlarmCount(removed.uid, 1);
}
}
for (int i = mPendingBackgroundAlarms.size() - 1; i >= 0; i--) {
if (UserHandle.getUserId(mPendingBackgroundAlarms.keyAt(i)) == userHandle) {
+ final ArrayList<Alarm> toRemove = mPendingBackgroundAlarms.valueAt(i);
+ if (toRemove != null) {
+ for (int j = 0; j < toRemove.size(); j++) {
+ decrementAlarmCount(toRemove.get(j).uid, 1);
+ }
+ }
mPendingBackgroundAlarms.removeAt(i);
}
}
@@ -3844,7 +3865,7 @@
Slog.w(TAG, "Failure sending alarm.", e);
}
Trace.traceEnd(Trace.TRACE_TAG_POWER);
- decrementAlarmCount(alarm.uid);
+ decrementAlarmCount(alarm.uid, 1);
}
}
@@ -4198,7 +4219,7 @@
removeImpl(alarm.operation, null);
}
}
- decrementAlarmCount(alarm.uid);
+ decrementAlarmCount(alarm.uid, 1);
}
break;
}
@@ -4828,16 +4849,21 @@
}
}
- private void decrementAlarmCount(int uid) {
+ private void decrementAlarmCount(int uid, int decrement) {
+ int oldCount = 0;
final int uidIndex = mAlarmsPerUid.indexOfKey(uid);
if (uidIndex >= 0) {
- final int newCount = mAlarmsPerUid.valueAt(uidIndex) - 1;
- if (newCount > 0) {
- mAlarmsPerUid.setValueAt(uidIndex, newCount);
+ oldCount = mAlarmsPerUid.valueAt(uidIndex);
+ if (oldCount > decrement) {
+ mAlarmsPerUid.setValueAt(uidIndex, oldCount - decrement);
} else {
mAlarmsPerUid.removeAt(uidIndex);
}
}
+ if (oldCount < decrement) {
+ Slog.wtf(TAG, "Attempt to decrement existing alarm count " + oldCount + " by "
+ + decrement + " for uid " + uid);
+ }
}
private class ShellCmd extends ShellCommand {
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index b44009f..7b5b419 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -29,6 +29,7 @@
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
+import android.provider.DeviceConfig;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -61,6 +62,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.TimeUnit;
/**
* Monitors the health of packages on the system and notifies interested observers when packages
@@ -69,10 +71,22 @@
*/
public class PackageWatchdog {
private static final String TAG = "PackageWatchdog";
+
+ static final String PROPERTY_WATCHDOG_TRIGGER_DURATION_MILLIS =
+ "watchdog_trigger_failure_duration_millis";
+ static final String PROPERTY_WATCHDOG_TRIGGER_FAILURE_COUNT =
+ "watchdog_trigger_failure_count";
+ static final String PROPERTY_WATCHDOG_EXPLICIT_HEALTH_CHECK_ENABLED =
+ "watchdog_explicit_health_check_enabled";
+
// Duration to count package failures before it resets to 0
- private static final int TRIGGER_DURATION_MS = 60000;
+ private static final int DEFAULT_TRIGGER_FAILURE_DURATION_MS =
+ (int) TimeUnit.MINUTES.toMillis(1);
// Number of package failures within the duration above before we notify observers
- static final int TRIGGER_FAILURE_COUNT = 5;
+ private static final int DEFAULT_TRIGGER_FAILURE_COUNT = 5;
+ // Whether explicit health checks are enabled or not
+ private static final boolean DEFAULT_EXPLICIT_HEALTH_CHECK_ENABLED = true;
+
private static final int DB_VERSION = 1;
private static final String TAG_PACKAGE_WATCHDOG = "package-watchdog";
private static final String TAG_PACKAGE = "package";
@@ -83,6 +97,7 @@
private static final String ATTR_EXPLICIT_HEALTH_CHECK_DURATION = "health-check-duration";
private static final String ATTR_PASSED_HEALTH_CHECK = "passed-health-check";
+ @GuardedBy("PackageWatchdog.class")
private static PackageWatchdog sPackageWatchdog;
private final Object mLock = new Object();
@@ -100,11 +115,15 @@
// File containing the XML data of monitored packages /data/system/package-watchdog.xml
private final AtomicFile mPolicyFile;
private final ExplicitHealthCheckController mHealthCheckController;
- // Flag to control whether explicit health checks are supported or not
- @GuardedBy("mLock")
- private boolean mIsHealthCheckEnabled = true;
@GuardedBy("mLock")
private boolean mIsPackagesReady;
+ // Flag to control whether explicit health checks are supported or not
+ @GuardedBy("mLock")
+ private boolean mIsHealthCheckEnabled = DEFAULT_EXPLICIT_HEALTH_CHECK_ENABLED;
+ @GuardedBy("mLock")
+ private int mTriggerFailureDurationMs = DEFAULT_TRIGGER_FAILURE_DURATION_MS;
+ @GuardedBy("mLock")
+ private int mTriggerFailureCount = DEFAULT_TRIGGER_FAILURE_COUNT;
// SystemClock#uptimeMillis when we last executed #syncState
// 0 if no prune is scheduled.
@GuardedBy("mLock")
@@ -153,8 +172,8 @@
mHealthCheckController.setCallbacks(packageName -> onHealthCheckPassed(packageName),
packages -> onSupportedPackages(packages),
() -> syncRequestsAsync());
- // Controller is initially disabled until here where we may enable it and sync our state
- setExplicitHealthCheckEnabled(mIsHealthCheckEnabled);
+ setPropertyChangedListenerLocked();
+ updateConfigs();
}
}
@@ -332,14 +351,13 @@
}
}
- // TODO(b/120598832): Set depending on DeviceConfig flag
/**
* Enables or disables explicit health checks.
* <p> If explicit health checks are enabled, the health check service is started.
* <p> If explicit health checks are disabled, pending explicit health check requests are
* passed and the health check service is stopped.
*/
- public void setExplicitHealthCheckEnabled(boolean enabled) {
+ private void setExplicitHealthCheckEnabled(boolean enabled) {
synchronized (mLock) {
mIsHealthCheckEnabled = enabled;
mHealthCheckController.setEnabled(enabled);
@@ -390,6 +408,12 @@
String getName();
}
+ long getTriggerFailureCount() {
+ synchronized (mLock) {
+ return mTriggerFailureCount;
+ }
+ }
+
/**
* Serializes and syncs health check requests with the {@link ExplicitHealthCheckController}.
*/
@@ -646,7 +670,7 @@
XmlUtils.beginDocument(parser, TAG_PACKAGE_WATCHDOG);
int outerDepth = parser.getDepth();
while (XmlUtils.nextElementWithin(parser, outerDepth)) {
- ObserverInternal observer = ObserverInternal.read(parser);
+ ObserverInternal observer = ObserverInternal.read(parser, this);
if (observer != null) {
mAllObservers.put(observer.mName, observer);
}
@@ -661,6 +685,48 @@
}
}
+ /** Adds a {@link DeviceConfig#OnPropertyChangedListener}. */
+ private void setPropertyChangedListenerLocked() {
+ DeviceConfig.addOnPropertyChangedListener(
+ DeviceConfig.NAMESPACE_ROLLBACK,
+ mContext.getMainExecutor(),
+ (namespace, name, value) -> {
+ if (!DeviceConfig.NAMESPACE_ROLLBACK.equals(namespace)) {
+ return;
+ }
+ updateConfigs();
+ });
+ }
+
+ /**
+ * Health check is enabled or disabled after reading the flags
+ * from DeviceConfig.
+ */
+ private void updateConfigs() {
+ synchronized (mLock) {
+ mTriggerFailureCount = DeviceConfig.getInt(
+ DeviceConfig.NAMESPACE_ROLLBACK,
+ PROPERTY_WATCHDOG_TRIGGER_FAILURE_COUNT,
+ DEFAULT_TRIGGER_FAILURE_COUNT);
+ if (mTriggerFailureCount <= 0) {
+ mTriggerFailureCount = DEFAULT_TRIGGER_FAILURE_COUNT;
+ }
+
+ mTriggerFailureDurationMs = DeviceConfig.getInt(
+ DeviceConfig.NAMESPACE_ROLLBACK,
+ PROPERTY_WATCHDOG_TRIGGER_DURATION_MILLIS,
+ DEFAULT_TRIGGER_FAILURE_DURATION_MS);
+ if (mTriggerFailureDurationMs <= 0) {
+ mTriggerFailureDurationMs = DEFAULT_TRIGGER_FAILURE_COUNT;
+ }
+
+ setExplicitHealthCheckEnabled(DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_ROLLBACK,
+ PROPERTY_WATCHDOG_EXPLICIT_HEALTH_CHECK_ENABLED,
+ DEFAULT_EXPLICIT_HEALTH_CHECK_ENABLED));
+ }
+ }
+
/**
* Persists mAllObservers to file. Threshold information is ignored.
*/
@@ -805,7 +871,7 @@
* #loadFromFile which in turn is only called on construction of the
* singleton PackageWatchdog.
**/
- public static ObserverInternal read(XmlPullParser parser) {
+ public static ObserverInternal read(XmlPullParser parser, PackageWatchdog watchdog) {
String observerName = null;
if (TAG_OBSERVER.equals(parser.getName())) {
observerName = parser.getAttributeValue(null, ATTR_NAME);
@@ -829,7 +895,7 @@
boolean hasPassedHealthCheck = Boolean.parseBoolean(
parser.getAttributeValue(null, ATTR_PASSED_HEALTH_CHECK));
if (!TextUtils.isEmpty(packageName)) {
- packages.add(new MonitoredPackage(packageName, duration,
+ packages.add(watchdog.new MonitoredPackage(packageName, duration,
healthCheckDuration, hasPassedHealthCheck));
}
} catch (NumberFormatException e) {
@@ -856,7 +922,7 @@
* <p> Note, the PackageWatchdog#mLock must always be held when reading or writing
* instances of this class.
*/
- static class MonitoredPackage {
+ class MonitoredPackage {
// Health check states
// TODO(b/120598832): Prefix with HEALTH_CHECK
// mName has not passed health check but has requested a health check
@@ -931,7 +997,7 @@
public boolean onFailureLocked() {
final long now = SystemClock.uptimeMillis();
final long duration = now - mUptimeStartMs;
- if (duration > TRIGGER_DURATION_MS) {
+ if (duration > mTriggerFailureDurationMs) {
// TODO(b/120598832): Reseting to 1 is not correct
// because there may be more than 1 failure in the last trigger window from now
// This is the RescueParty impl, will leave for now
@@ -940,7 +1006,7 @@
} else {
mFailures++;
}
- boolean failed = mFailures >= TRIGGER_FAILURE_COUNT;
+ boolean failed = mFailures >= mTriggerFailureCount;
if (failed) {
mFailures = 0;
}
@@ -1065,7 +1131,7 @@
}
/** Returns a {@link String} representation of the current health check state. */
- private static String toString(int state) {
+ private String toString(int state) {
switch (state) {
case STATE_ACTIVE:
return "ACTIVE";
@@ -1081,7 +1147,7 @@
}
/** Returns {@code value} if it is greater than 0 or {@link Long#MAX_VALUE} otherwise. */
- private static long toPositive(long value) {
+ private long toPositive(long value) {
return value > 0 ? value : Long.MAX_VALUE;
}
}
diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java
index 1fe0271..fb1a962 100644
--- a/services/core/java/com/android/server/RescueParty.java
+++ b/services/core/java/com/android/server/RescueParty.java
@@ -72,8 +72,12 @@
static final int LEVEL_FACTORY_RESET = 4;
@VisibleForTesting
static final String PROP_RESCUE_BOOT_COUNT = "sys.rescue_boot_count";
+ /**
+ * The boot trigger window size must always be greater than Watchdog's deadlock timeout
+ * {@link Watchdog#DEFAULT_TIMEOUT}.
+ */
@VisibleForTesting
- static final long BOOT_TRIGGER_WINDOW_MILLIS = 300 * DateUtils.SECOND_IN_MILLIS;
+ static final long BOOT_TRIGGER_WINDOW_MILLIS = 600 * DateUtils.SECOND_IN_MILLIS;
@VisibleForTesting
static final long PERSISTENT_APP_CRASH_TRIGGER_WINDOW_MILLIS = 30 * DateUtils.SECOND_IN_MILLIS;
@VisibleForTesting
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 6c1ffa7..baec3cc 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -802,8 +802,8 @@
}
});
// For now, simply clone property when it changes
- DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_STORAGE,
- mContext.getMainExecutor(), (namespace, name, value) -> {
+ DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_STORAGE,
+ mContext.getMainExecutor(), (properties) -> {
refreshIsolatedStorageSettings();
});
refreshIsolatedStorageSettings();
@@ -1063,11 +1063,7 @@
}
private boolean supportsBlockCheckpoint() throws RemoteException {
- // Only the system process is permitted to start checkpoints
- if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
- throw new SecurityException("no permission to check block based checkpoint support");
- }
-
+ enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
return mVold.supportsBlockCheckpoint();
}
@@ -2726,11 +2722,7 @@
*/
@Override
public boolean needsCheckpoint() throws RemoteException {
- // Only the system process is permitted to commit checkpoints
- if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
- throw new SecurityException("no permission to commit checkpoint changes");
- }
-
+ enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
return mVold.needsCheckpoint();
}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index da91187..28bc348 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -66,6 +66,7 @@
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.telephony.TelephonyPermissions;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.am.BatteryStatsService;
@@ -1164,36 +1165,33 @@
@Override
public void notifyCarrierNetworkChange(boolean active) {
- // only CarrierService with carrier privilege rule should have the permission.
- int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
- try {
- subId = Arrays.stream(SubscriptionManager.from(mContext)
+ // only CarrierService with carrier privilege rule should have the permission
+ int[] subIds = Arrays.stream(SubscriptionManager.from(mContext)
.getActiveSubscriptionIdList())
- .filter(i -> TelephonyPermissions.checkCarrierPrivilegeForSubId(i))
- .findFirst().getAsInt();
- } catch (NoSuchElementException ex) {
+ .filter(i -> TelephonyPermissions.checkCarrierPrivilegeForSubId(i)).toArray();
+ if (ArrayUtils.isEmpty(subIds)) {
loge("notifyCarrierNetworkChange without carrier privilege");
- }
- // the active subId does not have carrier privilege.
- if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ // the active subId does not have carrier privilege.
throw new SecurityException("notifyCarrierNetworkChange without carrier privilege");
}
- int phoneId = SubscriptionManager.getPhoneId(subId);
-
- if (VDBG) {
- log("notifyCarrierNetworkChange: active=" + active + "subId: " + subId);
- }
synchronized (mRecords) {
mCarrierNetworkChangeState = active;
- for (Record r : mRecords) {
- if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.LISTEN_CARRIER_NETWORK_CHANGE) &&
- idMatch(r.subId, subId, phoneId)) {
- try {
- r.callback.onCarrierNetworkChange(active);
- } catch (RemoteException ex) {
- mRemoveList.add(r.binder);
+ for (int subId : subIds) {
+ int phoneId = SubscriptionManager.getPhoneId(subId);
+
+ if (VDBG) {
+ log("notifyCarrierNetworkChange: active=" + active + "subId: " + subId);
+ }
+ for (Record r : mRecords) {
+ if (r.matchPhoneStateListenerEvent(
+ PhoneStateListener.LISTEN_CARRIER_NETWORK_CHANGE) &&
+ idMatch(r.subId, subId, phoneId)) {
+ try {
+ r.callback.onCarrierNetworkChange(active);
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 76136df..df92106 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -634,7 +634,7 @@
}
if (allowBackgroundActivityStarts) {
- r.hasStartedWhitelistingBgActivityStarts = true;
+ r.setHasStartedWhitelistingBgActivityStarts(true);
scheduleCleanUpHasStartedWhitelistingBgActivityStartsLocked(r);
}
@@ -761,11 +761,6 @@
}
service.callStart = false;
- // the service will not necessarily be brought down, so only clear the whitelisting state
- // for start-based bg activity starts now, and drop any existing future cleanup callback
- service.setHasStartedWhitelistingBgActivityStarts(false);
- mAm.mHandler.removeCallbacks(service.startedWhitelistingBgActivityStartsCleanUp);
-
bringDownServiceIfNeededLocked(service, false, false);
}
@@ -1768,12 +1763,7 @@
callerApp.uid, callerApp.processName, callingPackage);
IBinder binder = connection.asBinder();
- ArrayList<ConnectionRecord> clist = s.getConnections().get(binder);
- if (clist == null) {
- clist = new ArrayList<ConnectionRecord>();
- s.putConnection(binder, clist);
- }
- clist.add(c);
+ s.addConnection(binder, c);
b.connections.add(c);
if (activity != null) {
activity.addConnection(c);
@@ -1792,9 +1782,9 @@
if (s.app != null) {
updateServiceClientActivitiesLocked(s.app, c, true);
}
- clist = mServiceConnections.get(binder);
+ ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder);
if (clist == null) {
- clist = new ArrayList<ConnectionRecord>();
+ clist = new ArrayList<>();
mServiceConnections.put(binder, clist);
}
clist.add(c);
@@ -3828,8 +3818,8 @@
public PendingIntent getRunningServiceControlPanelLocked(ComponentName name) {
int userId = UserHandle.getUserId(Binder.getCallingUid());
ServiceRecord r = getServiceByNameLocked(name, userId);
- ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
if (r != null) {
+ ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
for (int conni = connections.size() - 1; conni >= 0; conni--) {
ArrayList<ConnectionRecord> conn = connections.valueAt(conni);
for (int i=0; i<conn.size(); i++) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index d7decb4..0da39e7 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -26,7 +26,8 @@
import android.os.Build;
import android.os.Handler;
import android.provider.DeviceConfig;
-import android.provider.DeviceConfig.OnPropertyChangedListener;
+import android.provider.DeviceConfig.OnPropertiesChangedListener;
+import android.provider.DeviceConfig.Properties;
import android.provider.Settings;
import android.text.TextUtils;
import android.text.TextUtils.SimpleStringSplitter;
@@ -315,23 +316,25 @@
private static final Uri ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS_URI =
Settings.Global.getUriFor(Settings.Global.ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS);
- private final OnPropertyChangedListener mOnDeviceConfigChangedListener =
- new OnPropertyChangedListener() {
+ private final OnPropertiesChangedListener mOnDeviceConfigChangedListener =
+ new OnPropertiesChangedListener() {
@Override
- public void onPropertyChanged(String namespace, String name, String value) {
- if (name == null) {
- return;
- }
- switch (name) {
- case KEY_MAX_CACHED_PROCESSES:
- updateMaxCachedProcesses();
- break;
- case KEY_DEFAULT_BACKGROUND_ACTIVITY_STARTS_ENABLED:
- case KEY_BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST:
- updateBackgroundActivityStarts();
- break;
- default:
- break;
+ public void onPropertiesChanged(Properties properties) {
+ for (String name : properties.getKeyset()) {
+ if (name == null) {
+ return;
+ }
+ switch (name) {
+ case KEY_MAX_CACHED_PROCESSES:
+ updateMaxCachedProcesses();
+ break;
+ case KEY_DEFAULT_BACKGROUND_ACTIVITY_STARTS_ENABLED:
+ case KEY_BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST:
+ updateBackgroundActivityStarts();
+ break;
+ default:
+ break;
+ }
}
}
};
@@ -362,7 +365,7 @@
if (mSystemServerAutomaticHeapDumpEnabled) {
updateEnableAutomaticSystemServerHeapDumps();
}
- DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
ActivityThread.currentApplication().getMainExecutor(),
mOnDeviceConfigChangedListener);
updateMaxCachedProcesses();
diff --git a/services/core/java/com/android/server/am/AppCompactor.java b/services/core/java/com/android/server/am/AppCompactor.java
index 13b55db..b0f8f86 100644
--- a/services/core/java/com/android/server/am/AppCompactor.java
+++ b/services/core/java/com/android/server/am/AppCompactor.java
@@ -30,7 +30,8 @@
import android.os.SystemClock;
import android.os.Trace;
import android.provider.DeviceConfig;
-import android.provider.DeviceConfig.OnPropertyChangedListener;
+import android.provider.DeviceConfig.OnPropertiesChangedListener;
+import android.provider.DeviceConfig.Properties;
import android.text.TextUtils;
import android.util.EventLog;
import android.util.Slog;
@@ -126,29 +127,31 @@
private final ArrayList<ProcessRecord> mPendingCompactionProcesses =
new ArrayList<ProcessRecord>();
private final ActivityManagerService mAm;
- private final OnPropertyChangedListener mOnFlagsChangedListener =
- new OnPropertyChangedListener() {
+ private final OnPropertiesChangedListener mOnFlagsChangedListener =
+ new OnPropertiesChangedListener() {
@Override
- public void onPropertyChanged(String namespace, String name, String value) {
+ public void onPropertiesChanged(Properties properties) {
synchronized (mPhenotypeFlagLock) {
- if (KEY_USE_COMPACTION.equals(name)) {
- updateUseCompaction();
- } else if (KEY_COMPACT_ACTION_1.equals(name)
- || KEY_COMPACT_ACTION_2.equals(name)) {
- updateCompactionActions();
- } else if (KEY_COMPACT_THROTTLE_1.equals(name)
- || KEY_COMPACT_THROTTLE_2.equals(name)
- || KEY_COMPACT_THROTTLE_3.equals(name)
- || KEY_COMPACT_THROTTLE_4.equals(name)) {
- updateCompactionThrottles();
- } else if (KEY_COMPACT_STATSD_SAMPLE_RATE.equals(name)) {
- updateStatsdSampleRate();
- } else if (KEY_COMPACT_FULL_RSS_THROTTLE_KB.equals(name)) {
- updateFullRssThrottle();
- } else if (KEY_COMPACT_FULL_DELTA_RSS_THROTTLE_KB.equals(name)) {
- updateFullDeltaRssThrottle();
- } else if (KEY_COMPACT_PROC_STATE_THROTTLE.equals(name)) {
- updateProcStateThrottle();
+ for (String name : properties.getKeyset()) {
+ if (KEY_USE_COMPACTION.equals(name)) {
+ updateUseCompaction();
+ } else if (KEY_COMPACT_ACTION_1.equals(name)
+ || KEY_COMPACT_ACTION_2.equals(name)) {
+ updateCompactionActions();
+ } else if (KEY_COMPACT_THROTTLE_1.equals(name)
+ || KEY_COMPACT_THROTTLE_2.equals(name)
+ || KEY_COMPACT_THROTTLE_3.equals(name)
+ || KEY_COMPACT_THROTTLE_4.equals(name)) {
+ updateCompactionThrottles();
+ } else if (KEY_COMPACT_STATSD_SAMPLE_RATE.equals(name)) {
+ updateStatsdSampleRate();
+ } else if (KEY_COMPACT_FULL_RSS_THROTTLE_KB.equals(name)) {
+ updateFullRssThrottle();
+ } else if (KEY_COMPACT_FULL_DELTA_RSS_THROTTLE_KB.equals(name)) {
+ updateFullDeltaRssThrottle();
+ } else if (KEY_COMPACT_PROC_STATE_THROTTLE.equals(name)) {
+ updateProcStateThrottle();
+ }
}
}
if (mTestCallback != null) {
@@ -229,7 +232,7 @@
* starts the background thread if necessary.
*/
public void init() {
- DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
ActivityThread.currentApplication().getMainExecutor(), mOnFlagsChangedListener);
synchronized (mPhenotypeFlagLock) {
updateUseCompaction();
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index e891e6e..563b2f3 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -1186,8 +1186,8 @@
!mAllowBackgroundActivityStartsTokens.isEmpty());
}
- void addBoundClientUids(ArraySet<Integer> clientUids) {
- mBoundClientUids.addAll(clientUids);
+ void addBoundClientUid(int clientUid) {
+ mBoundClientUids.add(clientUid);
mWindowProcessController.setBoundClientUids(mBoundClientUids);
}
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 27c62d0..0426ec1 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -38,7 +38,6 @@
import android.os.UserHandle;
import android.provider.Settings;
import android.util.ArrayMap;
-import android.util.ArraySet;
import android.util.Slog;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
@@ -131,10 +130,10 @@
int pendingConnectionImportance; // To be filled in to ProcessRecord once it connects
// any current binding to this service has BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS flag?
- private boolean hasBindingWhitelistingBgActivityStarts;
+ private boolean mHasBindingWhitelistingBgActivityStarts;
// is this service currently whitelisted to start activities from background by providing
// allowBackgroundActivityStarts=true to startServiceLocked()?
- boolean hasStartedWhitelistingBgActivityStarts;
+ private boolean mHasStartedWhitelistingBgActivityStarts;
// used to clean up the state of hasStartedWhitelistingBgActivityStarts after a timeout
Runnable startedWhitelistingBgActivityStartsCleanUp;
@@ -384,13 +383,13 @@
if (whitelistManager) {
pw.print(prefix); pw.print("whitelistManager="); pw.println(whitelistManager);
}
- if (hasBindingWhitelistingBgActivityStarts) {
+ if (mHasBindingWhitelistingBgActivityStarts) {
pw.print(prefix); pw.print("hasBindingWhitelistingBgActivityStarts=");
- pw.println(hasBindingWhitelistingBgActivityStarts);
+ pw.println(mHasBindingWhitelistingBgActivityStarts);
}
- if (hasStartedWhitelistingBgActivityStarts) {
+ if (mHasStartedWhitelistingBgActivityStarts) {
pw.print(prefix); pw.print("hasStartedWhitelistingBgActivityStarts=");
- pw.println(hasStartedWhitelistingBgActivityStarts);
+ pw.println(mHasStartedWhitelistingBgActivityStarts);
}
if (delayed) {
pw.print(prefix); pw.print("delayed="); pw.println(delayed);
@@ -542,7 +541,8 @@
public void setProcess(ProcessRecord _proc) {
if (_proc != null) {
- if (hasStartedWhitelistingBgActivityStarts || hasBindingWhitelistingBgActivityStarts) {
+ if (mHasStartedWhitelistingBgActivityStarts
+ || mHasBindingWhitelistingBgActivityStarts) {
_proc.addAllowBackgroundActivityStartsToken(this);
} else {
_proc.removeAllowBackgroundActivityStartsToken(this);
@@ -580,15 +580,17 @@
return connections;
}
- void putConnection(IBinder binder, ArrayList<ConnectionRecord> clist) {
- connections.put(binder, clist);
- // if we have a process attached, add bound client uids of this connection to it
+ void addConnection(IBinder binder, ConnectionRecord c) {
+ ArrayList<ConnectionRecord> clist = connections.get(binder);
+ if (clist == null) {
+ clist = new ArrayList<>();
+ connections.put(binder, clist);
+ }
+ clist.add(c);
+
+ // if we have a process attached, add bound client uid of this connection to it
if (app != null) {
- ArraySet<Integer> boundClientUids = new ArraySet<>();
- for (int i = 0; i < clist.size(); i++) {
- boundClientUids.add(clist.get(i).clientUid);
- }
- app.addBoundClientUids(boundClientUids);
+ app.addBoundClientUid(c.clientUid);
}
}
@@ -614,22 +616,22 @@
break;
}
}
- if (hasBindingWhitelistingBgActivityStarts != hasWhitelistingBinding) {
- hasBindingWhitelistingBgActivityStarts = hasWhitelistingBinding;
+ if (mHasBindingWhitelistingBgActivityStarts != hasWhitelistingBinding) {
+ mHasBindingWhitelistingBgActivityStarts = hasWhitelistingBinding;
updateParentProcessBgActivityStartsWhitelistingToken();
}
}
void setHasBindingWhitelistingBgActivityStarts(boolean newValue) {
- if (hasBindingWhitelistingBgActivityStarts != newValue) {
- hasBindingWhitelistingBgActivityStarts = newValue;
+ if (mHasBindingWhitelistingBgActivityStarts != newValue) {
+ mHasBindingWhitelistingBgActivityStarts = newValue;
updateParentProcessBgActivityStartsWhitelistingToken();
}
}
void setHasStartedWhitelistingBgActivityStarts(boolean newValue) {
- if (hasStartedWhitelistingBgActivityStarts != newValue) {
- hasStartedWhitelistingBgActivityStarts = newValue;
+ if (mHasStartedWhitelistingBgActivityStarts != newValue) {
+ mHasStartedWhitelistingBgActivityStarts = newValue;
updateParentProcessBgActivityStartsWhitelistingToken();
}
}
@@ -647,7 +649,7 @@
if (app == null) {
return;
}
- if (hasStartedWhitelistingBgActivityStarts || hasBindingWhitelistingBgActivityStarts) {
+ if (mHasStartedWhitelistingBgActivityStarts || mHasBindingWhitelistingBgActivityStarts) {
// if the token is already there it's safe to "re-add it" - we're deadling with
// a set of Binder objects
app.addAllowBackgroundActivityStartsToken(this);
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index 19c3a71..64f4a35 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -81,6 +81,7 @@
static final String[] sDeviceConfigScopes = new String[] {
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
DeviceConfig.NAMESPACE_INPUT_NATIVE_BOOT,
+ DeviceConfig.NAMESPACE_INTELLIGENCE_CONTENT_SUGGESTIONS,
DeviceConfig.NAMESPACE_MEDIA_NATIVE,
DeviceConfig.NAMESPACE_NETD_NATIVE,
DeviceConfig.NAMESPACE_RUNTIME_NATIVE,
diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java
index b50af28..032af25 100644
--- a/services/core/java/com/android/server/attention/AttentionManagerService.java
+++ b/services/core/java/com/android/server/attention/AttentionManagerService.java
@@ -22,7 +22,6 @@
import android.Manifest;
import android.annotation.Nullable;
-import android.annotation.TestApi;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.attention.AttentionManagerInternal;
@@ -43,6 +42,9 @@
import android.os.Message;
import android.os.PowerManager;
import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
+import android.os.ShellCommand;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.DeviceConfig;
@@ -56,7 +58,6 @@
import android.util.SparseArray;
import android.util.StatsLog;
-import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils;
@@ -76,15 +77,6 @@
private static final String LOG_TAG = "AttentionManagerService";
private static final boolean DEBUG = false;
- /**
- * DeviceConfig flag name, allows a CTS to inject a fake implementation.
- *
- * @hide
- */
- @TestApi
- public static final String COMPONENT_NAME = "component_name";
-
-
/** Default value in absence of {@link DeviceConfig} override. */
private static final boolean DEFAULT_SERVICE_ENABLED = true;
@@ -96,6 +88,7 @@
/** DeviceConfig flag name, if {@code true}, enables AttentionManagerService features. */
private static final String SERVICE_ENABLED = "service_enabled";
+ private static String sTestAttentionServicePackage;
private final Context mContext;
private final PowerManager mPowerManager;
private final Object mLock;
@@ -135,7 +128,7 @@
/** Returns {@code true} if attention service is configured on this device. */
public static boolean isServiceConfigured(Context context) {
- return !TextUtils.isEmpty(getServiceConfig(context));
+ return !TextUtils.isEmpty(getServiceConfigPackage(context));
}
/** Resolves and sets up the attention service if it had not been done yet. */
@@ -332,8 +325,8 @@
return mUserStates.get(userId);
}
- private static String getServiceConfig(Context context) {
- return context.getString(R.string.config_defaultAttentionService);
+ private static String getServiceConfigPackage(Context context) {
+ return context.getPackageManager().getAttentionServicePackageName();
}
/**
@@ -341,28 +334,26 @@
* system.
*/
private static ComponentName resolveAttentionService(Context context) {
- final String flag = DeviceConfig.getProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
- COMPONENT_NAME);
+ final String serviceConfigPackage = getServiceConfigPackage(context);
- final String componentNameString = flag != null ? flag : getServiceConfig(context);
- if (TextUtils.isEmpty(componentNameString)) {
- return null;
- }
-
- final ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
- if (componentName == null) {
+ String resolvedPackage;
+ int flags = PackageManager.MATCH_SYSTEM_ONLY;
+ if (!TextUtils.isEmpty(sTestAttentionServicePackage)) {
+ resolvedPackage = sTestAttentionServicePackage;
+ flags = PackageManager.GET_META_DATA;
+ } else if (!TextUtils.isEmpty(serviceConfigPackage)) {
+ resolvedPackage = serviceConfigPackage;
+ } else {
return null;
}
final Intent intent = new Intent(AttentionService.SERVICE_INTERFACE).setPackage(
- componentName.getPackageName());
+ resolvedPackage);
- // Make sure that only system apps can declare the AttentionService.
- final ResolveInfo resolveInfo = context.getPackageManager().resolveService(intent,
- PackageManager.MATCH_SYSTEM_ONLY);
+ final ResolveInfo resolveInfo = context.getPackageManager().resolveService(intent, flags);
if (resolveInfo == null || resolveInfo.serviceInfo == null) {
Slog.wtf(LOG_TAG, String.format("Service %s not found in package %s",
- AttentionService.SERVICE_INTERFACE, componentName
+ AttentionService.SERVICE_INTERFACE, serviceConfigPackage
));
return null;
}
@@ -447,6 +438,7 @@
}
void cancelInternal() {
+ mIsFulfilled = true;
mCallbackInternal.onFailure(ATTENTION_FAILURE_CANCELLED);
}
}
@@ -606,7 +598,6 @@
}
return;
}
- userState.mCurrentAttentionCheck.mIsFulfilled = true;
if (userState.mService == null) {
userState.mCurrentAttentionCheck.cancelInternal();
@@ -654,7 +645,165 @@
}
}
+ private final class AttentionManagerServiceShellCommand extends ShellCommand {
+ class TestableAttentionCallbackInternal extends AttentionCallbackInternal {
+ private int mLastCallbackCode = -1;
+
+ @Override
+ public void onSuccess(int result, long timestamp) {
+ mLastCallbackCode = result;
+ }
+
+ @Override
+ public void onFailure(int error) {
+ mLastCallbackCode = error;
+ }
+
+ public void reset() {
+ mLastCallbackCode = -1;
+ }
+
+ public int getLastCallbackCode() {
+ return mLastCallbackCode;
+ }
+ }
+
+ final TestableAttentionCallbackInternal mTestableAttentionCallback =
+ new TestableAttentionCallbackInternal();
+
+ @Override
+ public int onCommand(@Nullable final String cmd) {
+ if (cmd == null) {
+ return handleDefaultCommands(cmd);
+ }
+ final PrintWriter err = getErrPrintWriter();
+ try {
+ switch (cmd) {
+ case "getAttentionServiceComponent":
+ return cmdResolveAttentionServiceComponent();
+ case "call":
+ switch (getNextArgRequired()) {
+ case "checkAttention":
+ return cmdCallCheckAttention();
+ case "cancelCheckAttention":
+ return cmdCallCancelAttention();
+ default:
+ throw new IllegalArgumentException("Invalid argument");
+ }
+ case "setTestableAttentionService":
+ return cmdSetTestableAttentionService(getNextArgRequired());
+ case "clearTestableAttentionService":
+ return cmdClearTestableAttentionService();
+ case "getLastTestCallbackCode":
+ return cmdGetLastTestCallbackCode();
+ default:
+ return handleDefaultCommands(cmd);
+ }
+ } catch (IllegalArgumentException e) {
+ err.println("Error: " + e.getMessage());
+ }
+ return -1;
+ }
+
+ private int cmdSetTestableAttentionService(String testingServicePackage) {
+ final PrintWriter out = getOutPrintWriter();
+ if (TextUtils.isEmpty(testingServicePackage)) {
+ out.println("false");
+ } else {
+ sTestAttentionServicePackage = testingServicePackage;
+ resetStates();
+ out.println(mComponentName != null ? "true" : "false");
+ }
+ return 0;
+ }
+
+ private int cmdClearTestableAttentionService() {
+ sTestAttentionServicePackage = "";
+ mTestableAttentionCallback.reset();
+ resetStates();
+ return 0;
+ }
+
+ private int cmdCallCheckAttention() {
+ final PrintWriter out = getOutPrintWriter();
+ boolean calledSuccessfully = checkAttention(2000, mTestableAttentionCallback);
+ out.println(calledSuccessfully ? "true" : "false");
+ return 0;
+ }
+
+ private int cmdCallCancelAttention() {
+ final PrintWriter out = getOutPrintWriter();
+ cancelAttentionCheck(mTestableAttentionCallback);
+ out.println("true");
+ return 0;
+ }
+
+ private int cmdResolveAttentionServiceComponent() {
+ final PrintWriter out = getOutPrintWriter();
+ ComponentName resolvedComponent = resolveAttentionService(mContext);
+ out.println(resolvedComponent != null ? resolvedComponent.flattenToShortString() : "");
+ return 0;
+ }
+
+ private int cmdGetLastTestCallbackCode() {
+ final PrintWriter out = getOutPrintWriter();
+ out.println(mTestableAttentionCallback.getLastCallbackCode());
+ return 0;
+ }
+
+ private void resetStates() {
+ mComponentName = resolveAttentionService(mContext);
+ mUserStates.clear();
+ }
+
+ @Override
+ public void onHelp() {
+ final PrintWriter out = getOutPrintWriter();
+ out.println("Attention commands: ");
+ out.println(" setTestableAttentionService <service_package>: Bind to a custom"
+ + " implementation of attention service");
+ out.println(" ---<service_package>:");
+ out.println(
+ " := Package containing the Attention Service implementation to bind to");
+ out.println(" ---returns:");
+ out.println(" := true, if was bound successfully");
+ out.println(" := false, if was not bound successfully");
+ out.println(" clearTestableAttentionService: Undo custom bindings. Revert to previous"
+ + " behavior");
+ out.println(" getAttentionServiceComponent: Get the current service component string");
+ out.println(" ---returns:");
+ out.println(" := If valid, the component string (in shorten form) for the"
+ + " currently bound service.");
+ out.println(" := else, empty string");
+ out.println(" call checkAttention: Calls check attention");
+ out.println(" ---returns:");
+ out.println(
+ " := true, if the call was successfully dispatched to the service "
+ + "implementation."
+ + " (to see the result, call getLastTestCallbackCode)");
+ out.println(" := false, otherwise");
+ out.println(" call cancelCheckAttention: Cancels check attention");
+ out.println(" getLastTestCallbackCode");
+ out.println(" ---returns:");
+ out.println(
+ " := An integer, representing the last callback code received from the "
+ + "bounded implementation. If none, it will return -1");
+ }
+ }
+
private final class BinderService extends Binder {
+ AttentionManagerServiceShellCommand mAttentionManagerServiceShellCommand =
+ new AttentionManagerServiceShellCommand();
+
+ @Override
+ public void onShellCommand(FileDescriptor in, FileDescriptor out,
+ FileDescriptor err,
+ String[] args, ShellCallback callback,
+ ResultReceiver resultReceiver) {
+ mAttentionManagerServiceShellCommand.exec(this, in, out, err, args, callback,
+ resultReceiver);
+ }
+
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) {
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 668af85..a0522e3 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -723,7 +723,8 @@
case MSG_IL_SET_HEARING_AID_CONNECTION_STATE:
synchronized (mDeviceStateLock) {
mDeviceInventory.onSetHearingAidConnectionState(
- (BluetoothDevice) msg.obj, msg.arg1);
+ (BluetoothDevice) msg.obj, msg.arg1,
+ mAudioService.getHearingAidStreamType());
}
break;
case MSG_BT_HEADSET_CNCT_FAILED:
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 3948bd8..887c908 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -236,7 +236,7 @@
}
/*package*/ void onSetHearingAidConnectionState(BluetoothDevice btDevice,
- @AudioService.BtProfileConnectionState int state) {
+ @AudioService.BtProfileConnectionState int state, int streamType) {
String address = btDevice.getAddress();
if (!BluetoothAdapter.checkBluetoothAddress(address)) {
address = "";
@@ -253,7 +253,7 @@
if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
makeHearingAidDeviceUnavailable(address);
} else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
- makeHearingAidDeviceAvailable(address, BtHelper.getName(btDevice),
+ makeHearingAidDeviceAvailable(address, BtHelper.getName(btDevice), streamType,
"onSetHearingAidConnectionState");
}
}
@@ -719,10 +719,11 @@
}
@GuardedBy("mConnectedDevices")
- private void makeHearingAidDeviceAvailable(String address, String name, String eventSource) {
- final int hearingAidVolIndex = mDeviceBroker.getVssVolumeForDevice(AudioSystem.STREAM_MUSIC,
+ private void makeHearingAidDeviceAvailable(
+ String address, String name, int streamType, String eventSource) {
+ final int hearingAidVolIndex = mDeviceBroker.getVssVolumeForDevice(streamType,
AudioSystem.DEVICE_OUT_HEARING_AID);
- mDeviceBroker.postSetHearingAidVolumeIndex(hearingAidVolIndex, AudioSystem.STREAM_MUSIC);
+ mDeviceBroker.postSetHearingAidVolumeIndex(hearingAidVolIndex, streamType);
AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_HEARING_AID,
AudioSystem.DEVICE_STATE_AVAILABLE, address, name,
@@ -732,7 +733,7 @@
new DeviceInfo(AudioSystem.DEVICE_OUT_HEARING_AID, name,
address, AudioSystem.AUDIO_FORMAT_DEFAULT));
mDeviceBroker.postAccessoryPlugMediaUnmute(AudioSystem.DEVICE_OUT_HEARING_AID);
- mDeviceBroker.postApplyVolumeOnDevice(AudioSystem.STREAM_MUSIC,
+ mDeviceBroker.postApplyVolumeOnDevice(streamType,
AudioSystem.DEVICE_OUT_HEARING_AID, "makeHearingAidDeviceAvailable");
setCurrentAudioRouteNameIfPossible(name);
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index c34425f..d510912 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1825,14 +1825,28 @@
&& streamTypeAlias == AudioSystem.STREAM_MUSIC
// vol change on a full volume device
&& ((device & mFullVolumeDevices) != 0)) {
- int keyCode = (direction == -1) ? KeyEvent.KEYCODE_VOLUME_DOWN :
- KeyEvent.KEYCODE_VOLUME_UP;
- final long ident = Binder.clearCallingIdentity();
- try {
- mHdmiPlaybackClient.sendKeyEvent(keyCode, true);
- mHdmiPlaybackClient.sendKeyEvent(keyCode, false);
- } finally {
- Binder.restoreCallingIdentity(ident);
+ int keyCode = KeyEvent.KEYCODE_UNKNOWN;
+ switch (direction) {
+ case AudioManager.ADJUST_RAISE:
+ keyCode = KeyEvent.KEYCODE_VOLUME_UP;
+ break;
+ case AudioManager.ADJUST_LOWER:
+ keyCode = KeyEvent.KEYCODE_VOLUME_DOWN;
+ break;
+ case AudioManager.ADJUST_TOGGLE_MUTE:
+ keyCode = KeyEvent.KEYCODE_VOLUME_MUTE;
+ break;
+ default:
+ break;
+ }
+ if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mHdmiPlaybackClient.sendKeyEvent(keyCode, true);
+ mHdmiPlaybackClient.sendKeyEvent(keyCode, false);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
}
@@ -2078,6 +2092,22 @@
}
}
+ /*package*/ int getHearingAidStreamType() {
+ return getHearingAidStreamType(mMode);
+ }
+
+ private int getHearingAidStreamType(int mode) {
+ switch (mode) {
+ case AudioSystem.MODE_IN_COMMUNICATION:
+ case AudioSystem.MODE_IN_CALL:
+ return AudioSystem.STREAM_VOICE_CALL;
+ case AudioSystem.MODE_NORMAL:
+ default:
+ break;
+ }
+ return AudioSystem.STREAM_MUSIC;
+ }
+
/**
* Manage an audio mode change for audio devices that use an "absolute volume" model,
* i.e. the framework sends the full scale signal, and the actual volume for the use case
@@ -2087,14 +2117,10 @@
if (oldMode == newMode) {
return;
}
- int streamType = AudioSystem.STREAM_MUSIC;
switch (newMode) {
case AudioSystem.MODE_IN_COMMUNICATION:
case AudioSystem.MODE_IN_CALL:
- streamType = AudioSystem.STREAM_VOICE_CALL;
- break;
case AudioSystem.MODE_NORMAL:
- streamType = AudioSystem.STREAM_MUSIC;
break;
case AudioSystem.MODE_RINGTONE:
// not changing anything for ringtone
@@ -2105,6 +2131,9 @@
// don't know what to do in this case, better bail
return;
}
+
+ int streamType = getHearingAidStreamType(newMode);
+
final int device = AudioSystem.getDevicesForStream(streamType);
if ((device & mAbsVolumeMultiModeCaseDevices) == 0) {
return;
diff --git a/services/core/java/com/android/server/gpu/GpuService.java b/services/core/java/com/android/server/gpu/GpuService.java
index 0f73f37..d439653 100644
--- a/services/core/java/com/android/server/gpu/GpuService.java
+++ b/services/core/java/com/android/server/gpu/GpuService.java
@@ -37,6 +37,7 @@
import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.DeviceConfig;
+import android.provider.DeviceConfig.Properties;
import android.provider.Settings;
import android.util.Base64;
import android.util.Slog;
@@ -138,18 +139,19 @@
}
}
- private final class DeviceConfigListener implements DeviceConfig.OnPropertyChangedListener {
+ private final class DeviceConfigListener implements DeviceConfig.OnPropertiesChangedListener {
DeviceConfigListener() {
super();
- DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_GAME_DRIVER,
+ DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_GAME_DRIVER,
mContext.getMainExecutor(), this);
}
@Override
- public void onPropertyChanged(String namespace, String name, String value) {
+ public void onPropertiesChanged(Properties properties) {
synchronized (mDeviceConfigLock) {
- if (Settings.Global.GAME_DRIVER_BLACKLISTS.equals(name)) {
- parseBlacklists(value != null ? value : "");
+ if (properties.getKeyset().contains(Settings.Global.GAME_DRIVER_BLACKLISTS)) {
+ parseBlacklists(
+ properties.getString(Settings.Global.GAME_DRIVER_BLACKLISTS, ""));
setBlacklist();
}
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 651ce7d..30d244f 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -1409,7 +1409,7 @@
mIWindowManager = IWindowManager.Stub.asInterface(
ServiceManager.getService(Context.WINDOW_SERVICE));
mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
- mImeDisplayValidator = mWindowManagerInternal::shouldShowSystemDecorOnDisplay;
+ mImeDisplayValidator = displayId -> mWindowManagerInternal.shouldShowIme(displayId);
mCaller = new HandlerCaller(context, null, new HandlerCaller.Callback() {
@Override
public void executeMessage(Message msg) {
@@ -2139,7 +2139,9 @@
if (displayId == DEFAULT_DISPLAY || displayId == INVALID_DISPLAY) {
return FALLBACK_DISPLAY_ID;
}
- // Show IME window on fallback display when the display is not allowed.
+
+ // Show IME window on fallback display when the display doesn't support system decorations
+ // or the display is virtual and isn't owned by system for security concern.
return checker.displayCanShowIme(displayId) ? displayId : FALLBACK_DISPLAY_ID;
}
diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
index 580150e..e0b8e71 100644
--- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
@@ -79,6 +79,9 @@
import com.android.internal.inputmethod.UnbindReason;
import com.android.internal.messages.nano.SystemMessageProto;
import com.android.internal.notification.SystemNotificationChannels;
+import com.android.internal.os.TransferPipe;
+import com.android.internal.util.DumpUtils;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethodClient;
@@ -90,6 +93,8 @@
import com.android.server.wm.WindowManagerInternal;
import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.util.Collections;
import java.util.List;
@@ -645,6 +650,14 @@
mSelfReportedDisplayId = selfReportedDisplayId;
mClientId = InputMethodClientIdSource.getNext();
}
+
+ @GuardedBy("PerUserData.mLock")
+ void dumpLocked(FileDescriptor fd, IndentingPrintWriter ipw, String[] args) {
+ ipw.println("mState=" + mState + ",mBindingSequence=" + mBindingSequence
+ + ",mWriteChannel=" + mWriteChannel
+ + ",mInputMethodSession=" + mInputMethodSession
+ + ",mMSInputMethodSession=" + mMSInputMethodSession);
+ }
}
private static final class UserDataMap {
@@ -673,6 +686,22 @@
return mMap.removeReturnOld(userId);
}
}
+
+ @AnyThread
+ void dump(FileDescriptor fd, IndentingPrintWriter ipw, String[] args) {
+ synchronized (mMap) {
+ for (int i = 0; i < mMap.size(); i++) {
+ int userId = mMap.keyAt(i);
+ PerUserData data = mMap.valueAt(i);
+ ipw.println("userId=" + userId + ", data=");
+ if (data != null) {
+ ipw.increaseIndent();
+ data.dump(fd, ipw, args);
+ ipw.decreaseIndent();
+ }
+ }
+ }
+ }
}
private static final class TokenInfo {
@@ -967,6 +996,71 @@
}
}
+ @AnyThread
+ void dump(FileDescriptor fd, IndentingPrintWriter ipw, String[] args) {
+ synchronized (mLock) {
+ ipw.println("mState=" + mState
+ + ",mCurrentInputMethod=" + mCurrentInputMethod
+ + ",mCurrentInputMethodInfo=" + mCurrentInputMethodInfo);
+
+ if (mCurrentInputMethod != null) {
+ // indentation will not be kept. So add visual separator here.
+ ipw.println(">>Dump CurrentInputMethod>>");
+ ipw.flush();
+ try {
+ TransferPipe.dumpAsync(mCurrentInputMethod.asBinder(), fd, args);
+ } catch (IOException | RemoteException e) {
+ ipw.println("Failed to dump input method service: " + e);
+ }
+ ipw.println("<<Dump CurrentInputMethod<<");
+ }
+
+ ipw.println("mDisplayIdToImeWindowTokenMap=");
+ for (TokenInfo info : mDisplayIdToImeWindowTokenMap) {
+ ipw.println(" display=" + info.mDisplayId + ",token="
+ + info.mToken);
+ }
+ ipw.println("mClientMap=");
+ ipw.increaseIndent();
+ for (int i = 0; i < mClientMap.size(); i++) {
+
+ ipw.println("binder=" + mClientMap.keyAt(i));
+ ipw.println(" InputMethodClientInfo=");
+ InputMethodClientInfo info = mClientMap.valueAt(i);
+ if (info != null) {
+ ipw.increaseIndent();
+ info.dumpLocked(fd, ipw, args);
+ ipw.decreaseIndent();
+ }
+ }
+ ipw.decreaseIndent();
+ ipw.println("mClientIdToClientMap=");
+ ipw.increaseIndent();
+ for (int i = 0; i < mClientIdToClientMap.size(); i++) {
+ ipw.println("clientId=" + mClientIdToClientMap.keyAt(i));
+ ipw.println(" InputMethodClientInfo=");
+ InputMethodClientInfo info = mClientIdToClientMap.valueAt(i);
+ if (info != null) {
+ ipw.increaseIndent();
+ info.dumpLocked(fd, ipw, args);
+ ipw.decreaseIndent();
+ }
+ if (info.mClient != null) {
+ // indentation will not be kept. So add visual separator here.
+ ipw.println(">>DumpClientStart>>");
+ ipw.flush(); // all writes should be flushed to guarantee order.
+ try {
+ TransferPipe.dumpAsync(info.mClient.asBinder(), fd, args);
+ } catch (IOException | RemoteException e) {
+ ipw.println(" Failed to dump client:" + e);
+ }
+ ipw.println("<<DumpClientEnd<<");
+ }
+ }
+ ipw.decreaseIndent();
+ }
+ }
+
private static final class ClientDeathRecipient implements IBinder.DeathRecipient {
private final PerUserData mPerUserData;
private final IInputMethodClient mClient;
@@ -1106,6 +1200,16 @@
}
return Collections.singletonList(info);
}
+
+ @AnyThread
+ void dump(FileDescriptor fd, IndentingPrintWriter ipw, String[] args) {
+ synchronized (mArray) {
+ for (int i = 0; i < mArray.size(); i++) {
+ ipw.println("userId=" + mArray.keyAt(i));
+ ipw.println(" InputMethodInfo=" + mArray.valueAt(i));
+ }
+ }
+ }
}
/**
@@ -1601,5 +1705,19 @@
@Nullable FileDescriptor err, String[] args, @Nullable ShellCallback callback,
ResultReceiver resultReceiver) {
}
+
+ @BinderThread
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+ final String prefixChild = " ";
+ pw.println("Current Multi Client Input Method Manager state:");
+ IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
+ ipw.println("mUserDataMap=");
+ if (mUserDataMap != null) {
+ ipw.increaseIndent();
+ mUserDataMap.dump(fd, ipw, args);
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index d5883bb..b676618 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -18,6 +18,7 @@
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
+import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
@@ -463,32 +464,6 @@
private static final String KEY_CONN_CONGESTION_DELAY_FRAC = "conn_congestion_delay_frac";
private static final String KEY_CONN_PREFETCH_RELAX_FRAC = "conn_prefetch_relax_frac";
private static final String KEY_USE_HEARTBEATS = "use_heartbeats";
- private static final String KEY_TIME_CONTROLLER_SKIP_NOT_READY_JOBS =
- "tc_skip_not_ready_jobs";
- private static final String KEY_QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS =
- "qc_allowed_time_per_period_ms";
- private static final String KEY_QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS =
- "qc_in_quota_buffer_ms";
- private static final String KEY_QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS =
- "qc_window_size_active_ms";
- private static final String KEY_QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS =
- "qc_window_size_working_ms";
- private static final String KEY_QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS =
- "qc_window_size_frequent_ms";
- private static final String KEY_QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS =
- "qc_window_size_rare_ms";
- private static final String KEY_QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS =
- "qc_max_execution_time_ms";
- private static final String KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE =
- "qc_max_job_count_active";
- private static final String KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING =
- "qc_max_job_count_working";
- private static final String KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT =
- "qc_max_job_count_frequent";
- private static final String KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE =
- "qc_max_job_count_rare";
- private static final String KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME =
- "qc_max_count_per_allowed_time";
private static final int DEFAULT_MIN_IDLE_COUNT = 1;
private static final int DEFAULT_MIN_CHARGING_COUNT = 1;
@@ -510,30 +485,6 @@
private static final float DEFAULT_CONN_CONGESTION_DELAY_FRAC = 0.5f;
private static final float DEFAULT_CONN_PREFETCH_RELAX_FRAC = 0.5f;
private static final boolean DEFAULT_USE_HEARTBEATS = false;
- private static final boolean DEFAULT_TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true;
- private static final long DEFAULT_QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS =
- 10 * 60 * 1000L; // 10 minutes
- private static final long DEFAULT_QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS =
- 30 * 1000L; // 30 seconds
- private static final long DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS =
- 10 * 60 * 1000L; // 10 minutes for ACTIVE -- ACTIVE apps can run jobs at any time
- private static final long DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS =
- 2 * 60 * 60 * 1000L; // 2 hours
- private static final long DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS =
- 8 * 60 * 60 * 1000L; // 8 hours
- private static final long DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS =
- 24 * 60 * 60 * 1000L; // 24 hours
- private static final long DEFAULT_QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS =
- 4 * 60 * 60 * 1000L; // 4 hours
- private static final int DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE =
- 200; // 1200/hr
- private static final int DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING =
- 1200; // 600/hr
- private static final int DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT =
- 1800; // 225/hr
- private static final int DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE =
- 2400; // 100/hr
- private static final int DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME = 20;
/**
* Minimum # of idle jobs that must be ready in order to force the JMS to schedule things
@@ -680,97 +631,6 @@
*/
public boolean USE_HEARTBEATS = DEFAULT_USE_HEARTBEATS;
- /**
- * Whether or not TimeController should skip setting wakeup alarms for jobs that aren't
- * ready now.
- */
- public boolean TIME_CONTROLLER_SKIP_NOT_READY_JOBS =
- DEFAULT_TIME_CONTROLLER_SKIP_NOT_READY_JOBS;
-
- /** How much time each app will have to run jobs within their standby bucket window. */
- public long QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS =
- DEFAULT_QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS;
-
- /**
- * How much time the package should have before transitioning from out-of-quota to in-quota.
- * This should not affect processing if the package is already in-quota.
- */
- public long QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS =
- DEFAULT_QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS;
-
- /**
- * The quota window size of the particular standby bucket. Apps in this standby bucket are
- * expected to run only {@link #QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past
- * WINDOW_SIZE_MS.
- */
- public long QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS =
- DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS;
-
- /**
- * The quota window size of the particular standby bucket. Apps in this standby bucket are
- * expected to run only {@link #QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past
- * WINDOW_SIZE_MS.
- */
- public long QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS =
- DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS;
-
- /**
- * The quota window size of the particular standby bucket. Apps in this standby bucket are
- * expected to run only {@link #QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past
- * WINDOW_SIZE_MS.
- */
- public long QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS =
- DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS;
-
- /**
- * The quota window size of the particular standby bucket. Apps in this standby bucket are
- * expected to run only {@link #QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past
- * WINDOW_SIZE_MS.
- */
- public long QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS =
- DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS;
-
- /**
- * The maximum amount of time an app can have its jobs running within a 24 hour window.
- */
- public long QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS =
- DEFAULT_QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS;
-
- /**
- * The maximum number of jobs an app can run within this particular standby bucket's
- * window size.
- */
- public int QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE =
- DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE;
-
- /**
- * The maximum number of jobs an app can run within this particular standby bucket's
- * window size.
- */
- public int QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING =
- DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING;
-
- /**
- * The maximum number of jobs an app can run within this particular standby bucket's
- * window size.
- */
- public int QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT =
- DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT;
-
- /**
- * The maximum number of jobs an app can run within this particular standby bucket's
- * window size.
- */
- public int QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE =
- DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE;
-
- /**
- * The maximum number of jobs that can run within the past
- * {@link #QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS}.
- */
- public int QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME =
- DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME;
-
private final KeyValueListParser mParser = new KeyValueListParser(',');
void updateConstantsLocked(String value) {
@@ -834,45 +694,6 @@
CONN_PREFETCH_RELAX_FRAC = mParser.getFloat(KEY_CONN_PREFETCH_RELAX_FRAC,
DEFAULT_CONN_PREFETCH_RELAX_FRAC);
USE_HEARTBEATS = mParser.getBoolean(KEY_USE_HEARTBEATS, DEFAULT_USE_HEARTBEATS);
- TIME_CONTROLLER_SKIP_NOT_READY_JOBS = mParser.getBoolean(
- KEY_TIME_CONTROLLER_SKIP_NOT_READY_JOBS,
- DEFAULT_TIME_CONTROLLER_SKIP_NOT_READY_JOBS);
- QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS = mParser.getDurationMillis(
- KEY_QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS,
- DEFAULT_QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS);
- QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS = mParser.getDurationMillis(
- KEY_QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS,
- DEFAULT_QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS);
- QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS = mParser.getDurationMillis(
- KEY_QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS,
- DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS);
- QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS = mParser.getDurationMillis(
- KEY_QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS,
- DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS);
- QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS = mParser.getDurationMillis(
- KEY_QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS,
- DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS);
- QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS = mParser.getDurationMillis(
- KEY_QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS,
- DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS);
- QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS = mParser.getDurationMillis(
- KEY_QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS,
- DEFAULT_QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS);
- QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE = mParser.getInt(
- KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE,
- DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE);
- QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING = mParser.getInt(
- KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING,
- DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING);
- QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT = mParser.getInt(
- KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT,
- DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT);
- QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE = mParser.getInt(
- KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE,
- DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE);
- QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME = mParser.getInt(
- KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME,
- DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME);
}
void dump(IndentingPrintWriter pw) {
@@ -915,37 +736,11 @@
pw.printPair(KEY_CONN_CONGESTION_DELAY_FRAC, CONN_CONGESTION_DELAY_FRAC).println();
pw.printPair(KEY_CONN_PREFETCH_RELAX_FRAC, CONN_PREFETCH_RELAX_FRAC).println();
pw.printPair(KEY_USE_HEARTBEATS, USE_HEARTBEATS).println();
- pw.printPair(KEY_TIME_CONTROLLER_SKIP_NOT_READY_JOBS,
- TIME_CONTROLLER_SKIP_NOT_READY_JOBS).println();
- pw.printPair(KEY_QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS,
- QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS).println();
- pw.printPair(KEY_QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS,
- QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS).println();
- pw.printPair(KEY_QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS,
- QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS).println();
- pw.printPair(KEY_QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS,
- QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS).println();
- pw.printPair(KEY_QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS,
- QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS).println();
- pw.printPair(KEY_QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS,
- QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS).println();
- pw.printPair(KEY_QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS,
- QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS).println();
- pw.printPair(KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE,
- QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE).println();
- pw.printPair(KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING,
- QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING).println();
- pw.printPair(KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT,
- QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT).println();
- pw.printPair(KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE,
- QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE).println();
- pw.printPair(KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME,
- QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME).println();
+
pw.decreaseIndent();
}
- void dump(ProtoOutputStream proto, long fieldId) {
- final long token = proto.start(fieldId);
+ void dump(ProtoOutputStream proto) {
proto.write(ConstantsProto.MIN_IDLE_COUNT, MIN_IDLE_COUNT);
proto.write(ConstantsProto.MIN_CHARGING_COUNT, MIN_CHARGING_COUNT);
proto.write(ConstantsProto.MIN_BATTERY_NOT_LOW_COUNT, MIN_BATTERY_NOT_LOW_COUNT);
@@ -973,40 +768,6 @@
proto.write(ConstantsProto.CONN_CONGESTION_DELAY_FRAC, CONN_CONGESTION_DELAY_FRAC);
proto.write(ConstantsProto.CONN_PREFETCH_RELAX_FRAC, CONN_PREFETCH_RELAX_FRAC);
proto.write(ConstantsProto.USE_HEARTBEATS, USE_HEARTBEATS);
-
- final long tcToken = proto.start(ConstantsProto.TIME_CONTROLLER);
- proto.write(ConstantsProto.TimeController.SKIP_NOT_READY_JOBS,
- TIME_CONTROLLER_SKIP_NOT_READY_JOBS);
- proto.end(tcToken);
-
- final long qcToken = proto.start(ConstantsProto.QUOTA_CONTROLLER);
- proto.write(ConstantsProto.QuotaController.ALLOWED_TIME_PER_PERIOD_MS,
- QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS);
- proto.write(ConstantsProto.QuotaController.IN_QUOTA_BUFFER_MS,
- QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS);
- proto.write(ConstantsProto.QuotaController.ACTIVE_WINDOW_SIZE_MS,
- QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS);
- proto.write(ConstantsProto.QuotaController.WORKING_WINDOW_SIZE_MS,
- QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS);
- proto.write(ConstantsProto.QuotaController.FREQUENT_WINDOW_SIZE_MS,
- QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS);
- proto.write(ConstantsProto.QuotaController.RARE_WINDOW_SIZE_MS,
- QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS);
- proto.write(ConstantsProto.QuotaController.MAX_EXECUTION_TIME_MS,
- QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS);
- proto.write(ConstantsProto.QuotaController.MAX_JOB_COUNT_ACTIVE,
- QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE);
- proto.write(ConstantsProto.QuotaController.MAX_JOB_COUNT_WORKING,
- QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING);
- proto.write(ConstantsProto.QuotaController.MAX_JOB_COUNT_FREQUENT,
- QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT);
- proto.write(ConstantsProto.QuotaController.MAX_JOB_COUNT_RARE,
- QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE);
- proto.write(ConstantsProto.QuotaController.MAX_JOB_COUNT_PER_ALLOWED_TIME,
- QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME);
- proto.end(qcToken);
-
- proto.end(token);
}
}
@@ -1636,6 +1397,9 @@
public void onBootPhase(int phase) {
if (PHASE_SYSTEM_SERVICES_READY == phase) {
mConstantsObserver.start(getContext().getContentResolver());
+ for (StateController controller : mControllers) {
+ controller.onSystemServicesReady();
+ }
mAppStateTracker = Preconditions.checkNotNull(
LocalServices.getService(AppStateTracker.class));
@@ -1801,7 +1565,8 @@
*
* @see #maybeQueueReadyJobsForExecutionLocked
*/
- private JobStatus getRescheduleJobForFailureLocked(JobStatus failureToReschedule) {
+ @VisibleForTesting
+ JobStatus getRescheduleJobForFailureLocked(JobStatus failureToReschedule) {
final long elapsedNowMillis = sElapsedRealtimeClock.millis();
final JobInfo job = failureToReschedule.getJob();
@@ -1848,6 +1613,10 @@
elapsedNowMillis + delayMillis,
JobStatus.NO_LATEST_RUNTIME, backoffAttempts,
failureToReschedule.getLastSuccessfulRunTime(), sSystemClock.millis());
+ if (job.isPeriodic()) {
+ newJob.setOriginalLatestRunTimeElapsed(
+ failureToReschedule.getOriginalLatestRunTimeElapsed());
+ }
for (int ic=0; ic<mControllers.size(); ic++) {
StateController controller = mControllers.get(ic);
controller.rescheduleForFailureLocked(newJob, failureToReschedule);
@@ -1868,23 +1637,41 @@
* @return A new job representing the execution criteria for this instantiation of the
* recurring job.
*/
- private JobStatus getRescheduleJobForPeriodic(JobStatus periodicToReschedule) {
+ @VisibleForTesting
+ JobStatus getRescheduleJobForPeriodic(JobStatus periodicToReschedule) {
final long elapsedNow = sElapsedRealtimeClock.millis();
- // Compute how much of the period is remaining.
- long runEarly = 0L;
+ final long newLatestRuntimeElapsed;
+ final long period = periodicToReschedule.getJob().getIntervalMillis();
+ final long latestRunTimeElapsed = periodicToReschedule.getOriginalLatestRunTimeElapsed();
+ final long flex = periodicToReschedule.getJob().getFlexMillis();
- // If this periodic was rescheduled it won't have a deadline.
- if (periodicToReschedule.hasDeadlineConstraint()) {
- runEarly = Math.max(periodicToReschedule.getLatestRunTimeElapsed() - elapsedNow, 0L);
+ if (elapsedNow > latestRunTimeElapsed) {
+ // The job ran past its expected run window. Have it count towards the current window
+ // and schedule a new job for the next window.
+ if (DEBUG) {
+ Slog.i(TAG, "Periodic job ran after its intended window.");
+ }
+ final long diffMs = (elapsedNow - latestRunTimeElapsed);
+ int numSkippedWindows = (int) (diffMs / period) + 1; // +1 to include original window
+ if (period != flex && diffMs > Math.min(30 * MINUTE_IN_MILLIS, (period - flex) / 2)) {
+ if (DEBUG) {
+ Slog.d(TAG, "Custom flex job ran too close to next window.");
+ }
+ // For custom flex periods, if the job was run too close to the next window,
+ // skip the next window and schedule for the following one.
+ numSkippedWindows += 1;
+ }
+ newLatestRuntimeElapsed = latestRunTimeElapsed + (period * numSkippedWindows);
+ } else {
+ newLatestRuntimeElapsed = latestRunTimeElapsed + period;
}
- long flex = periodicToReschedule.getJob().getFlexMillis();
- long period = periodicToReschedule.getJob().getIntervalMillis();
- long newLatestRuntimeElapsed = elapsedNow + runEarly + period;
- long newEarliestRunTimeElapsed = newLatestRuntimeElapsed - flex;
+
+ final long newEarliestRunTimeElapsed = newLatestRuntimeElapsed - flex;
if (DEBUG) {
Slog.v(TAG, "Rescheduling executed periodic. New execution window [" +
- newEarliestRunTimeElapsed/1000 + ", " + newLatestRuntimeElapsed/1000 + "]s");
+ newEarliestRunTimeElapsed / 1000 + ", " + newLatestRuntimeElapsed / 1000
+ + "]s");
}
return new JobStatus(periodicToReschedule, getCurrentHeartbeat(),
newEarliestRunTimeElapsed, newLatestRuntimeElapsed,
@@ -3424,6 +3211,11 @@
};
synchronized (mLock) {
mConstants.dump(pw);
+ for (StateController controller : mControllers) {
+ pw.increaseIndent();
+ controller.dumpConstants(pw);
+ pw.decreaseIndent();
+ }
pw.println();
pw.println(" Heartbeat:");
@@ -3614,7 +3406,13 @@
};
synchronized (mLock) {
- mConstants.dump(proto, JobSchedulerServiceDumpProto.SETTINGS);
+ final long settingsToken = proto.start(JobSchedulerServiceDumpProto.SETTINGS);
+ mConstants.dump(proto);
+ for (StateController controller : mControllers) {
+ controller.dumpConstants(proto);
+ }
+ proto.end(settingsToken);
+
proto.write(JobSchedulerServiceDumpProto.CURRENT_HEARTBEAT, mHeartbeat);
proto.write(JobSchedulerServiceDumpProto.NEXT_HEARTBEAT, mNextBucketHeartbeat[0]);
proto.write(JobSchedulerServiceDumpProto.NEXT_HEARTBEAT, mNextBucketHeartbeat[1]);
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index 48f21e4..fd20e11 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -161,6 +161,12 @@
*/
private final long latestRunTimeElapsedMillis;
+ /**
+ * Valid only for periodic jobs. The original latest point in the future at which this
+ * job was expected to run.
+ */
+ private long mOriginalLatestRunTimeElapsedMillis;
+
/** How many times this job has failed, used to compute back-off. */
private final int numFailures;
@@ -394,6 +400,7 @@
this.earliestRunTimeElapsedMillis = earliestRunTimeElapsedMillis;
this.latestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
+ this.mOriginalLatestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
this.numFailures = numFailures;
int requiredConstraints = job.getConstraintFlags();
@@ -871,6 +878,14 @@
return latestRunTimeElapsedMillis;
}
+ public long getOriginalLatestRunTimeElapsed() {
+ return mOriginalLatestRunTimeElapsedMillis;
+ }
+
+ public void setOriginalLatestRunTimeElapsed(long latestRunTimeElapsed) {
+ mOriginalLatestRunTimeElapsedMillis = latestRunTimeElapsed;
+ }
+
/**
* Return the fractional position of "now" within the "run time" window of
* this job.
diff --git a/services/core/java/com/android/server/job/controllers/QuotaController.java b/services/core/java/com/android/server/job/controllers/QuotaController.java
index 11f0939..2a9d3f3 100644
--- a/services/core/java/com/android/server/job/controllers/QuotaController.java
+++ b/services/core/java/com/android/server/job/controllers/QuotaController.java
@@ -34,9 +34,12 @@
import android.app.usage.UsageStatsManagerInternal;
import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener;
import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.database.ContentObserver;
+import android.net.Uri;
import android.os.BatteryManager;
import android.os.BatteryManagerInternal;
import android.os.Handler;
@@ -44,8 +47,10 @@
import android.os.Message;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.provider.Settings;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.KeyValueListParser;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
@@ -57,6 +62,7 @@
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.LocalServices;
+import com.android.server.job.ConstantsProto;
import com.android.server.job.JobSchedulerService;
import com.android.server.job.StateControllerProto;
@@ -354,6 +360,7 @@
private final AlarmManager mAlarmManager;
private final ChargingTracker mChargeTracker;
private final Handler mHandler;
+ private final QcConstants mQcConstants;
private volatile boolean mInParole;
@@ -489,6 +496,7 @@
mChargeTracker.startTracking();
mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
+ mQcConstants = new QcConstants(mHandler);
final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
mContext.registerReceiverAsUser(mPackageAddedReceiver, UserHandle.ALL, filter, null, null);
@@ -506,7 +514,12 @@
// ignored; both services live in system_server
}
- onConstantsUpdatedLocked();
+ mShouldThrottle = !mConstants.USE_HEARTBEATS;
+ }
+
+ @Override
+ public void onSystemServicesReady() {
+ mQcConstants.start(mContext.getContentResolver());
}
@Override
@@ -581,89 +594,9 @@
@Override
public void onConstantsUpdatedLocked() {
- boolean changed = false;
if (mShouldThrottle == mConstants.USE_HEARTBEATS) {
mShouldThrottle = !mConstants.USE_HEARTBEATS;
- changed = true;
- }
- long newAllowedTimeMs = Math.min(MAX_PERIOD_MS,
- Math.max(MINUTE_IN_MILLIS, mConstants.QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS));
- if (mAllowedTimePerPeriodMs != newAllowedTimeMs) {
- mAllowedTimePerPeriodMs = newAllowedTimeMs;
- mAllowedTimeIntoQuotaMs = mAllowedTimePerPeriodMs - mQuotaBufferMs;
- changed = true;
- }
- long newQuotaBufferMs = Math.max(0,
- Math.min(5 * MINUTE_IN_MILLIS, mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS));
- if (mQuotaBufferMs != newQuotaBufferMs) {
- mQuotaBufferMs = newQuotaBufferMs;
- mAllowedTimeIntoQuotaMs = mAllowedTimePerPeriodMs - mQuotaBufferMs;
- mMaxExecutionTimeIntoQuotaMs = mMaxExecutionTimeMs - mQuotaBufferMs;
- changed = true;
- }
- long newActivePeriodMs = Math.max(mAllowedTimePerPeriodMs,
- Math.min(MAX_PERIOD_MS, mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS));
- if (mBucketPeriodsMs[ACTIVE_INDEX] != newActivePeriodMs) {
- mBucketPeriodsMs[ACTIVE_INDEX] = newActivePeriodMs;
- changed = true;
- }
- long newWorkingPeriodMs = Math.max(mAllowedTimePerPeriodMs,
- Math.min(MAX_PERIOD_MS, mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS));
- if (mBucketPeriodsMs[WORKING_INDEX] != newWorkingPeriodMs) {
- mBucketPeriodsMs[WORKING_INDEX] = newWorkingPeriodMs;
- changed = true;
- }
- long newFrequentPeriodMs = Math.max(mAllowedTimePerPeriodMs,
- Math.min(MAX_PERIOD_MS, mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS));
- if (mBucketPeriodsMs[FREQUENT_INDEX] != newFrequentPeriodMs) {
- mBucketPeriodsMs[FREQUENT_INDEX] = newFrequentPeriodMs;
- changed = true;
- }
- long newRarePeriodMs = Math.max(mAllowedTimePerPeriodMs,
- Math.min(MAX_PERIOD_MS, mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS));
- if (mBucketPeriodsMs[RARE_INDEX] != newRarePeriodMs) {
- mBucketPeriodsMs[RARE_INDEX] = newRarePeriodMs;
- changed = true;
- }
- long newMaxExecutionTimeMs = Math.max(60 * MINUTE_IN_MILLIS,
- Math.min(MAX_PERIOD_MS, mConstants.QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS));
- if (mMaxExecutionTimeMs != newMaxExecutionTimeMs) {
- mMaxExecutionTimeMs = newMaxExecutionTimeMs;
- mMaxExecutionTimeIntoQuotaMs = mMaxExecutionTimeMs - mQuotaBufferMs;
- changed = true;
- }
- int newMaxCountPerAllowedPeriod = Math.max(10,
- mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME);
- if (mMaxJobCountPerAllowedTime != newMaxCountPerAllowedPeriod) {
- mMaxJobCountPerAllowedTime = newMaxCountPerAllowedPeriod;
- changed = true;
- }
- int newActiveMaxJobCount = Math.max(mMaxJobCountPerAllowedTime,
- Math.max(MIN_BUCKET_JOB_COUNT, mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE));
- if (mMaxBucketJobCounts[ACTIVE_INDEX] != newActiveMaxJobCount) {
- mMaxBucketJobCounts[ACTIVE_INDEX] = newActiveMaxJobCount;
- changed = true;
- }
- int newWorkingMaxJobCount = Math.max(mMaxJobCountPerAllowedTime,
- Math.max(MIN_BUCKET_JOB_COUNT, mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING));
- if (mMaxBucketJobCounts[WORKING_INDEX] != newWorkingMaxJobCount) {
- mMaxBucketJobCounts[WORKING_INDEX] = newWorkingMaxJobCount;
- changed = true;
- }
- int newFrequentMaxJobCount = Math.max(mMaxJobCountPerAllowedTime,
- Math.max(MIN_BUCKET_JOB_COUNT, mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT));
- if (mMaxBucketJobCounts[FREQUENT_INDEX] != newFrequentMaxJobCount) {
- mMaxBucketJobCounts[FREQUENT_INDEX] = newFrequentMaxJobCount;
- changed = true;
- }
- int newRareMaxJobCount = Math.max(mMaxJobCountPerAllowedTime,
- Math.max(MIN_BUCKET_JOB_COUNT, mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE));
- if (mMaxBucketJobCounts[RARE_INDEX] != newRareMaxJobCount) {
- mMaxBucketJobCounts[RARE_INDEX] = newRareMaxJobCount;
- changed = true;
- }
- if (changed) {
// Update job bookkeeping out of band.
BackgroundThread.getHandler().post(() -> {
synchronized (mLock) {
@@ -1891,6 +1824,311 @@
}
}
+ @VisibleForTesting
+ class QcConstants extends ContentObserver {
+ private ContentResolver mResolver;
+ private final KeyValueListParser mParser = new KeyValueListParser(',');
+
+ private static final String KEY_ALLOWED_TIME_PER_PERIOD_MS = "allowed_time_per_period_ms";
+ private static final String KEY_IN_QUOTA_BUFFER_MS = "in_quota_buffer_ms";
+ private static final String KEY_WINDOW_SIZE_ACTIVE_MS = "window_size_active_ms";
+ private static final String KEY_WINDOW_SIZE_WORKING_MS = "window_size_working_ms";
+ private static final String KEY_WINDOW_SIZE_FREQUENT_MS = "window_size_frequent_ms";
+ private static final String KEY_WINDOW_SIZE_RARE_MS = "window_size_rare_ms";
+ private static final String KEY_MAX_EXECUTION_TIME_MS = "max_execution_time_ms";
+ private static final String KEY_MAX_JOB_COUNT_ACTIVE = "max_job_count_active";
+ private static final String KEY_MAX_JOB_COUNT_WORKING = "max_job_count_working";
+ private static final String KEY_MAX_JOB_COUNT_FREQUENT = "max_job_count_frequent";
+ private static final String KEY_MAX_JOB_COUNT_RARE = "max_job_count_rare";
+ private static final String KEY_MAX_JOB_COUNT_PER_ALLOWED_TIME =
+ "max_count_per_allowed_time";
+
+ private static final long DEFAULT_ALLOWED_TIME_PER_PERIOD_MS =
+ 10 * 60 * 1000L; // 10 minutes
+ private static final long DEFAULT_IN_QUOTA_BUFFER_MS =
+ 30 * 1000L; // 30 seconds
+ private static final long DEFAULT_WINDOW_SIZE_ACTIVE_MS =
+ 10 * 60 * 1000L; // 10 minutes for ACTIVE -- ACTIVE apps can run jobs at any time
+ private static final long DEFAULT_WINDOW_SIZE_WORKING_MS =
+ 2 * 60 * 60 * 1000L; // 2 hours
+ private static final long DEFAULT_WINDOW_SIZE_FREQUENT_MS =
+ 8 * 60 * 60 * 1000L; // 8 hours
+ private static final long DEFAULT_WINDOW_SIZE_RARE_MS =
+ 24 * 60 * 60 * 1000L; // 24 hours
+ private static final long DEFAULT_MAX_EXECUTION_TIME_MS =
+ 4 * 60 * 60 * 1000L; // 4 hours
+ private static final int DEFAULT_MAX_JOB_COUNT_ACTIVE =
+ 200; // 1200/hr
+ private static final int DEFAULT_MAX_JOB_COUNT_WORKING =
+ 1200; // 600/hr
+ private static final int DEFAULT_MAX_JOB_COUNT_FREQUENT =
+ 1800; // 225/hr
+ private static final int DEFAULT_MAX_JOB_COUNT_RARE =
+ 2400; // 100/hr
+ private static final int DEFAULT_MAX_JOB_COUNT_PER_ALLOWED_TIME = 20;
+
+ /** How much time each app will have to run jobs within their standby bucket window. */
+ public long ALLOWED_TIME_PER_PERIOD_MS = DEFAULT_ALLOWED_TIME_PER_PERIOD_MS;
+
+ /**
+ * How much time the package should have before transitioning from out-of-quota to in-quota.
+ * This should not affect processing if the package is already in-quota.
+ */
+ public long IN_QUOTA_BUFFER_MS = DEFAULT_IN_QUOTA_BUFFER_MS;
+
+ /**
+ * The quota window size of the particular standby bucket. Apps in this standby bucket are
+ * expected to run only {@link #ALLOWED_TIME_PER_PERIOD_MS} within the past
+ * WINDOW_SIZE_MS.
+ */
+ public long WINDOW_SIZE_ACTIVE_MS = DEFAULT_WINDOW_SIZE_ACTIVE_MS;
+
+ /**
+ * The quota window size of the particular standby bucket. Apps in this standby bucket are
+ * expected to run only {@link #ALLOWED_TIME_PER_PERIOD_MS} within the past
+ * WINDOW_SIZE_MS.
+ */
+ public long WINDOW_SIZE_WORKING_MS = DEFAULT_WINDOW_SIZE_WORKING_MS;
+
+ /**
+ * The quota window size of the particular standby bucket. Apps in this standby bucket are
+ * expected to run only {@link #ALLOWED_TIME_PER_PERIOD_MS} within the past
+ * WINDOW_SIZE_MS.
+ */
+ public long WINDOW_SIZE_FREQUENT_MS = DEFAULT_WINDOW_SIZE_FREQUENT_MS;
+
+ /**
+ * The quota window size of the particular standby bucket. Apps in this standby bucket are
+ * expected to run only {@link #ALLOWED_TIME_PER_PERIOD_MS} within the past
+ * WINDOW_SIZE_MS.
+ */
+ public long WINDOW_SIZE_RARE_MS = DEFAULT_WINDOW_SIZE_RARE_MS;
+
+ /**
+ * The maximum amount of time an app can have its jobs running within a 24 hour window.
+ */
+ public long MAX_EXECUTION_TIME_MS = DEFAULT_MAX_EXECUTION_TIME_MS;
+
+ /**
+ * The maximum number of jobs an app can run within this particular standby bucket's
+ * window size.
+ */
+ public int MAX_JOB_COUNT_ACTIVE = DEFAULT_MAX_JOB_COUNT_ACTIVE;
+
+ /**
+ * The maximum number of jobs an app can run within this particular standby bucket's
+ * window size.
+ */
+ public int MAX_JOB_COUNT_WORKING = DEFAULT_MAX_JOB_COUNT_WORKING;
+
+ /**
+ * The maximum number of jobs an app can run within this particular standby bucket's
+ * window size.
+ */
+ public int MAX_JOB_COUNT_FREQUENT = DEFAULT_MAX_JOB_COUNT_FREQUENT;
+
+ /**
+ * The maximum number of jobs an app can run within this particular standby bucket's
+ * window size.
+ */
+ public int MAX_JOB_COUNT_RARE = DEFAULT_MAX_JOB_COUNT_RARE;
+
+ /**
+ * The maximum number of jobs that can run within the past
+ * {@link #ALLOWED_TIME_PER_PERIOD_MS}.
+ */
+ public int MAX_JOB_COUNT_PER_ALLOWED_TIME = DEFAULT_MAX_JOB_COUNT_PER_ALLOWED_TIME;
+
+ QcConstants(Handler handler) {
+ super(handler);
+ }
+
+ private void start(ContentResolver resolver) {
+ mResolver = resolver;
+ mResolver.registerContentObserver(Settings.Global.getUriFor(
+ Settings.Global.JOB_SCHEDULER_QUOTA_CONTROLLER_CONSTANTS), false, this);
+ updateConstants();
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ final String constants = Settings.Global.getString(
+ mResolver, Settings.Global.JOB_SCHEDULER_QUOTA_CONTROLLER_CONSTANTS);
+
+ try {
+ mParser.setString(constants);
+ } catch (Exception e) {
+ // Failed to parse the settings string, log this and move on with defaults.
+ Slog.e(TAG, "Bad jobscheduler quota controller settings", e);
+ }
+
+ ALLOWED_TIME_PER_PERIOD_MS = mParser.getDurationMillis(
+ KEY_ALLOWED_TIME_PER_PERIOD_MS, DEFAULT_ALLOWED_TIME_PER_PERIOD_MS);
+ IN_QUOTA_BUFFER_MS = mParser.getDurationMillis(
+ KEY_IN_QUOTA_BUFFER_MS, DEFAULT_IN_QUOTA_BUFFER_MS);
+ WINDOW_SIZE_ACTIVE_MS = mParser.getDurationMillis(
+ KEY_WINDOW_SIZE_ACTIVE_MS, DEFAULT_WINDOW_SIZE_ACTIVE_MS);
+ WINDOW_SIZE_WORKING_MS = mParser.getDurationMillis(
+ KEY_WINDOW_SIZE_WORKING_MS, DEFAULT_WINDOW_SIZE_WORKING_MS);
+ WINDOW_SIZE_FREQUENT_MS = mParser.getDurationMillis(
+ KEY_WINDOW_SIZE_FREQUENT_MS, DEFAULT_WINDOW_SIZE_FREQUENT_MS);
+ WINDOW_SIZE_RARE_MS = mParser.getDurationMillis(
+ KEY_WINDOW_SIZE_RARE_MS, DEFAULT_WINDOW_SIZE_RARE_MS);
+ MAX_EXECUTION_TIME_MS = mParser.getDurationMillis(
+ KEY_MAX_EXECUTION_TIME_MS, DEFAULT_MAX_EXECUTION_TIME_MS);
+ MAX_JOB_COUNT_ACTIVE = mParser.getInt(
+ KEY_MAX_JOB_COUNT_ACTIVE, DEFAULT_MAX_JOB_COUNT_ACTIVE);
+ MAX_JOB_COUNT_WORKING = mParser.getInt(
+ KEY_MAX_JOB_COUNT_WORKING, DEFAULT_MAX_JOB_COUNT_WORKING);
+ MAX_JOB_COUNT_FREQUENT = mParser.getInt(
+ KEY_MAX_JOB_COUNT_FREQUENT, DEFAULT_MAX_JOB_COUNT_FREQUENT);
+ MAX_JOB_COUNT_RARE = mParser.getInt(
+ KEY_MAX_JOB_COUNT_RARE, DEFAULT_MAX_JOB_COUNT_RARE);
+ MAX_JOB_COUNT_PER_ALLOWED_TIME = mParser.getInt(
+ KEY_MAX_JOB_COUNT_PER_ALLOWED_TIME, DEFAULT_MAX_JOB_COUNT_PER_ALLOWED_TIME);
+
+ updateConstants();
+ }
+
+ @VisibleForTesting
+ void updateConstants() {
+ synchronized (mLock) {
+ boolean changed = false;
+
+ long newAllowedTimeMs = Math.min(MAX_PERIOD_MS,
+ Math.max(MINUTE_IN_MILLIS, ALLOWED_TIME_PER_PERIOD_MS));
+ if (mAllowedTimePerPeriodMs != newAllowedTimeMs) {
+ mAllowedTimePerPeriodMs = newAllowedTimeMs;
+ mAllowedTimeIntoQuotaMs = mAllowedTimePerPeriodMs - mQuotaBufferMs;
+ changed = true;
+ }
+ long newQuotaBufferMs = Math.max(0,
+ Math.min(5 * MINUTE_IN_MILLIS, IN_QUOTA_BUFFER_MS));
+ if (mQuotaBufferMs != newQuotaBufferMs) {
+ mQuotaBufferMs = newQuotaBufferMs;
+ mAllowedTimeIntoQuotaMs = mAllowedTimePerPeriodMs - mQuotaBufferMs;
+ mMaxExecutionTimeIntoQuotaMs = mMaxExecutionTimeMs - mQuotaBufferMs;
+ changed = true;
+ }
+ long newActivePeriodMs = Math.max(mAllowedTimePerPeriodMs,
+ Math.min(MAX_PERIOD_MS, WINDOW_SIZE_ACTIVE_MS));
+ if (mBucketPeriodsMs[ACTIVE_INDEX] != newActivePeriodMs) {
+ mBucketPeriodsMs[ACTIVE_INDEX] = newActivePeriodMs;
+ changed = true;
+ }
+ long newWorkingPeriodMs = Math.max(mAllowedTimePerPeriodMs,
+ Math.min(MAX_PERIOD_MS, WINDOW_SIZE_WORKING_MS));
+ if (mBucketPeriodsMs[WORKING_INDEX] != newWorkingPeriodMs) {
+ mBucketPeriodsMs[WORKING_INDEX] = newWorkingPeriodMs;
+ changed = true;
+ }
+ long newFrequentPeriodMs = Math.max(mAllowedTimePerPeriodMs,
+ Math.min(MAX_PERIOD_MS, WINDOW_SIZE_FREQUENT_MS));
+ if (mBucketPeriodsMs[FREQUENT_INDEX] != newFrequentPeriodMs) {
+ mBucketPeriodsMs[FREQUENT_INDEX] = newFrequentPeriodMs;
+ changed = true;
+ }
+ long newRarePeriodMs = Math.max(mAllowedTimePerPeriodMs,
+ Math.min(MAX_PERIOD_MS, WINDOW_SIZE_RARE_MS));
+ if (mBucketPeriodsMs[RARE_INDEX] != newRarePeriodMs) {
+ mBucketPeriodsMs[RARE_INDEX] = newRarePeriodMs;
+ changed = true;
+ }
+ long newMaxExecutionTimeMs = Math.max(60 * MINUTE_IN_MILLIS,
+ Math.min(MAX_PERIOD_MS, MAX_EXECUTION_TIME_MS));
+ if (mMaxExecutionTimeMs != newMaxExecutionTimeMs) {
+ mMaxExecutionTimeMs = newMaxExecutionTimeMs;
+ mMaxExecutionTimeIntoQuotaMs = mMaxExecutionTimeMs - mQuotaBufferMs;
+ changed = true;
+ }
+ int newMaxCountPerAllowedPeriod = Math.max(10,
+ MAX_JOB_COUNT_PER_ALLOWED_TIME);
+ if (mMaxJobCountPerAllowedTime != newMaxCountPerAllowedPeriod) {
+ mMaxJobCountPerAllowedTime = newMaxCountPerAllowedPeriod;
+ changed = true;
+ }
+ int newActiveMaxJobCount = Math.max(mMaxJobCountPerAllowedTime,
+ Math.max(MIN_BUCKET_JOB_COUNT, MAX_JOB_COUNT_ACTIVE));
+ if (mMaxBucketJobCounts[ACTIVE_INDEX] != newActiveMaxJobCount) {
+ mMaxBucketJobCounts[ACTIVE_INDEX] = newActiveMaxJobCount;
+ changed = true;
+ }
+ int newWorkingMaxJobCount = Math.max(mMaxJobCountPerAllowedTime,
+ Math.max(MIN_BUCKET_JOB_COUNT, MAX_JOB_COUNT_WORKING));
+ if (mMaxBucketJobCounts[WORKING_INDEX] != newWorkingMaxJobCount) {
+ mMaxBucketJobCounts[WORKING_INDEX] = newWorkingMaxJobCount;
+ changed = true;
+ }
+ int newFrequentMaxJobCount = Math.max(mMaxJobCountPerAllowedTime,
+ Math.max(MIN_BUCKET_JOB_COUNT, MAX_JOB_COUNT_FREQUENT));
+ if (mMaxBucketJobCounts[FREQUENT_INDEX] != newFrequentMaxJobCount) {
+ mMaxBucketJobCounts[FREQUENT_INDEX] = newFrequentMaxJobCount;
+ changed = true;
+ }
+ int newRareMaxJobCount = Math.max(mMaxJobCountPerAllowedTime,
+ Math.max(MIN_BUCKET_JOB_COUNT, MAX_JOB_COUNT_RARE));
+ if (mMaxBucketJobCounts[RARE_INDEX] != newRareMaxJobCount) {
+ mMaxBucketJobCounts[RARE_INDEX] = newRareMaxJobCount;
+ changed = true;
+ }
+
+ if (changed && mShouldThrottle) {
+ // Update job bookkeeping out of band.
+ BackgroundThread.getHandler().post(() -> {
+ synchronized (mLock) {
+ maybeUpdateAllConstraintsLocked();
+ }
+ });
+ }
+ }
+ }
+
+ private void dump(IndentingPrintWriter pw) {
+ pw.println();
+ pw.println("QuotaController:");
+ pw.increaseIndent();
+ pw.printPair(KEY_ALLOWED_TIME_PER_PERIOD_MS, ALLOWED_TIME_PER_PERIOD_MS).println();
+ pw.printPair(KEY_IN_QUOTA_BUFFER_MS, IN_QUOTA_BUFFER_MS).println();
+ pw.printPair(KEY_WINDOW_SIZE_ACTIVE_MS, WINDOW_SIZE_ACTIVE_MS).println();
+ pw.printPair(KEY_WINDOW_SIZE_WORKING_MS, WINDOW_SIZE_WORKING_MS).println();
+ pw.printPair(KEY_WINDOW_SIZE_FREQUENT_MS, WINDOW_SIZE_FREQUENT_MS).println();
+ pw.printPair(KEY_WINDOW_SIZE_RARE_MS, WINDOW_SIZE_RARE_MS).println();
+ pw.printPair(KEY_MAX_EXECUTION_TIME_MS, MAX_EXECUTION_TIME_MS).println();
+ pw.printPair(KEY_MAX_JOB_COUNT_ACTIVE, MAX_JOB_COUNT_ACTIVE).println();
+ pw.printPair(KEY_MAX_JOB_COUNT_WORKING, MAX_JOB_COUNT_WORKING).println();
+ pw.printPair(KEY_MAX_JOB_COUNT_FREQUENT, MAX_JOB_COUNT_FREQUENT).println();
+ pw.printPair(KEY_MAX_JOB_COUNT_RARE, MAX_JOB_COUNT_RARE).println();
+ pw.printPair(KEY_MAX_JOB_COUNT_PER_ALLOWED_TIME, MAX_JOB_COUNT_PER_ALLOWED_TIME)
+ .println();
+ pw.decreaseIndent();
+ }
+
+ private void dump(ProtoOutputStream proto) {
+ final long qcToken = proto.start(ConstantsProto.QUOTA_CONTROLLER);
+ proto.write(ConstantsProto.QuotaController.ALLOWED_TIME_PER_PERIOD_MS,
+ ALLOWED_TIME_PER_PERIOD_MS);
+ proto.write(ConstantsProto.QuotaController.IN_QUOTA_BUFFER_MS, IN_QUOTA_BUFFER_MS);
+ proto.write(ConstantsProto.QuotaController.ACTIVE_WINDOW_SIZE_MS,
+ WINDOW_SIZE_ACTIVE_MS);
+ proto.write(ConstantsProto.QuotaController.WORKING_WINDOW_SIZE_MS,
+ WINDOW_SIZE_WORKING_MS);
+ proto.write(ConstantsProto.QuotaController.FREQUENT_WINDOW_SIZE_MS,
+ WINDOW_SIZE_FREQUENT_MS);
+ proto.write(ConstantsProto.QuotaController.RARE_WINDOW_SIZE_MS, WINDOW_SIZE_RARE_MS);
+ proto.write(ConstantsProto.QuotaController.MAX_EXECUTION_TIME_MS,
+ MAX_EXECUTION_TIME_MS);
+ proto.write(ConstantsProto.QuotaController.MAX_JOB_COUNT_ACTIVE, MAX_JOB_COUNT_ACTIVE);
+ proto.write(ConstantsProto.QuotaController.MAX_JOB_COUNT_WORKING,
+ MAX_JOB_COUNT_WORKING);
+ proto.write(ConstantsProto.QuotaController.MAX_JOB_COUNT_FREQUENT,
+ MAX_JOB_COUNT_FREQUENT);
+ proto.write(ConstantsProto.QuotaController.MAX_JOB_COUNT_RARE, MAX_JOB_COUNT_RARE);
+ proto.write(ConstantsProto.QuotaController.MAX_JOB_COUNT_PER_ALLOWED_TIME,
+ MAX_JOB_COUNT_PER_ALLOWED_TIME);
+ proto.end(qcToken);
+ }
+ }
+
//////////////////////// TESTING HELPERS /////////////////////////////
@VisibleForTesting
@@ -1943,6 +2181,12 @@
return mTimingSessions.get(userId, packageName);
}
+ @VisibleForTesting
+ @NonNull
+ QcConstants getQcConstants() {
+ return mQcConstants;
+ }
+
//////////////////////////// DATA DUMP //////////////////////////////
@Override
@@ -2188,4 +2432,14 @@
proto.end(mToken);
proto.end(token);
}
+
+ @Override
+ public void dumpConstants(IndentingPrintWriter pw) {
+ mQcConstants.dump(pw);
+ }
+
+ @Override
+ public void dumpConstants(ProtoOutputStream proto) {
+ mQcConstants.dump(proto);
+ }
}
diff --git a/services/core/java/com/android/server/job/controllers/StateController.java b/services/core/java/com/android/server/job/controllers/StateController.java
index 74628fb..51be38b 100644
--- a/services/core/java/com/android/server/job/controllers/StateController.java
+++ b/services/core/java/com/android/server/job/controllers/StateController.java
@@ -52,6 +52,13 @@
}
/**
+ * Called when the system boot phase has reached
+ * {@link com.android.server.SystemService#PHASE_SYSTEM_SERVICES_READY}.
+ */
+ public void onSystemServicesReady() {
+ }
+
+ /**
* Implement the logic here to decide whether a job should be tracked by this controller.
* This logic is put here so the JobManager can be completely agnostic of Controller logic.
* Also called when updating a task, so implementing controllers have to be aware of
@@ -127,4 +134,12 @@
Predicate<JobStatus> predicate);
public abstract void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId,
Predicate<JobStatus> predicate);
+
+ /** Dump any internal constants the Controller may have. */
+ public void dumpConstants(IndentingPrintWriter pw) {
+ }
+
+ /** Dump any internal constants the Controller may have. */
+ public void dumpConstants(ProtoOutputStream proto) {
+ }
}
diff --git a/services/core/java/com/android/server/job/controllers/TimeController.java b/services/core/java/com/android/server/job/controllers/TimeController.java
index 70deb38..ababad9 100644
--- a/services/core/java/com/android/server/job/controllers/TimeController.java
+++ b/services/core/java/com/android/server/job/controllers/TimeController.java
@@ -18,13 +18,20 @@
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AlarmManager;
import android.app.AlarmManager.OnAlarmListener;
+import android.content.ContentResolver;
import android.content.Context;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
import android.os.Process;
import android.os.UserHandle;
import android.os.WorkSource;
+import android.provider.Settings;
+import android.util.KeyValueListParser;
import android.util.Log;
import android.util.Slog;
import android.util.TimeUtils;
@@ -32,6 +39,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.job.ConstantsProto;
import com.android.server.job.JobSchedulerService;
import com.android.server.job.StateControllerProto;
@@ -55,6 +63,9 @@
/** Delay alarm tag for logging purposes */
private final String DELAY_TAG = "*job.delay*";
+ private final Handler mHandler;
+ private final TcConstants mTcConstants;
+
private long mNextJobExpiredElapsedMillis;
private long mNextDelayExpiredElapsedMillis;
@@ -70,6 +81,14 @@
mNextJobExpiredElapsedMillis = Long.MAX_VALUE;
mNextDelayExpiredElapsedMillis = Long.MAX_VALUE;
mChainedAttributionEnabled = mService.isChainedAttributionEnabled();
+
+ mHandler = new Handler(mContext.getMainLooper());
+ mTcConstants = new TcConstants(mHandler);
+ }
+
+ @Override
+ public void onSystemServicesReady() {
+ mTcConstants.start(mContext.getContentResolver());
}
/**
@@ -118,7 +137,7 @@
job.hasDeadlineConstraint() ? job.getLatestRunTimeElapsed() : Long.MAX_VALUE;
final long delayExpiredElapsed =
job.hasTimingDelayConstraint() ? job.getEarliestRunTime() : Long.MAX_VALUE;
- if (mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS) {
+ if (mTcConstants.SKIP_NOT_READY_JOBS) {
if (wouldBeReadyWithConstraintLocked(job, JobStatus.CONSTRAINT_TIMING_DELAY)) {
maybeUpdateDelayAlarmLocked(delayExpiredElapsed, ws);
}
@@ -148,14 +167,8 @@
}
@Override
- public void onConstantsUpdatedLocked() {
- checkExpiredDeadlinesAndResetAlarm();
- checkExpiredDelaysAndResetAlarm();
- }
-
- @Override
public void evaluateStateLocked(JobStatus job) {
- if (!mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS) {
+ if (!mTcConstants.SKIP_NOT_READY_JOBS) {
return;
}
@@ -248,7 +261,7 @@
}
it.remove();
} else { // Sorted by expiry time, so take the next one and stop.
- if (mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS
+ if (mTcConstants.SKIP_NOT_READY_JOBS
&& !wouldBeReadyWithConstraintLocked(
job, JobStatus.CONSTRAINT_DEADLINE)) {
if (DEBUG) {
@@ -308,7 +321,7 @@
ready = true;
}
} else {
- if (mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS
+ if (mTcConstants.SKIP_NOT_READY_JOBS
&& !wouldBeReadyWithConstraintLocked(
job, JobStatus.CONSTRAINT_TIMING_DELAY)) {
if (DEBUG) {
@@ -439,6 +452,87 @@
}
};
+ @VisibleForTesting
+ void recheckAlarmsLocked() {
+ checkExpiredDeadlinesAndResetAlarm();
+ checkExpiredDelaysAndResetAlarm();
+ }
+
+ @VisibleForTesting
+ class TcConstants extends ContentObserver {
+ private ContentResolver mResolver;
+ private final KeyValueListParser mParser = new KeyValueListParser(',');
+
+ private static final String KEY_SKIP_NOT_READY_JOBS = "skip_not_ready_jobs";
+
+ private static final boolean DEFAULT_SKIP_NOT_READY_JOBS = true;
+
+ /**
+ * Whether or not TimeController should skip setting wakeup alarms for jobs that aren't
+ * ready now.
+ */
+ public boolean SKIP_NOT_READY_JOBS = DEFAULT_SKIP_NOT_READY_JOBS;
+
+ /**
+ * Creates a content observer.
+ *
+ * @param handler The handler to run {@link #onChange} on, or null if none.
+ */
+ TcConstants(Handler handler) {
+ super(handler);
+ }
+
+ private void start(ContentResolver resolver) {
+ mResolver = resolver;
+ mResolver.registerContentObserver(Settings.Global.getUriFor(
+ Settings.Global.JOB_SCHEDULER_TIME_CONTROLLER_CONSTANTS), false, this);
+ onChange(true, null);
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ final String constants = Settings.Global.getString(
+ mResolver, Settings.Global.JOB_SCHEDULER_TIME_CONTROLLER_CONSTANTS);
+
+ try {
+ mParser.setString(constants);
+ } catch (Exception e) {
+ // Failed to parse the settings string, log this and move on with defaults.
+ Slog.e(TAG, "Bad jobscheduler time controller settings", e);
+ }
+
+ final boolean oldVal = SKIP_NOT_READY_JOBS;
+ SKIP_NOT_READY_JOBS = mParser.getBoolean(
+ KEY_SKIP_NOT_READY_JOBS, DEFAULT_SKIP_NOT_READY_JOBS);
+
+ if (oldVal != SKIP_NOT_READY_JOBS) {
+ synchronized (mLock) {
+ recheckAlarmsLocked();
+ }
+ }
+ }
+
+ private void dump(IndentingPrintWriter pw) {
+ pw.println();
+ pw.println("TimeController:");
+ pw.increaseIndent();
+ pw.printPair(KEY_SKIP_NOT_READY_JOBS, SKIP_NOT_READY_JOBS).println();
+ pw.decreaseIndent();
+ }
+
+ private void dump(ProtoOutputStream proto) {
+ final long tcToken = proto.start(ConstantsProto.TIME_CONTROLLER);
+ proto.write(ConstantsProto.TimeController.SKIP_NOT_READY_JOBS, SKIP_NOT_READY_JOBS);
+ proto.end(tcToken);
+ }
+ }
+
+ @VisibleForTesting
+ @NonNull
+ TcConstants getTcConstants() {
+ return mTcConstants;
+ }
+
@Override
public void dumpControllerStateLocked(IndentingPrintWriter pw,
Predicate<JobStatus> predicate) {
@@ -513,4 +607,14 @@
proto.end(mToken);
proto.end(token);
}
+
+ @Override
+ public void dumpConstants(IndentingPrintWriter pw) {
+ mTcConstants.dump(pw);
+ }
+
+ @Override
+ public void dumpConstants(ProtoOutputStream proto) {
+ mTcConstants.dump(proto);
+ }
}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java
index c739650..1dffcf9 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java
@@ -333,6 +333,7 @@
String[] selectionArguments = new String[] {String.valueOf(userId)};
ensureUserMetadataEntryExists(userId);
+ invalidateKeysForUser(userId);
return db.update(UserMetadataEntry.TABLE_NAME, values, selection, selectionArguments);
}
@@ -394,16 +395,13 @@
/**
* Updates status of old keys to {@code RecoveryController.RECOVERY_STATUS_PERMANENT_FAILURE}.
*/
- public void invalidateKeysWithOldGenerationId(int userId, int newGenerationId) {
+ public void invalidateKeysForUser(int userId) {
SQLiteDatabase db = mKeyStoreDbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KeysEntry.COLUMN_NAME_RECOVERY_STATUS,
RecoveryController.RECOVERY_STATUS_PERMANENT_FAILURE);
- String selection =
- KeysEntry.COLUMN_NAME_USER_ID + " = ? AND "
- + KeysEntry.COLUMN_NAME_GENERATION_ID + " < ?";
- db.update(KeysEntry.TABLE_NAME, values, selection,
- new String[] {String.valueOf(userId), String.valueOf(newGenerationId)});
+ String selection = KeysEntry.COLUMN_NAME_USER_ID + " = ?";
+ db.update(KeysEntry.TABLE_NAME, values, selection, new String[] {String.valueOf(userId)});
}
/**
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index c6f6c50..19ff2c1 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -1164,6 +1164,15 @@
// Carrier might want to manage notifications themselves
final PersistableBundle config = mCarrierConfigManager.getConfigForSubId(subId);
+ if (!CarrierConfigManager.isConfigForIdentifiedCarrier(config)) {
+ if (LOGV) Slog.v(TAG, "isConfigForIdentifiedCarrier returned false");
+ // Don't show notifications until we confirm that the loaded config is from an
+ // identified carrier, which may want to manage their own notifications. This method
+ // should be called every time the carrier config changes anyways, and there's no
+ // reason to alert if there isn't a carrier.
+ return;
+ }
+
final boolean notifyWarning = getBooleanDefeatingNullable(config,
KEY_DATA_WARNING_NOTIFICATION_BOOL, true);
final boolean notifyLimit = getBooleanDefeatingNullable(config,
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 21a862a..5737532 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -26,6 +26,7 @@
import static android.app.NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED;
import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED;
import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED;
+import static android.app.NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED;
import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.app.NotificationManager.IMPORTANCE_MIN;
import static android.app.NotificationManager.IMPORTANCE_NONE;
@@ -1811,14 +1812,15 @@
}
private void registerDeviceConfigChange() {
- DeviceConfig.addOnPropertyChangedListener(
+ DeviceConfig.addOnPropertiesChangedListener(
DeviceConfig.NAMESPACE_SYSTEMUI,
getContext().getMainExecutor(),
- (namespace, name, value) -> {
- if (!DeviceConfig.NAMESPACE_SYSTEMUI.equals(namespace)) {
+ (properties) -> {
+ if (!DeviceConfig.NAMESPACE_SYSTEMUI.equals(properties.getNamespace())) {
return;
}
- if (SystemUiDeviceConfigFlags.NAS_DEFAULT_SERVICE.equals(name)) {
+ if (properties.getKeyset()
+ .contains(SystemUiDeviceConfigFlags.NAS_DEFAULT_SERVICE)) {
mAssistants.resetDefaultAssistantsIfNecessary();
}
});
@@ -3753,7 +3755,7 @@
pkg, userId, true, granted);
getContext().sendBroadcastAsUser(new Intent(
- NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
+ ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
.setPackage(pkg)
.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
UserHandle.of(userId), null);
@@ -3913,7 +3915,7 @@
userId, true, granted);
getContext().sendBroadcastAsUser(new Intent(
- NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
+ ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
.setPackage(listener.getPackageName())
.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
UserHandle.of(userId), null);
@@ -3929,7 +3931,9 @@
public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant,
int userId, boolean granted) {
checkCallerIsSystemOrSystemUiOrShell();
- mAssistants.setUserSet(userId, true);
+ for (UserInfo ui : mUm.getEnabledProfiles(userId)) {
+ mAssistants.setUserSet(ui.id, true);
+ }
final long identity = Binder.clearCallingIdentity();
try {
setNotificationAssistantAccessGrantedForUserInternal(assistant, userId, granted);
@@ -4143,30 +4147,36 @@
@VisibleForTesting
protected void setNotificationAssistantAccessGrantedForUserInternal(
- ComponentName assistant, int userId, boolean granted) {
- if (assistant == null) {
- ComponentName allowedAssistant = CollectionUtils.firstOrNull(
- mAssistants.getAllowedComponents(userId));
- if (allowedAssistant != null) {
- setNotificationAssistantAccessGrantedForUserInternal(
- allowedAssistant, userId, false);
+ ComponentName assistant, int baseUserId, boolean granted) {
+ List<UserInfo> users = mUm.getEnabledProfiles(baseUserId);
+ if (users != null) {
+ for (UserInfo user : users) {
+ int userId = user.id;
+ if (assistant == null) {
+ ComponentName allowedAssistant = CollectionUtils.firstOrNull(
+ mAssistants.getAllowedComponents(userId));
+ if (allowedAssistant != null) {
+ setNotificationAssistantAccessGrantedForUserInternal(
+ allowedAssistant, userId, false);
+ }
+ continue;
+ }
+ if (!granted || mAllowedManagedServicePackages.test(assistant.getPackageName(),
+ userId, mAssistants.getRequiredPermission())) {
+ mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(),
+ userId, false, granted);
+ mAssistants.setPackageOrComponentEnabled(assistant.flattenToString(),
+ userId, true, granted);
+
+ getContext().sendBroadcastAsUser(
+ new Intent(ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
+ .setPackage(assistant.getPackageName())
+ .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
+ UserHandle.of(userId), null);
+
+ handleSavePolicyFile();
+ }
}
- return;
- }
- if (!granted || mAllowedManagedServicePackages.test(assistant.getPackageName(), userId,
- mAssistants.getRequiredPermission())) {
- mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(),
- userId, false, granted);
- mAssistants.setPackageOrComponentEnabled(assistant.flattenToString(),
- userId, true, granted);
-
- getContext().sendBroadcastAsUser(new Intent(
- NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
- .setPackage(assistant.getPackageName())
- .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
- UserHandle.of(userId), null);
-
- handleSavePolicyFile();
}
}
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 981e0f5..f81015d 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -80,7 +80,6 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
import java.util.Objects;
@@ -731,12 +730,14 @@
public void writeXml(XmlSerializer out, boolean forBackup, Integer version, int userId)
throws IOException {
- final int N = mConfigs.size();
- for (int i = 0; i < N; i++) {
- if (forBackup && mConfigs.keyAt(i) != userId) {
- continue;
+ synchronized (mConfigs) {
+ final int n = mConfigs.size();
+ for (int i = 0; i < n; i++) {
+ if (forBackup && mConfigs.keyAt(i) != userId) {
+ continue;
+ }
+ mConfigs.valueAt(i).writeXml(out, version);
}
- mConfigs.valueAt(i).writeXml(out, version);
}
}
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index ee07c7d..209ccda 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -720,6 +720,26 @@
}
@Override
+ public String[] getDefaultOverlayPackages() throws RemoteException {
+ try {
+ traceBegin(TRACE_TAG_RRO, "OMS#getDefaultOverlayPackages");
+ getContext().enforceCallingOrSelfPermission(
+ android.Manifest.permission.MODIFY_THEME_OVERLAY, null);
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ return mImpl.getDefaultOverlayPackages();
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ } finally {
+ traceEnd(TRACE_TAG_RRO);
+ }
+ }
+
+ @Override
public void onShellCommand(@NonNull final FileDescriptor in,
@NonNull final FileDescriptor out, @NonNull final FileDescriptor err,
@NonNull final String[] args, @NonNull final ShellCallback callback,
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index 3a84b1e..092dbc8 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -641,6 +641,10 @@
pw.println("Default overlays: " + TextUtils.join(";", mDefaultOverlays));
}
+ @NonNull String[] getDefaultOverlayPackages() {
+ return mDefaultOverlays;
+ }
+
List<String> getEnabledOverlayPackageNames(@NonNull final String targetPackageName,
final int userId) {
final List<OverlayInfo> overlays = mSettings.getOverlaysForTarget(targetPackageName,
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 21b6f12..497385f 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -22,21 +22,21 @@
import android.apex.ApexInfoList;
import android.apex.ApexSessionInfo;
import android.apex.IApexService;
-import android.content.BroadcastReceiver;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
import android.content.pm.PackageParser.PackageParserException;
+import android.os.HandlerThread;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
+import android.os.SystemClock;
+import android.sysprop.ApexProperties;
import android.util.Slog;
-import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.SystemService;
import java.io.File;
import java.io.PrintWriter;
@@ -45,75 +45,108 @@
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.CountDownLatch;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* ApexManager class handles communications with the apex service to perform operation and queries,
* as well as providing caching to avoid unnecessary calls to the service.
+ *
+ * @hide
*/
-class ApexManager {
- static final String TAG = "ApexManager";
- private final IApexService mApexService;
- private final Context mContext;
- private final Object mLock = new Object();
- @GuardedBy("mLock")
+public final class ApexManager extends SystemService {
+ private static final String TAG = "ApexManager";
+ private IApexService mApexService;
+
+ private final CountDownLatch mActivePackagesCacheLatch = new CountDownLatch(1);
private Map<String, PackageInfo> mActivePackagesCache;
- ApexManager(Context context) {
+ private final CountDownLatch mApexFilesCacheLatch = new CountDownLatch(1);
+ private ApexInfo[] mApexFiles;
+
+ public ApexManager(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onStart() {
try {
mApexService = IApexService.Stub.asInterface(
- ServiceManager.getServiceOrThrow("apexservice"));
+ ServiceManager.getServiceOrThrow("apexservice"));
} catch (ServiceNotFoundException e) {
throw new IllegalStateException("Required service apexservice not available");
}
- mContext = context;
+ publishLocalService(ApexManager.class, this);
+ HandlerThread oneShotThread = new HandlerThread("ApexManagerOneShotHandler");
+ oneShotThread.start();
+ oneShotThread.getThreadHandler().post(this::initSequence);
+ oneShotThread.quitSafely();
}
- void systemReady() {
- mContext.registerReceiver(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- onBootCompleted();
- mContext.unregisterReceiver(this);
- }
- }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
+ private void initSequence() {
+ populateApexFilesCache();
+ parseApexFiles();
}
- private void populateActivePackagesCacheIfNeeded() {
- synchronized (mLock) {
- if (mActivePackagesCache != null) {
- return;
- }
+ private void populateApexFilesCache() {
+ if (mApexFiles != null) {
+ return;
+ }
+ long startTimeMicros = SystemClock.currentTimeMicro();
+ Slog.i(TAG, "Starting to populate apex files cache");
+ try {
+ mApexFiles = mApexService.getActivePackages();
+ Slog.i(TAG, "IPC to apexd finished in " + (SystemClock.currentTimeMicro()
+ - startTimeMicros) + " μs");
+ } catch (RemoteException re) {
+ // TODO: make sure this error is propagated to system server.
+ Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString());
+ re.rethrowAsRuntimeException();
+ }
+ mApexFilesCacheLatch.countDown();
+ Slog.i(TAG, "Finished populating apex files cache in " + (SystemClock.currentTimeMicro()
+ - startTimeMicros) + " μs");
+ }
+
+ private void parseApexFiles() {
+ waitForLatch(mApexFilesCacheLatch);
+ if (mApexFiles == null) {
+ throw new IllegalStateException("mApexFiles must be populated");
+ }
+ long startTimeMicros = SystemClock.currentTimeMicro();
+ Slog.i(TAG, "Starting to parse apex files");
+ List<PackageInfo> list = new ArrayList<>();
+ // TODO: this can be parallelized.
+ for (ApexInfo ai : mApexFiles) {
try {
- List<PackageInfo> list = new ArrayList<>();
- final ApexInfo[] activePkgs = mApexService.getActivePackages();
- for (ApexInfo ai : activePkgs) {
- // If the device is using flattened APEX, don't report any APEX
- // packages since they won't be managed or updated by PackageManager.
- if ((new File(ai.packagePath)).isDirectory()) {
- break;
- }
- try {
- list.add(PackageParser.generatePackageInfoFromApex(
- new File(ai.packagePath), PackageManager.GET_META_DATA
- | PackageManager.GET_SIGNING_CERTIFICATES));
- } catch (PackageParserException pe) {
- throw new IllegalStateException("Unable to parse: " + ai, pe);
- }
+ // If the device is using flattened APEX, don't report any APEX
+ // packages since they won't be managed or updated by PackageManager.
+ if ((new File(ai.packagePath)).isDirectory()) {
+ break;
}
- mActivePackagesCache = list.stream().collect(
- Collectors.toMap(p -> p.packageName, Function.identity()));
- } catch (RemoteException re) {
- Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString());
- throw new RuntimeException(re);
+ list.add(PackageParser.generatePackageInfoFromApex(
+ new File(ai.packagePath), PackageManager.GET_META_DATA
+ | PackageManager.GET_SIGNING_CERTIFICATES));
+ } catch (PackageParserException pe) {
+ // TODO: make sure this error is propagated to system server.
+ throw new IllegalStateException("Unable to parse: " + ai, pe);
}
}
+ mActivePackagesCache = list.stream().collect(
+ Collectors.toMap(p -> p.packageName, Function.identity()));
+ mActivePackagesCacheLatch.countDown();
+ Slog.i(TAG, "Finished parsing apex files in " + (SystemClock.currentTimeMicro()
+ - startTimeMicros) + " μs");
}
/**
* Retrieves information about an active APEX package.
*
+ * <p>This method blocks caller thread until {@link #parseApexFiles()} succeeds. Note that in
+ * case {@link #parseApexFiles()}} throws an exception this method will never finish
+ * essentially putting device into a boot loop.
+ *
* @param packageName the package name to look for. Note that this is the package name reported
* in the APK container manifest (i.e. AndroidManifest.xml), which might
* differ from the one reported in the APEX manifest (i.e.
@@ -122,30 +155,43 @@
* is not found.
*/
@Nullable PackageInfo getActivePackage(String packageName) {
- populateActivePackagesCacheIfNeeded();
+ waitForLatch(mActivePackagesCacheLatch);
return mActivePackagesCache.get(packageName);
}
/**
* Retrieves information about all active APEX packages.
*
+ * <p>This method blocks caller thread until {@link #parseApexFiles()} succeeds. Note that in
+ * case {@link #parseApexFiles()}} throws an exception this method will never finish
+ * essentially putting device into a boot loop.
+ *
* @return a Collection of PackageInfo object, each one containing information about a different
* active package.
*/
Collection<PackageInfo> getActivePackages() {
- populateActivePackagesCacheIfNeeded();
+ waitForLatch(mActivePackagesCacheLatch);
return mActivePackagesCache.values();
}
/**
* Checks if {@code packageName} is an apex package.
*
+ * <p>This method blocks caller thread until {@link #populateApexFilesCache()} succeeds. Note
+ * that in case {@link #populateApexFilesCache()} throws an exception this method will never
+ * finish essentially putting device into a boot loop.
+ *
* @param packageName package to check.
* @return {@code true} if {@code packageName} is an apex package.
*/
boolean isApexPackage(String packageName) {
- populateActivePackagesCacheIfNeeded();
- return mActivePackagesCache.containsKey(packageName);
+ waitForLatch(mApexFilesCacheLatch);
+ for (ApexInfo ai : mApexFiles) {
+ if (ai.packageName.equals(packageName)) {
+ return true;
+ }
+ }
+ return false;
}
/**
@@ -237,11 +283,7 @@
* @return true if APEX packages can be managed on this device, false otherwise.
*/
boolean isApexSupported() {
- populateActivePackagesCacheIfNeeded();
- // There is no system-wide property available to check if APEX are flattened and hence can't
- // be updated. In absence of such property, we assume that if we didn't index APEX packages
- // since they were flattened, no APEX management should be possible.
- return !mActivePackagesCache.isEmpty();
+ return ApexProperties.updatable().orElse(false);
}
/**
@@ -277,6 +319,19 @@
}
/**
+ * Blocks current thread until {@code latch} has counted down to zero.
+ *
+ * @throws RuntimeException if thread was interrupted while waiting.
+ */
+ private void waitForLatch(CountDownLatch latch) {
+ try {
+ latch.await();
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Interrupted waiting for cache to be populated", e);
+ }
+ }
+
+ /**
* Dumps various state information to the provided {@link PrintWriter} object.
*
* @param pw the {@link PrintWriter} object to send information to.
@@ -289,7 +344,7 @@
ipw.println("Active APEX packages:");
ipw.increaseIndent();
try {
- populateActivePackagesCacheIfNeeded();
+ waitForLatch(mActivePackagesCacheLatch);
for (PackageInfo pi : mActivePackagesCache.values()) {
if (packageName != null && !packageName.equals(pi.packageName)) {
continue;
@@ -334,8 +389,4 @@
ipw.println("Couldn't communicate with apexd.");
}
}
-
- public void onBootCompleted() {
- populateActivePackagesCacheIfNeeded();
- }
}
diff --git a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
index 3a7919a..d6108b7c 100644
--- a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
+++ b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
@@ -24,6 +24,7 @@
import android.app.ActivityOptions;
import android.app.AppOpsManager;
import android.app.IApplicationThread;
+import android.app.admin.DevicePolicyEventLogger;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -37,6 +38,7 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
+import android.stats.devicepolicy.DevicePolicyEnums;
import android.text.TextUtils;
import com.android.internal.annotations.VisibleForTesting;
@@ -69,6 +71,11 @@
verifyCallingPackage(callingPackage);
+ DevicePolicyEventLogger
+ .createEvent(DevicePolicyEnums.CROSS_PROFILE_APPS_GET_TARGET_USER_PROFILES)
+ .setStrings(new String[] {callingPackage})
+ .write();
+
return getTargetUserProfilesUnchecked(
callingPackage, mInjector.getCallingUserId());
}
@@ -85,6 +92,11 @@
verifyCallingPackage(callingPackage);
+ DevicePolicyEventLogger
+ .createEvent(DevicePolicyEnums.CROSS_PROFILE_APPS_START_ACTIVITY_AS_USER)
+ .setStrings(new String[] {callingPackage})
+ .write();
+
final int callerUserId = mInjector.getCallingUserId();
final int callingUid = mInjector.getCallingUid();
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 74fb4b2..5f6e739 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -2050,6 +2050,13 @@
synchronized (mLock) {
assertCallerIsOwnerOrRootLocked();
+ if (isStagedAndInTerminalState()) {
+ // We keep the session in the database if it's in a finalized state. It will be
+ // removed by PackageInstallerService when the last update time is old enough.
+ // Also, in such cases cleanStageDir() has already been executed so no need to
+ // do it now.
+ return;
+ }
if (mCommitted && params.isStaged) {
synchronized (mLock) {
mDestroyed = true;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index e08af6f..c0f09d2 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -939,6 +939,7 @@
ComponentName mCustomResolverComponentName;
boolean mResolverReplaced = false;
+ boolean mOkToReplacePersistentPackages = false;
private final @Nullable ComponentName mIntentFilterVerifierComponent;
private final @Nullable IntentFilterVerifier<ActivityIntentInfo> mIntentFilterVerifier;
@@ -2374,6 +2375,8 @@
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
+ mApexManager = LocalServices.getService(ApexManager.class);
+
LockGuard.installLock(mPackages, LockGuard.INDEX_PACKAGES);
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "create package manager");
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
@@ -2470,7 +2473,6 @@
mProtectedPackages = new ProtectedPackages(mContext);
- mApexManager = new ApexManager(context);
synchronized (mInstallLock) {
// writer
synchronized (mPackages) {
@@ -17324,7 +17326,8 @@
+ " target SDK " + oldTargetSdk + " does.");
}
// Prevent persistent apps from being updated
- if ((oldPackage.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0) {
+ if (((oldPackage.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0)
+ && !mOkToReplacePersistentPackages) {
throw new PrepareFailure(PackageManager.INSTALL_FAILED_INVALID_APK,
"Package " + oldPackage.packageName + " is a persistent app. "
+ "Persistent apps are not updateable.");
@@ -18759,6 +18762,7 @@
boolean installedStateChanged = false;
if (deletedPs != null) {
if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
+ final SparseBooleanArray changedUsers = new SparseBooleanArray();
synchronized (mPackages) {
clearIntentFilterVerificationsLPw(deletedPs.name, UserHandle.USER_ALL);
clearDefaultBrowserIfNeeded(packageName);
@@ -18790,10 +18794,9 @@
}
}
}
+ clearPackagePreferredActivitiesLPw(
+ deletedPs.name, changedUsers, UserHandle.USER_ALL);
}
- final SparseBooleanArray changedUsers = new SparseBooleanArray();
- clearPackagePreferredActivitiesLPw(
- deletedPs.name, changedUsers, UserHandle.USER_ALL);
if (changedUsers.size() > 0) {
updateDefaultHomeNotLocked(changedUsers);
postPreferredActivityChangedBroadcast(UserHandle.USER_ALL);
@@ -21462,7 +21465,6 @@
storage.registerListener(mStorageListener);
mInstallerService.systemReady();
- mApexManager.systemReady();
mPackageDexOptimizer.systemReady();
getStorageManagerInternal().addExternalStoragePolicy(
@@ -21505,10 +21507,12 @@
mModuleInfoProvider.systemReady();
+ mOkToReplacePersistentPackages = true;
// Installer service might attempt to install some packages that have been staged for
// installation on reboot. Make sure this is the last component to be call since the
// installation might require other components to be ready.
mInstallerService.restoreAndApplyStagedSessionIfNeeded();
+ mOkToReplacePersistentPackages = false;
}
public void waitForAppDataPrepared() {
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 6154726..db2c742 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -70,6 +70,7 @@
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -588,6 +589,7 @@
// rollback sessions been applied.
List<RollbackData> enabling = new ArrayList<>();
List<RollbackData> restoreInProgress = new ArrayList<>();
+ Set<String> apexPackageNames = new HashSet<>();
synchronized (mLock) {
ensureRollbackDataLoadedLocked();
for (RollbackData data : mRollbacks) {
@@ -597,6 +599,12 @@
} else if (data.restoreUserDataInProgress) {
restoreInProgress.add(data);
}
+
+ for (PackageRollbackInfo info : data.info.getPackages()) {
+ if (info.isApex()) {
+ apexPackageNames.add(info.getPackageName());
+ }
+ }
}
}
}
@@ -634,6 +642,14 @@
}
}
+ for (String apexPackageName : apexPackageNames) {
+ // We will not recieve notifications when an apex is updated,
+ // so check now in case any rollbacks ought to be expired. The
+ // onPackagedReplace function is safe to call if the package
+ // hasn't actually been updated.
+ onPackageReplaced(apexPackageName);
+ }
+
mPackageHealthObserver.onBootCompleted();
});
}
diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
index d8f07fe..748a661 100644
--- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
+++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
@@ -16,6 +16,7 @@
package com.android.server.rollback;
+import android.annotation.Nullable;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -32,7 +33,6 @@
import android.os.HandlerThread;
import android.os.PowerManager;
import android.text.TextUtils;
-import android.util.Pair;
import android.util.Slog;
import android.util.StatsLog;
@@ -77,74 +77,50 @@
@Override
public int onHealthCheckFailed(VersionedPackage failedPackage) {
VersionedPackage moduleMetadataPackage = getModuleMetadataPackage();
- if (moduleMetadataPackage == null) {
- // Ignore failure, no mainline update available
- return PackageHealthObserverImpact.USER_IMPACT_NONE;
- }
- if (getAvailableRollback(mContext.getSystemService(RollbackManager.class),
- failedPackage, moduleMetadataPackage) == null) {
+ if (getAvailableRollback(mContext.getSystemService(RollbackManager.class), failedPackage)
+ == null) {
// Don't handle the notification, no rollbacks available for the package
return PackageHealthObserverImpact.USER_IMPACT_NONE;
+ } else {
+ // Rollback is available, we may get a callback into #execute
+ return PackageHealthObserverImpact.USER_IMPACT_MEDIUM;
}
- // Rollback is available, we may get a callback into #execute
- return PackageHealthObserverImpact.USER_IMPACT_MEDIUM;
}
@Override
public boolean execute(VersionedPackage failedPackage) {
- VersionedPackage moduleMetadataPackage = getModuleMetadataPackage();
- if (moduleMetadataPackage == null) {
- // Ignore failure, no mainline update available
- return false;
- }
-
RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
- Pair<RollbackInfo, Boolean> rollbackPair = getAvailableRollback(rollbackManager,
- failedPackage, moduleMetadataPackage);
- if (rollbackPair == null) {
+ VersionedPackage moduleMetadataPackage = getModuleMetadataPackage();
+ RollbackInfo rollback = getAvailableRollback(rollbackManager, failedPackage);
+
+ if (rollback == null) {
Slog.w(TAG, "Expected rollback but no valid rollback found for package: [ "
+ failedPackage.getPackageName() + "] with versionCode: ["
+ failedPackage.getVersionCode() + "]");
return false;
}
- RollbackInfo rollback = rollbackPair.first;
- // We only log mainline package rollbacks, so check if rollback contains the
- // module metadata provider, if it does, the rollback is a mainline rollback
- boolean hasModuleMetadataPackage = rollbackPair.second;
-
- if (hasModuleMetadataPackage) {
- StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED,
- StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE,
- moduleMetadataPackage.getPackageName(),
- moduleMetadataPackage.getVersionCode());
- }
+ logEvent(moduleMetadataPackage,
+ StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE);
LocalIntentReceiver rollbackReceiver = new LocalIntentReceiver((Intent result) -> {
- if (hasModuleMetadataPackage) {
- int status = result.getIntExtra(RollbackManager.EXTRA_STATUS,
- RollbackManager.STATUS_FAILURE);
- if (status == RollbackManager.STATUS_SUCCESS) {
- if (rollback.isStaged()) {
- int rollbackId = rollback.getRollbackId();
- BroadcastReceiver listener =
- listenForStagedSessionReady(rollbackManager, rollbackId,
- moduleMetadataPackage);
- handleStagedSessionChange(rollbackManager, rollbackId, listener,
- moduleMetadataPackage);
- } else {
- StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED,
- StatsLog
- .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS,
- moduleMetadataPackage.getPackageName(),
- moduleMetadataPackage.getVersionCode());
- }
+ int status = result.getIntExtra(RollbackManager.EXTRA_STATUS,
+ RollbackManager.STATUS_FAILURE);
+ if (status == RollbackManager.STATUS_SUCCESS) {
+ if (rollback.isStaged()) {
+ int rollbackId = rollback.getRollbackId();
+ BroadcastReceiver listener =
+ listenForStagedSessionReady(rollbackManager, rollbackId,
+ moduleMetadataPackage);
+ handleStagedSessionChange(rollbackManager, rollbackId, listener,
+ moduleMetadataPackage);
} else {
- StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED,
- StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE,
- moduleMetadataPackage.getPackageName(),
- moduleMetadataPackage.getVersionCode());
+ logEvent(moduleMetadataPackage,
+ StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS);
}
+ } else {
+ logEvent(moduleMetadataPackage,
+ StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE);
}
});
@@ -193,26 +169,17 @@
}
String moduleMetadataPackageName = getModuleMetadataPackageName();
- if (moduleMetadataPackageName == null) {
- // Only log mainline staged rollbacks
- return;
- }
// Use the version of the metadata package that was installed before
// we rolled back for logging purposes.
VersionedPackage moduleMetadataPackage = null;
for (PackageRollbackInfo packageRollback : rollback.getPackages()) {
- if (moduleMetadataPackageName.equals(packageRollback.getPackageName())) {
+ if (packageRollback.getPackageName().equals(moduleMetadataPackageName)) {
moduleMetadataPackage = packageRollback.getVersionRolledBackFrom();
break;
}
}
- if (moduleMetadataPackage == null) {
- // Only log mainline staged rollbacks
- return;
- }
-
int sessionId = rollback.getCommittedSessionId();
PackageInstaller.SessionInfo sessionInfo = packageInstaller.getSessionInfo(sessionId);
if (sessionInfo == null) {
@@ -220,42 +187,33 @@
return;
}
if (sessionInfo.isStagedSessionApplied()) {
- StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED,
- StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS,
- moduleMetadataPackage.getPackageName(),
- moduleMetadataPackage.getVersionCode());
+ logEvent(moduleMetadataPackage,
+ StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS);
} else if (sessionInfo.isStagedSessionReady()) {
// TODO: What do for staged session ready but not applied
} else {
- StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED,
- StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE,
- moduleMetadataPackage.getPackageName(),
- moduleMetadataPackage.getVersionCode());
+ logEvent(moduleMetadataPackage,
+ StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE);
}
}
- private Pair<RollbackInfo, Boolean> getAvailableRollback(RollbackManager rollbackManager,
- VersionedPackage failedPackage, VersionedPackage moduleMetadataPackage) {
+ private RollbackInfo getAvailableRollback(RollbackManager rollbackManager,
+ VersionedPackage failedPackage) {
for (RollbackInfo rollback : rollbackManager.getAvailableRollbacks()) {
- // We only rollback mainline packages, so check if rollback contains the
- // module metadata provider, if it does, the rollback is a mainline rollback
- boolean hasModuleMetadataPackage = false;
- boolean hasFailedPackage = false;
for (PackageRollbackInfo packageRollback : rollback.getPackages()) {
- hasModuleMetadataPackage |= packageRollback.getPackageName().equals(
- moduleMetadataPackage.getPackageName());
- hasFailedPackage |= packageRollback.getPackageName().equals(
+ boolean hasFailedPackage = packageRollback.getPackageName().equals(
failedPackage.getPackageName())
&& packageRollback.getVersionRolledBackFrom().getVersionCode()
== failedPackage.getVersionCode();
- }
- if (hasFailedPackage) {
- return new Pair<RollbackInfo, Boolean>(rollback, hasModuleMetadataPackage);
+ if (hasFailedPackage) {
+ return rollback;
+ }
}
}
return null;
}
+ @Nullable
private String getModuleMetadataPackageName() {
String packageName = mContext.getResources().getString(
R.string.config_defaultModuleMetadataProvider);
@@ -265,6 +223,7 @@
return packageName;
}
+ @Nullable
private VersionedPackage getModuleMetadataPackage() {
String packageName = getModuleMetadataPackageName();
if (packageName == null) {
@@ -311,18 +270,13 @@
if (sessionInfo.isStagedSessionReady()) {
mContext.unregisterReceiver(listener);
saveLastStagedRollbackId(rollbackId);
- StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED,
+ logEvent(moduleMetadataPackage,
StatsLog
- .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_BOOT_TRIGGERED,
- moduleMetadataPackage.getPackageName(),
- moduleMetadataPackage.getVersionCode());
+ .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_BOOT_TRIGGERED);
mContext.getSystemService(PowerManager.class).reboot("Rollback staged install");
} else if (sessionInfo.isStagedSessionFailed()) {
- StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED,
- StatsLog
- .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE,
- moduleMetadataPackage.getPackageName(),
- moduleMetadataPackage.getVersionCode());
+ logEvent(moduleMetadataPackage,
+ StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE);
mContext.unregisterReceiver(listener);
}
}
@@ -358,4 +312,12 @@
mLastStagedRollbackIdFile.delete();
return rollbackId;
}
+
+ private static void logEvent(@Nullable VersionedPackage moduleMetadataPackage, int type) {
+ Slog.i(TAG, "Watchdog event occurred of type: " + type);
+ if (moduleMetadataPackage != null) {
+ StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED, type,
+ moduleMetadataPackage.getPackageName(), moduleMetadataPackage.getVersionCode());
+ }
+ }
}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index b9b5aae..7734d6b 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -77,7 +77,8 @@
void onCameraLaunchGestureDetected(int source);
void topAppWindowChanged(int displayId, boolean menuVisible);
void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis, int dockedStackVis,
- int mask, Rect fullscreenBounds, Rect dockedBounds, String cause);
+ int mask, Rect fullscreenBounds, Rect dockedBounds, boolean isNavbarColorManagedByIme,
+ String cause);
void toggleSplitScreen();
void appTransitionFinished(int displayId);
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index a5656c3..b2d7084 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -262,9 +262,10 @@
@Override
public void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis,
int dockedStackVis, int mask, Rect fullscreenBounds, Rect dockedBounds,
- String cause) {
+ boolean isNavbarColorManagedByIme, String cause) {
StatusBarManagerService.this.setSystemUiVisibility(displayId, vis, fullscreenStackVis,
- dockedStackVis, mask, fullscreenBounds, dockedBounds, cause);
+ dockedStackVis, mask, fullscreenBounds, dockedBounds, isNavbarColorManagedByIme,
+ cause);
}
@Override
@@ -872,11 +873,13 @@
public void setSystemUiVisibility(int displayId, int vis, int mask, String cause) {
final UiState state = getUiState(displayId);
setSystemUiVisibility(displayId, vis, 0, 0, mask,
- state.mFullscreenStackBounds, state.mDockedStackBounds, cause);
+ state.mFullscreenStackBounds, state.mDockedStackBounds,
+ state.mNavbarColorManagedByIme, cause);
}
private void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis,
- int dockedStackVis, int mask, Rect fullscreenBounds, Rect dockedBounds, String cause) {
+ int dockedStackVis, int mask, Rect fullscreenBounds, Rect dockedBounds,
+ boolean isNavbarColorManagedByIme, String cause) {
// also allows calls from window manager which is in this process.
enforceStatusBarService();
@@ -884,7 +887,7 @@
synchronized (mLock) {
updateUiVisibilityLocked(displayId, vis, fullscreenStackVis, dockedStackVis, mask,
- fullscreenBounds, dockedBounds);
+ fullscreenBounds, dockedBounds, isNavbarColorManagedByIme);
disableLocked(
displayId,
mCurrentUserId,
@@ -896,17 +899,19 @@
private void updateUiVisibilityLocked(final int displayId, final int vis,
final int fullscreenStackVis, final int dockedStackVis, final int mask,
- final Rect fullscreenBounds, final Rect dockedBounds) {
+ final Rect fullscreenBounds, final Rect dockedBounds,
+ final boolean isNavbarColorManagedByIme) {
final UiState state = getUiState(displayId);
if (!state.systemUiStateEquals(vis, fullscreenStackVis, dockedStackVis,
- fullscreenBounds, dockedBounds)) {
+ fullscreenBounds, dockedBounds, isNavbarColorManagedByIme)) {
state.setSystemUiState(vis, fullscreenStackVis, dockedStackVis, fullscreenBounds,
- dockedBounds);
+ dockedBounds, isNavbarColorManagedByIme);
mHandler.post(() -> {
if (mBar != null) {
try {
mBar.setSystemUiVisibility(displayId, vis, fullscreenStackVis,
- dockedStackVis, mask, fullscreenBounds, dockedBounds);
+ dockedStackVis, mask, fullscreenBounds, dockedBounds,
+ isNavbarColorManagedByIme);
} catch (RemoteException ex) {
Log.w(TAG, "Can not get StatusBar!");
}
@@ -945,6 +950,7 @@
private int mImeBackDisposition = 0;
private boolean mShowImeSwitcher = false;
private IBinder mImeToken = null;
+ private boolean mNavbarColorManagedByIme = false;
private int getDisabled1() {
return mDisabled1;
@@ -972,21 +978,25 @@
}
private void setSystemUiState(final int vis, final int fullscreenStackVis,
- final int dockedStackVis, final Rect fullscreenBounds, final Rect dockedBounds) {
+ final int dockedStackVis, final Rect fullscreenBounds, final Rect dockedBounds,
+ final boolean navbarColorManagedByIme) {
mSystemUiVisibility = vis;
mFullscreenStackSysUiVisibility = fullscreenStackVis;
mDockedStackSysUiVisibility = dockedStackVis;
mFullscreenStackBounds.set(fullscreenBounds);
mDockedStackBounds.set(dockedBounds);
+ mNavbarColorManagedByIme = navbarColorManagedByIme;
}
private boolean systemUiStateEquals(final int vis, final int fullscreenStackVis,
- final int dockedStackVis, final Rect fullscreenBounds, final Rect dockedBounds) {
+ final int dockedStackVis, final Rect fullscreenBounds, final Rect dockedBounds,
+ final boolean navbarColorManagedByIme) {
return mSystemUiVisibility == vis
&& mFullscreenStackSysUiVisibility == fullscreenStackVis
&& mDockedStackSysUiVisibility == dockedStackVis
&& mFullscreenStackBounds.equals(fullscreenBounds)
- && mDockedStackBounds.equals(dockedBounds);
+ && mDockedStackBounds.equals(dockedBounds)
+ && mNavbarColorManagedByIme == navbarColorManagedByIme;
}
private void setImeWindowState(final int vis, final int backDisposition,
@@ -1051,7 +1061,8 @@
state.mImeBackDisposition, state.mShowImeSwitcher,
gatherDisableActionsLocked(mCurrentUserId, 2),
state.mFullscreenStackSysUiVisibility, state.mDockedStackSysUiVisibility,
- state.mImeToken, state.mFullscreenStackBounds, state.mDockedStackBounds);
+ state.mImeToken, state.mFullscreenStackBounds, state.mDockedStackBounds,
+ state.mNavbarColorManagedByIme);
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 4ed07c3..8a834c8 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -5438,7 +5438,7 @@
if (isAttached()) {
getDisplay().positionChildAtBottom(this);
}
- if (!isActivityTypeHome() || getDisplay().isRemoved()) {
+ if (!isActivityTypeHome() || !isAttached()) {
remove();
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 4ef8753..6976aa9 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1038,6 +1038,12 @@
}
}
}
+ // don't abort if the callingUid has SYSTEM_ALERT_WINDOW permission
+ if (mService.hasSystemAlertWindowPermission(callingUid, callingPid, callingPackage)) {
+ Slog.w(TAG, "Background activity start for " + callingPackage
+ + " allowed because SYSTEM_ALERT_WINDOW permission is granted.");
+ return false;
+ }
// anything that has fallen through would currently be aborted
Slog.w(TAG, "Background activity start [callingPackage: " + callingPackage
+ "; callingUid: " + callingUid
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index a55ee5f..4a6aa33 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -108,12 +108,10 @@
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_VISIBILITY;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_ACTIVITY_ID;
import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_CONTENT;
import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_DATA;
import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_RECEIVER_EXTRAS;
import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_STRUCTURE;
-import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_TASK_ID;
import static com.android.server.wm.ActivityTaskManagerService.H.REPORT_TIME_TRACKER_MSG;
import static com.android.server.wm.ActivityTaskManagerService.UiHandler.DISMISS_DIALOG_UI_MSG;
import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE;
@@ -136,6 +134,7 @@
import android.app.ActivityThread;
import android.app.AlertDialog;
import android.app.AppGlobals;
+import android.app.AppOpsManager;
import android.app.Dialog;
import android.app.IActivityController;
import android.app.IActivityTaskManager;
@@ -216,7 +215,6 @@
import android.util.ArrayMap;
import android.util.EventLog;
import android.util.Log;
-import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
@@ -875,6 +873,16 @@
return getUserManager().hasUserRestriction(restriction, userId);
}
+ boolean hasSystemAlertWindowPermission(int callingUid, int callingPid, String callingPackage) {
+ final int mode = getAppOpsService().noteOperation(AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
+ callingUid, callingPackage);
+ if (mode == AppOpsManager.MODE_DEFAULT) {
+ return checkPermission(Manifest.permission.SYSTEM_ALERT_WINDOW, callingPid, callingUid)
+ == PERMISSION_GRANTED;
+ }
+ return mode == AppOpsManager.MODE_ALLOWED;
+ }
+
protected RecentTasks createRecentTasks() {
return new RecentTasks(this, mStackSupervisor);
}
@@ -5810,10 +5818,8 @@
*/
Intent getSecondaryHomeIntent(String preferredPackage) {
final Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
- final boolean useSystemProvidedLauncher = mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_useSystemProvidedLauncherForSecondary);
- if (preferredPackage == null || useSystemProvidedLauncher) {
- // Using the component stored in config if no package name or forced.
+ if (preferredPackage == null) {
+ // Using the component stored in config if no package name.
final String secondaryHomeComponent = mContext.getResources().getString(
com.android.internal.R.string.config_secondaryHomeComponent);
intent.setComponent(ComponentName.unflattenFromString(secondaryHomeComponent));
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 2321898..8785b01 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -78,6 +78,7 @@
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
import static com.android.server.wm.WindowManagerService.logWithStack;
+import static com.android.server.wm.WindowState.LEGACY_POLICY_VISIBILITY;
import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM;
@@ -638,8 +639,8 @@
// If we are being set visible, and the starting window is not yet displayed,
// then make sure it doesn't get displayed.
if (startingWindow != null && !startingWindow.isDrawnLw()) {
- startingWindow.mPolicyVisibility = false;
- startingWindow.mPolicyVisibilityAfterAnim = false;
+ startingWindow.clearPolicyVisibilityFlag(LEGACY_POLICY_VISIBILITY);
+ startingWindow.mLegacyPolicyVisibilityAfterAnim = false;
}
// We are becoming visible, so better freeze the screen with the windows that are
@@ -1932,7 +1933,7 @@
+ ", isAnimationSet=" + isSelfAnimating());
if (!w.isDrawnLw()) {
Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurfaceController
- + " pv=" + w.mPolicyVisibility
+ + " pv=" + w.isVisibleByPolicy()
+ " mDrawState=" + winAnimator.drawStateToString()
+ " ph=" + w.isParentWindowHidden() + " th=" + hiddenRequested
+ " a=" + isSelfAnimating());
@@ -2432,14 +2433,19 @@
}
}
- private boolean shouldAnimate(int transit) {
+
+ @VisibleForTesting
+ boolean shouldAnimate(int transit) {
final boolean isSplitScreenPrimary =
getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
final boolean allowSplitScreenPrimaryAnimation = transit != TRANSIT_WALLPAPER_OPEN;
- // Don't animate when the task runs recents animation.
+ // Don't animate while the task runs recents animation but only if we are in the mode
+ // where we cancel with deferred screenshot, which means that the controller has
+ // transformed the task.
final RecentsAnimationController controller = mWmService.getRecentsAnimationController();
- if (controller != null && controller.isAnimatingTask(getTask())) {
+ if (controller != null && controller.isAnimatingTask(getTask())
+ && controller.shouldCancelWithDeferredScreenshot()) {
return false;
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 41292d2..3f783f6 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -4562,7 +4562,7 @@
token2.mOwnerCanManageAppTokens) ? -1 : 1;
private final Predicate<WindowState> mGetOrientingWindow = w -> {
- if (!w.isVisibleLw() || !w.mPolicyVisibilityAfterAnim) {
+ if (!w.isVisibleLw() || !w.mLegacyPolicyVisibilityAfterAnim) {
return false;
}
final int req = w.mAttrs.screenOrientation;
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 3bb3653..32d0b32 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -112,7 +112,6 @@
import android.annotation.Nullable;
import android.annotation.Px;
import android.app.ActivityManager;
-import android.app.ActivityManagerInternal;
import android.app.ActivityThread;
import android.app.LoadedApk;
import android.app.ResourcesManager;
@@ -133,6 +132,7 @@
import android.os.SystemProperties;
import android.os.UserHandle;
import android.util.ArraySet;
+import android.util.Pair;
import android.util.PrintWriterPrinter;
import android.util.Slog;
import android.view.DisplayCutout;
@@ -3113,7 +3113,9 @@
WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME, mNonDockedStackBounds);
mService.getStackBounds(
WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, mDockedStackBounds);
- final int visibility = updateSystemBarsLw(win, mLastSystemUiFlags, tmpVisibility);
+ final Pair<Integer, Boolean> result =
+ updateSystemBarsLw(win, mLastSystemUiFlags, tmpVisibility);
+ final int visibility = result.first;
final int diff = visibility ^ mLastSystemUiFlags;
final int fullscreenDiff = fullscreenVisibility ^ mLastFullscreenStackSysUiFlags;
final int dockedDiff = dockedVisibility ^ mLastDockedStackSysUiFlags;
@@ -3133,13 +3135,14 @@
mLastDockedStackBounds.set(mDockedStackBounds);
final Rect fullscreenStackBounds = new Rect(mNonDockedStackBounds);
final Rect dockedStackBounds = new Rect(mDockedStackBounds);
+ final boolean isNavbarColorManagedByIme = result.second;
mHandler.post(() -> {
StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
if (statusBar != null) {
final int displayId = getDisplayId();
statusBar.setSystemUiVisibility(displayId, visibility, fullscreenVisibility,
dockedVisibility, 0xffffffff, fullscreenStackBounds,
- dockedStackBounds, win.toString());
+ dockedStackBounds, isNavbarColorManagedByIme, win.toString());
statusBar.topAppWindowChanged(displayId, needsMenu);
}
});
@@ -3222,7 +3225,7 @@
return vis;
}
- private int updateSystemBarsLw(WindowState win, int oldVis, int vis) {
+ private Pair<Integer, Boolean> updateSystemBarsLw(WindowState win, int oldVis, int vis) {
final boolean dockedStackVisible =
mDisplayContent.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
final boolean freeformStackVisible =
@@ -3355,8 +3358,11 @@
vis = updateLightNavigationBarLw(vis, mTopFullscreenOpaqueWindowState,
mTopFullscreenOpaqueOrDimmingWindowState,
mDisplayContent.mInputMethodWindow, navColorWin);
+ // Navbar color is controlled by the IME.
+ final boolean isManagedByIme =
+ navColorWin != null && navColorWin == mDisplayContent.mInputMethodWindow;
- return vis;
+ return Pair.create(vis, isManagedByIme);
}
private boolean drawsBarBackground(int vis, WindowState win, BarController controller,
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index f67b11b..402ec59 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -29,12 +29,11 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.util.proto.ProtoOutputStream;
+import android.view.InsetsSource;
+import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
-import android.view.InsetsSource;
-import android.view.InsetsSourceControl;
-import android.view.ViewRootImpl;
import com.android.internal.util.function.TriConsumer;
import com.android.internal.util.function.pooled.PooledLambda;
@@ -142,7 +141,7 @@
mStateController.notifyControlChanged(mControllingWin);
}
}
- setServerVisible(mWin.wouldBeVisibleIfPolicyIgnored() && mWin.mPolicyVisibility
+ setServerVisible(mWin.wouldBeVisibleIfPolicyIgnored() && mWin.isVisibleByPolicy()
&& !mWin.mGivenInsetsPending);
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 78c5dbd..75a8dd5 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -481,7 +481,15 @@
public abstract int getTopFocusedDisplayId();
/**
- * Checks whether this display should support showing system decorations.
+ * Checks if this display is configured and allowed to show system decorations.
*/
public abstract boolean shouldShowSystemDecorOnDisplay(int displayId);
+
+ /**
+ * Indicates that the display should show IME.
+ *
+ * @param displayId The id of the display.
+ * @return {@code true} if the display should show IME when an input field become focused on it.
+ */
+ public abstract boolean shouldShowIme(int displayId);
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index dae29b2..4f849cd 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -35,6 +35,7 @@
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
+import static android.view.Display.TYPE_VIRTUAL;
import static android.view.WindowManager.DOCKED_INVALID;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
@@ -163,6 +164,7 @@
import android.os.PowerManager.ServiceType;
import android.os.PowerManagerInternal;
import android.os.PowerSaveState;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
@@ -5298,7 +5300,7 @@
": removed=" + win.mRemoved + " visible=" + win.isVisibleLw() +
" mHasSurface=" + win.mHasSurface +
" drawState=" + win.mWinAnimator.mDrawState);
- if (win.mRemoved || !win.mHasSurface || !win.mPolicyVisibility) {
+ if (win.mRemoved || !win.mHasSurface || !win.isVisibleByPolicy()) {
// Window has been removed or hidden; no draw will now happen, so stop waiting.
if (DEBUG_SCREEN_ON) Slog.w(TAG_WM, "Aborted waiting for drawn: " + win);
mWaitingForDrawn.remove(win);
@@ -6871,10 +6873,21 @@
+ "not exist: " + displayId);
return false;
}
+ final Display display = displayContent.getDisplay();
+ if (isUntrustedVirtualDisplay(display)) {
+ return false;
+ }
return displayContent.supportsSystemDecorations();
}
}
+ /**
+ * @return {@code true} if the display is non-system created virtual display.
+ */
+ private static boolean isUntrustedVirtualDisplay(Display display) {
+ return display.getType() == TYPE_VIRTUAL && display.getOwnerUid() != Process.SYSTEM_UID;
+ }
+
@Override
public void setShouldShowSystemDecors(int displayId, boolean shouldShow) {
if (!checkCallingPermission(INTERNAL_SYSTEM_WINDOW, "setShouldShowSystemDecors()")) {
@@ -6908,7 +6921,12 @@
+ displayId);
return false;
}
- return mDisplayWindowSettings.shouldShowImeLocked(displayContent);
+ final Display display = displayContent.getDisplay();
+ if (isUntrustedVirtualDisplay(display)) {
+ return false;
+ }
+ return mDisplayWindowSettings.shouldShowImeLocked(displayContent)
+ || mForceDesktopModeOnExternalDisplays;
}
}
@@ -7352,6 +7370,14 @@
return WindowManagerService.this.shouldShowSystemDecors(displayId);
}
}
+
+ @Override
+ public boolean shouldShowIme(int displayId) {
+ synchronized (mGlobalLock) {
+ final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
+ return mDisplayWindowSettings.shouldShowImeLocked(displayContent);
+ }
+ }
}
void registerAppFreezeListener(AppFreezeListener listener) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index e39cd56..8123182 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -251,18 +251,33 @@
int mSeq;
int mViewVisibility;
int mSystemUiVisibility;
+
/**
- * The visibility of the window based on policy like {@link WindowManagerPolicy}.
+ * The visibility flag of the window based on policy like {@link WindowManagerPolicy}.
* Normally set by calling {@link #showLw} and {@link #hideLw}.
+ *
+ * TODO: b/131253938 This will eventually be split into individual visibility policy flags.
*/
- boolean mPolicyVisibility = true;
+ static final int LEGACY_POLICY_VISIBILITY = 1;
/**
- * What {@link #mPolicyVisibility} should be set to after a transition animation.
- * For example, {@link #mPolicyVisibility} might true during an exit animation to hide it and
- * then set to the value of {@link #mPolicyVisibilityAfterAnim} which is false after the exit
- * animation is done.
+ * The visibility flag that determines whether this window is visible for the current user.
*/
- boolean mPolicyVisibilityAfterAnim = true;
+ private static final int VISIBLE_FOR_USER = 1 << 1;
+ private static final int POLICY_VISIBILITY_ALL = VISIBLE_FOR_USER | LEGACY_POLICY_VISIBILITY;
+ /**
+ * The Bitwise-or of flags that contribute to visibility of the WindowState
+ */
+ private int mPolicyVisibility = POLICY_VISIBILITY_ALL;
+
+ /**
+ * Whether {@link #LEGACY_POLICY_VISIBILITY} flag should be set after a transition animation.
+ * For example, {@link #LEGACY_POLICY_VISIBILITY} might be set during an exit animation to hide
+ * it and then unset when the value of {@link #mLegacyPolicyVisibilityAfterAnim} is false
+ * after the exit animation is done.
+ *
+ * TODO: b/131253938 Determine whether this can be changed to use a visibility flag instead.
+ */
+ boolean mLegacyPolicyVisibilityAfterAnim = true;
// overlay window is hidden because the owning app is suspended
private boolean mHiddenWhileSuspended;
private boolean mAppOpVisibility = true;
@@ -1414,13 +1429,33 @@
@Override
boolean isVisible() {
- return wouldBeVisibleIfPolicyIgnored() && mPolicyVisibility
+ return wouldBeVisibleIfPolicyIgnored() && isVisibleByPolicy()
// If we don't have a provider, this window isn't used as a window generating
// insets, so nobody can hide it over the inset APIs.
&& (mInsetProvider == null || mInsetProvider.isClientVisible());
}
/**
+ * Ensures that all the policy visibility bits are set.
+ * @return {@code true} if all flags about visiblity are set
+ */
+ boolean isVisibleByPolicy() {
+ return (mPolicyVisibility & POLICY_VISIBILITY_ALL) == POLICY_VISIBILITY_ALL;
+ }
+
+ void clearPolicyVisibilityFlag(int policyVisibilityFlag) {
+ mPolicyVisibility &= ~policyVisibilityFlag;
+ }
+
+ void setPolicyVisibilityFlag(int policyVisibilityFlag) {
+ mPolicyVisibility |= policyVisibilityFlag;
+ }
+
+ private boolean isLegacyPolicyVisibility() {
+ return (mPolicyVisibility & LEGACY_POLICY_VISIBILITY) != 0;
+ }
+
+ /**
* @return {@code true} if the window would be visible if we'd ignore policy visibility,
* {@code false} otherwise.
*/
@@ -1470,7 +1505,7 @@
boolean isVisibleOrAdding() {
final AppWindowToken atoken = mAppToken;
return (mHasSurface || (!mRelayoutCalled && mViewVisibility == View.VISIBLE))
- && mPolicyVisibility && !isParentWindowHidden()
+ && isVisibleByPolicy() && !isParentWindowHidden()
&& (atoken == null || !atoken.hiddenRequested)
&& !mAnimatingExit && !mDestroying;
}
@@ -1481,7 +1516,7 @@
* being visible.
*/
boolean isOnScreen() {
- if (!mHasSurface || mDestroying || !mPolicyVisibility) {
+ if (!mHasSurface || mDestroying || !isVisibleByPolicy()) {
return false;
}
final AppWindowToken atoken = mAppToken;
@@ -1522,7 +1557,7 @@
}
final boolean parentAndClientVisible = !isParentWindowHidden()
&& mViewVisibility == View.VISIBLE && !mToken.isHidden();
- return mHasSurface && mPolicyVisibility && !mDestroying
+ return mHasSurface && isVisibleByPolicy() && !mDestroying
&& (parentAndClientVisible || isAnimating());
}
@@ -1551,7 +1586,7 @@
@Override
public boolean isDisplayedLw() {
final AppWindowToken atoken = mAppToken;
- return isDrawnLw() && mPolicyVisibility
+ return isDrawnLw() && isVisibleByPolicy()
&& ((!isParentWindowHidden() && (atoken == null || !atoken.hiddenRequested))
|| isAnimating());
}
@@ -2057,8 +2092,8 @@
Slog.i(TAG_WM, " mSurfaceController=" + mWinAnimator.mSurfaceController
+ " relayoutCalled=" + mRelayoutCalled
+ " viewVis=" + mViewVisibility
- + " policyVis=" + mPolicyVisibility
- + " policyVisAfterAnim=" + mPolicyVisibilityAfterAnim
+ + " policyVis=" + isVisibleByPolicy()
+ + " policyVisAfterAnim=" + mLegacyPolicyVisibilityAfterAnim
+ " parentHidden=" + isParentWindowHidden()
+ " exiting=" + mAnimatingExit + " destroying=" + mDestroying);
if (mAppToken != null) {
@@ -2192,7 +2227,9 @@
if (isHiddenFromUserLocked()) {
if (DEBUG_VISIBILITY) Slog.w(TAG_WM, "user changing, hiding " + this
+ ", attrs=" + mAttrs.type + ", belonging to " + mOwnerUid);
- hideLw(false);
+ clearPolicyVisibilityFlag(VISIBLE_FOR_USER);
+ } else {
+ setPolicyVisibilityFlag(VISIBLE_FOR_USER);
}
}
@@ -2284,13 +2321,17 @@
}
void checkPolicyVisibilityChange() {
- if (mPolicyVisibility != mPolicyVisibilityAfterAnim) {
+ if (isLegacyPolicyVisibility() != mLegacyPolicyVisibilityAfterAnim) {
if (DEBUG_VISIBILITY) {
Slog.v(TAG, "Policy visibility changing after anim in " +
- mWinAnimator + ": " + mPolicyVisibilityAfterAnim);
+ mWinAnimator + ": " + mLegacyPolicyVisibilityAfterAnim);
}
- mPolicyVisibility = mPolicyVisibilityAfterAnim;
- if (!mPolicyVisibility) {
+ if (mLegacyPolicyVisibilityAfterAnim) {
+ setPolicyVisibilityFlag(LEGACY_POLICY_VISIBILITY);
+ } else {
+ clearPolicyVisibilityFlag(LEGACY_POLICY_VISIBILITY);
+ }
+ if (!isVisibleByPolicy()) {
mWinAnimator.hide("checkPolicyVisibilityChange");
if (isFocused()) {
if (DEBUG_FOCUS_LIGHT) Slog.i(TAG,
@@ -2531,7 +2572,7 @@
}
boolean showLw(boolean doAnimation, boolean requestAnim) {
- if (mPolicyVisibility && mPolicyVisibilityAfterAnim) {
+ if (isLegacyPolicyVisibility() && mLegacyPolicyVisibilityAfterAnim) {
// Already showing.
return false;
}
@@ -2558,18 +2599,18 @@
if (DEBUG_VISIBILITY) Slog.v(TAG, "Policy visibility true: " + this);
if (doAnimation) {
if (DEBUG_VISIBILITY) Slog.v(TAG, "doAnimation: mPolicyVisibility="
- + mPolicyVisibility + " animating=" + isAnimating());
+ + isLegacyPolicyVisibility() + " animating=" + isAnimating());
if (!mToken.okToAnimate()) {
doAnimation = false;
- } else if (mPolicyVisibility && !isAnimating()) {
+ } else if (isLegacyPolicyVisibility() && !isAnimating()) {
// Check for the case where we are currently visible and
// not animating; we do not want to do animation at such a
// point to become visible when we already are.
doAnimation = false;
}
}
- mPolicyVisibility = true;
- mPolicyVisibilityAfterAnim = true;
+ setPolicyVisibilityFlag(LEGACY_POLICY_VISIBILITY);
+ mLegacyPolicyVisibilityAfterAnim = true;
if (doAnimation) {
mWinAnimator.applyAnimationLocked(TRANSIT_ENTER, true);
}
@@ -2593,7 +2634,8 @@
doAnimation = false;
}
}
- boolean current = doAnimation ? mPolicyVisibilityAfterAnim : mPolicyVisibility;
+ boolean current =
+ doAnimation ? mLegacyPolicyVisibilityAfterAnim : isLegacyPolicyVisibility();
if (!current) {
// Already hiding.
return false;
@@ -2604,11 +2646,11 @@
doAnimation = false;
}
}
- mPolicyVisibilityAfterAnim = false;
+ mLegacyPolicyVisibilityAfterAnim = false;
final boolean isFocused = isFocused();
if (!doAnimation) {
if (DEBUG_VISIBILITY) Slog.v(TAG, "Policy visibility false: " + this);
- mPolicyVisibility = false;
+ clearPolicyVisibilityFlag(LEGACY_POLICY_VISIBILITY);
// Window is no longer visible -- make sure if we were waiting
// for it to be displayed before enabling the display, that
// we allow the display to be enabled now.
@@ -3443,11 +3485,11 @@
pw.println(prefix + "mSeq=" + mSeq
+ " mSystemUiVisibility=0x" + Integer.toHexString(mSystemUiVisibility));
}
- if (!mPolicyVisibility || !mPolicyVisibilityAfterAnim || !mAppOpVisibility
+ if (!isVisibleByPolicy() || !mLegacyPolicyVisibilityAfterAnim || !mAppOpVisibility
|| isParentWindowHidden() || mPermanentlyHidden || mForceHideNonSystemOverlayWindow
|| mHiddenWhileSuspended) {
- pw.println(prefix + "mPolicyVisibility=" + mPolicyVisibility
- + " mPolicyVisibilityAfterAnim=" + mPolicyVisibilityAfterAnim
+ pw.println(prefix + "mPolicyVisibility=" + isVisibleByPolicy()
+ + " mLegacyPolicyVisibilityAfterAnim=" + mLegacyPolicyVisibilityAfterAnim
+ " mAppOpVisibility=" + mAppOpVisibility
+ " parentHidden=" + isParentWindowHidden()
+ " mPermanentlyHidden=" + mPermanentlyHidden
@@ -3904,7 +3946,7 @@
+ ": mDrawState=" + mWinAnimator.drawStateToString()
+ " readyForDisplay=" + isReadyForDisplay()
+ " starting=" + (mAttrs.type == TYPE_APPLICATION_STARTING)
- + " during animation: policyVis=" + mPolicyVisibility
+ + " during animation: policyVis=" + isVisibleByPolicy()
+ " parentHidden=" + isParentWindowHidden()
+ " tok.hiddenRequested="
+ (mAppToken != null && mAppToken.hiddenRequested)
@@ -4313,7 +4355,7 @@
+ ", animating=" + isAnimating());
if (!isDrawnLw()) {
Slog.v(TAG, "Not displayed: s=" + mWinAnimator.mSurfaceController
- + " pv=" + mPolicyVisibility
+ + " pv=" + isVisibleByPolicy()
+ " mDrawState=" + mWinAnimator.mDrawState
+ " ph=" + isParentWindowHidden()
+ " th=" + (mAppToken != null ? mAppToken.hiddenRequested : false)
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 780d471..20e1ac6 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -256,7 +256,7 @@
mWin.checkPolicyVisibilityChange();
final DisplayContent displayContent = mWin.getDisplayContent();
- if (mAttrType == LayoutParams.TYPE_STATUS_BAR && mWin.mPolicyVisibility) {
+ if (mAttrType == LayoutParams.TYPE_STATUS_BAR && mWin.isVisibleByPolicy()) {
// Upon completion of a not-visible to visible status bar animation a relayout is
// required.
if (displayContent != null) {
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 7bc6776..4d37f1a 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -1860,13 +1860,14 @@
* Fail if the main interface fails to initialize
*/
if (gnssHal == nullptr) {
- ALOGE("Unable to Initialize GNSS HAL\n");
+ ALOGE("Unable to initialize GNSS HAL.");
return JNI_FALSE;
}
- sp<IGnssCallback> gnssCbIface = new GnssCallback();
-
Return<bool> result = false;
+
+ // Set top level IGnss.hal callback.
+ sp<IGnssCallback> gnssCbIface = new GnssCallback();
if (gnssHal_V2_0 != nullptr) {
result = gnssHal_V2_0->setCallback_2_0(gnssCbIface);
} else if (gnssHal_V1_1 != nullptr) {
@@ -1876,62 +1877,89 @@
}
if (!result.isOk() || !result) {
- ALOGE("SetCallback for Gnss Interface fails\n");
+ ALOGE("SetCallback for IGnss interface failed.");
return JNI_FALSE;
}
- sp<IGnssXtraCallback> gnssXtraCbIface = new GnssXtraCallback();
+ // Set IGnssXtra.hal callback.
if (gnssXtraIface == nullptr) {
- ALOGI("Unable to initialize GNSS Xtra interface\n");
+ ALOGI("Unable to initialize IGnssXtra interface.");
} else {
+ sp<IGnssXtraCallback> gnssXtraCbIface = new GnssXtraCallback();
result = gnssXtraIface->setCallback(gnssXtraCbIface);
if (!result.isOk() || !result) {
gnssXtraIface = nullptr;
- ALOGI("SetCallback for Gnss Xtra Interface fails\n");
+ ALOGI("SetCallback for IGnssXtra interface failed.");
}
}
+ // Set IAGnss.hal callback.
+ Return<void> agnssStatus;
if (agnssIface_V2_0 != nullptr) {
sp<IAGnssCallback_V2_0> aGnssCbIface = new AGnssCallback_V2_0();
- agnssIface_V2_0->setCallback(aGnssCbIface);
+ agnssStatus = agnssIface_V2_0->setCallback(aGnssCbIface);
} else if (agnssIface != nullptr) {
sp<IAGnssCallback_V1_0> aGnssCbIface = new AGnssCallback_V1_0();
- agnssIface->setCallback(aGnssCbIface);
+ agnssStatus = agnssIface->setCallback(aGnssCbIface);
} else {
- ALOGI("Unable to initialize AGnss interface\n");
+ ALOGI("Unable to initialize IAGnss interface.");
}
+ if (!agnssStatus.isOk()) {
+ ALOGI("SetCallback for IAGnss interface failed.");
+ }
+
+ // Set IGnssGeofencing.hal callback.
sp<IGnssGeofenceCallback> gnssGeofencingCbIface = new GnssGeofenceCallback();
if (gnssGeofencingIface != nullptr) {
- gnssGeofencingIface->setCallback(gnssGeofencingCbIface);
+ auto status = gnssGeofencingIface->setCallback(gnssGeofencingCbIface);
+ if (!status.isOk()) {
+ ALOGI("SetCallback for IGnssGeofencing interface failed.");
+ }
} else {
- ALOGI("Unable to initialize GNSS Geofencing interface\n");
+ ALOGI("Unable to initialize IGnssGeofencing interface.");
}
+ // Set IGnssNi.hal callback.
sp<IGnssNiCallback> gnssNiCbIface = new GnssNiCallback();
if (gnssNiIface != nullptr) {
- gnssNiIface->setCallback(gnssNiCbIface);
+ auto status = gnssNiIface->setCallback(gnssNiCbIface);
+ if (!status.isOk()) {
+ ALOGI("SetCallback for IGnssNi interface failed.");
+ }
} else {
- ALOGI("Unable to initialize GNSS NI interface\n");
+ ALOGI("Unable to initialize IGnssNi interface.");
}
+ // Set IAGnssRil.hal callback.
sp<IAGnssRilCallback> aGnssRilCbIface = new AGnssRilCallback();
if (agnssRilIface != nullptr) {
- agnssRilIface->setCallback(aGnssRilCbIface);
+ auto status = agnssRilIface->setCallback(aGnssRilCbIface);
+ if (!status.isOk()) {
+ ALOGI("SetCallback for IAGnssRil interface failed.");
+ }
} else {
- ALOGI("Unable to initialize AGnss Ril interface\n");
+ ALOGI("Unable to initialize IAGnssRil interface.");
}
+ // Set IGnssVisibilityControl.hal callback.
if (gnssVisibilityControlIface != nullptr) {
sp<IGnssVisibilityControlCallback> gnssVisibilityControlCbIface =
new GnssVisibilityControlCallback();
- gnssVisibilityControlIface->setCallback(gnssVisibilityControlCbIface);
+ result = gnssVisibilityControlIface->setCallback(gnssVisibilityControlCbIface);
+ if (!result.isOk() || !result) {
+ ALOGI("SetCallback for IGnssVisibilityControl interface failed.");
+ }
}
+ // Set IMeasurementCorrections.hal callback.
if (gnssCorrectionsIface != nullptr) {
sp<IMeasurementCorrectionsCallback> gnssCorrectionsIfaceCbIface =
new MeasurementCorrectionsCallback();
- gnssCorrectionsIface->setCallback(gnssCorrectionsIfaceCbIface);
+ result = gnssCorrectionsIface->setCallback(gnssCorrectionsIfaceCbIface);
+ if (!result.isOk() || !result) {
+ ALOGI("SetCallback for IMeasurementCorrections interface failed.");
+ }
}
return JNI_TRUE;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index be7dd31..4ac8342 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -115,6 +115,7 @@
import com.android.server.os.BugreportManagerService;
import com.android.server.os.DeviceIdentifiersPolicyService;
import com.android.server.os.SchedulingPolicyService;
+import com.android.server.pm.ApexManager;
import com.android.server.pm.BackgroundDexOptService;
import com.android.server.pm.CrossProfileAppsService;
import com.android.server.pm.DynamicCodeLoggingService;
@@ -627,6 +628,12 @@
watchdog.start();
traceEnd();
+ // Start ApexManager as early as we can to give it enough time to call apexd and populate
+ // cache of known apex packages. Note that calling apexd will happen asynchronously.
+ traceBeginAndSlog("StartApexManager");
+ mSystemServiceManager.startService(ApexManager.class);
+ traceEnd();
+
Slog.i(TAG, "Reading configuration...");
final String TAG_SYSTEM_CONFIG = "ReadingSystemConfig";
traceBeginAndSlog(TAG_SYSTEM_CONFIG);
diff --git a/services/net/Android.bp b/services/net/Android.bp
index a44d835..ab11fe4 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -56,6 +56,7 @@
versions: [
"1",
"2",
+ "3",
],
}
diff --git a/services/net/aidl/networkstack/3/android/net/DhcpResultsParcelable.aidl b/services/net/aidl/networkstack/3/android/net/DhcpResultsParcelable.aidl
new file mode 100644
index 0000000..31891de
--- /dev/null
+++ b/services/net/aidl/networkstack/3/android/net/DhcpResultsParcelable.aidl
@@ -0,0 +1,9 @@
+package android.net;
+parcelable DhcpResultsParcelable {
+ android.net.StaticIpConfiguration baseConfiguration;
+ int leaseDuration;
+ int mtu;
+ String serverAddress;
+ String vendorInfo;
+ String serverHostName;
+}
diff --git a/services/net/aidl/networkstack/3/android/net/INetworkMonitor.aidl b/services/net/aidl/networkstack/3/android/net/INetworkMonitor.aidl
new file mode 100644
index 0000000..029968b
--- /dev/null
+++ b/services/net/aidl/networkstack/3/android/net/INetworkMonitor.aidl
@@ -0,0 +1,24 @@
+package android.net;
+interface INetworkMonitor {
+ oneway void start();
+ oneway void launchCaptivePortalApp();
+ oneway void notifyCaptivePortalAppFinished(int response);
+ oneway void setAcceptPartialConnectivity();
+ oneway void forceReevaluation(int uid);
+ oneway void notifyPrivateDnsChanged(in android.net.PrivateDnsConfigParcel config);
+ oneway void notifyDnsResponse(int returnCode);
+ oneway void notifyNetworkConnected(in android.net.LinkProperties lp, in android.net.NetworkCapabilities nc);
+ oneway void notifyNetworkDisconnected();
+ oneway void notifyLinkPropertiesChanged(in android.net.LinkProperties lp);
+ oneway void notifyNetworkCapabilitiesChanged(in android.net.NetworkCapabilities nc);
+ const int NETWORK_TEST_RESULT_VALID = 0;
+ const int NETWORK_TEST_RESULT_INVALID = 1;
+ const int NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY = 2;
+ const int NETWORK_VALIDATION_RESULT_VALID = 1;
+ const int NETWORK_VALIDATION_RESULT_PARTIAL = 2;
+ const int NETWORK_VALIDATION_PROBE_DNS = 4;
+ const int NETWORK_VALIDATION_PROBE_HTTP = 8;
+ const int NETWORK_VALIDATION_PROBE_HTTPS = 16;
+ const int NETWORK_VALIDATION_PROBE_FALLBACK = 32;
+ const int NETWORK_VALIDATION_PROBE_PRIVDNS = 64;
+}
diff --git a/services/net/aidl/networkstack/3/android/net/INetworkMonitorCallbacks.aidl b/services/net/aidl/networkstack/3/android/net/INetworkMonitorCallbacks.aidl
new file mode 100644
index 0000000..ee9871d
--- /dev/null
+++ b/services/net/aidl/networkstack/3/android/net/INetworkMonitorCallbacks.aidl
@@ -0,0 +1,8 @@
+package android.net;
+interface INetworkMonitorCallbacks {
+ oneway void onNetworkMonitorCreated(in android.net.INetworkMonitor networkMonitor);
+ oneway void notifyNetworkTested(int testResult, @nullable String redirectUrl);
+ oneway void notifyPrivateDnsConfigResolved(in android.net.PrivateDnsConfigParcel config);
+ oneway void showProvisioningNotification(String action, String packageName);
+ oneway void hideProvisioningNotification();
+}
diff --git a/services/net/aidl/networkstack/3/android/net/INetworkStackConnector.aidl b/services/net/aidl/networkstack/3/android/net/INetworkStackConnector.aidl
new file mode 100644
index 0000000..7da11e4
--- /dev/null
+++ b/services/net/aidl/networkstack/3/android/net/INetworkStackConnector.aidl
@@ -0,0 +1,7 @@
+package android.net;
+interface INetworkStackConnector {
+ oneway void makeDhcpServer(in String ifName, in android.net.dhcp.DhcpServingParamsParcel params, in android.net.dhcp.IDhcpServerCallbacks cb);
+ oneway void makeNetworkMonitor(in android.net.Network network, String name, in android.net.INetworkMonitorCallbacks cb);
+ oneway void makeIpClient(in String ifName, in android.net.ip.IIpClientCallbacks callbacks);
+ oneway void fetchIpMemoryStore(in android.net.IIpMemoryStoreCallbacks cb);
+}
diff --git a/services/net/aidl/networkstack/3/android/net/INetworkStackStatusCallback.aidl b/services/net/aidl/networkstack/3/android/net/INetworkStackStatusCallback.aidl
new file mode 100644
index 0000000..f6ca6f7
--- /dev/null
+++ b/services/net/aidl/networkstack/3/android/net/INetworkStackStatusCallback.aidl
@@ -0,0 +1,4 @@
+package android.net;
+interface INetworkStackStatusCallback {
+ oneway void onStatusAvailable(int statusCode);
+}
diff --git a/services/net/aidl/networkstack/3/android/net/InitialConfigurationParcelable.aidl b/services/net/aidl/networkstack/3/android/net/InitialConfigurationParcelable.aidl
new file mode 100644
index 0000000..c80a787
--- /dev/null
+++ b/services/net/aidl/networkstack/3/android/net/InitialConfigurationParcelable.aidl
@@ -0,0 +1,7 @@
+package android.net;
+parcelable InitialConfigurationParcelable {
+ android.net.LinkAddress[] ipAddresses;
+ android.net.IpPrefix[] directlyConnectedRoutes;
+ String[] dnsServers;
+ String gateway;
+}
diff --git a/services/net/aidl/networkstack/3/android/net/NattKeepalivePacketDataParcelable.aidl b/services/net/aidl/networkstack/3/android/net/NattKeepalivePacketDataParcelable.aidl
new file mode 100644
index 0000000..65de883
--- /dev/null
+++ b/services/net/aidl/networkstack/3/android/net/NattKeepalivePacketDataParcelable.aidl
@@ -0,0 +1,7 @@
+package android.net;
+parcelable NattKeepalivePacketDataParcelable {
+ byte[] srcAddress;
+ int srcPort;
+ byte[] dstAddress;
+ int dstPort;
+}
diff --git a/services/net/aidl/networkstack/3/android/net/PrivateDnsConfigParcel.aidl b/services/net/aidl/networkstack/3/android/net/PrivateDnsConfigParcel.aidl
new file mode 100644
index 0000000..2de790b
--- /dev/null
+++ b/services/net/aidl/networkstack/3/android/net/PrivateDnsConfigParcel.aidl
@@ -0,0 +1,5 @@
+package android.net;
+parcelable PrivateDnsConfigParcel {
+ String hostname;
+ String[] ips;
+}
diff --git a/services/net/aidl/networkstack/3/android/net/ProvisioningConfigurationParcelable.aidl b/services/net/aidl/networkstack/3/android/net/ProvisioningConfigurationParcelable.aidl
new file mode 100644
index 0000000..3a6c304
--- /dev/null
+++ b/services/net/aidl/networkstack/3/android/net/ProvisioningConfigurationParcelable.aidl
@@ -0,0 +1,15 @@
+package android.net;
+parcelable ProvisioningConfigurationParcelable {
+ boolean enableIPv4;
+ boolean enableIPv6;
+ boolean usingMultinetworkPolicyTracker;
+ boolean usingIpReachabilityMonitor;
+ int requestedPreDhcpActionMs;
+ android.net.InitialConfigurationParcelable initialConfig;
+ android.net.StaticIpConfiguration staticIpConfig;
+ android.net.apf.ApfCapabilities apfCapabilities;
+ int provisioningTimeoutMs;
+ int ipv6AddrGenMode;
+ android.net.Network network;
+ String displayName;
+}
diff --git a/services/net/aidl/networkstack/3/android/net/TcpKeepalivePacketDataParcelable.aidl b/services/net/aidl/networkstack/3/android/net/TcpKeepalivePacketDataParcelable.aidl
new file mode 100644
index 0000000..e121c06
--- /dev/null
+++ b/services/net/aidl/networkstack/3/android/net/TcpKeepalivePacketDataParcelable.aidl
@@ -0,0 +1,13 @@
+package android.net;
+parcelable TcpKeepalivePacketDataParcelable {
+ byte[] srcAddress;
+ int srcPort;
+ byte[] dstAddress;
+ int dstPort;
+ int seq;
+ int ack;
+ int rcvWnd;
+ int rcvWndScale;
+ int tos;
+ int ttl;
+}
diff --git a/services/net/aidl/networkstack/3/android/net/dhcp/DhcpServingParamsParcel.aidl b/services/net/aidl/networkstack/3/android/net/dhcp/DhcpServingParamsParcel.aidl
new file mode 100644
index 0000000..67193ae
--- /dev/null
+++ b/services/net/aidl/networkstack/3/android/net/dhcp/DhcpServingParamsParcel.aidl
@@ -0,0 +1,11 @@
+package android.net.dhcp;
+parcelable DhcpServingParamsParcel {
+ int serverAddr;
+ int serverAddrPrefixLength;
+ int[] defaultRouters;
+ int[] dnsServers;
+ int[] excludedAddrs;
+ long dhcpLeaseTimeSecs;
+ int linkMtu;
+ boolean metered;
+}
diff --git a/services/net/aidl/networkstack/3/android/net/dhcp/IDhcpServer.aidl b/services/net/aidl/networkstack/3/android/net/dhcp/IDhcpServer.aidl
new file mode 100644
index 0000000..9143158
--- /dev/null
+++ b/services/net/aidl/networkstack/3/android/net/dhcp/IDhcpServer.aidl
@@ -0,0 +1,10 @@
+package android.net.dhcp;
+interface IDhcpServer {
+ oneway void start(in android.net.INetworkStackStatusCallback cb);
+ oneway void updateParams(in android.net.dhcp.DhcpServingParamsParcel params, in android.net.INetworkStackStatusCallback cb);
+ oneway void stop(in android.net.INetworkStackStatusCallback cb);
+ const int STATUS_UNKNOWN = 0;
+ const int STATUS_SUCCESS = 1;
+ const int STATUS_INVALID_ARGUMENT = 2;
+ const int STATUS_UNKNOWN_ERROR = 3;
+}
diff --git a/services/net/aidl/networkstack/3/android/net/dhcp/IDhcpServerCallbacks.aidl b/services/net/aidl/networkstack/3/android/net/dhcp/IDhcpServerCallbacks.aidl
new file mode 100644
index 0000000..dcc4489
--- /dev/null
+++ b/services/net/aidl/networkstack/3/android/net/dhcp/IDhcpServerCallbacks.aidl
@@ -0,0 +1,4 @@
+package android.net.dhcp;
+interface IDhcpServerCallbacks {
+ oneway void onDhcpServerCreated(int statusCode, in android.net.dhcp.IDhcpServer server);
+}
diff --git a/services/net/aidl/networkstack/3/android/net/ip/IIpClient.aidl b/services/net/aidl/networkstack/3/android/net/ip/IIpClient.aidl
new file mode 100644
index 0000000..176a5ce
--- /dev/null
+++ b/services/net/aidl/networkstack/3/android/net/ip/IIpClient.aidl
@@ -0,0 +1,16 @@
+package android.net.ip;
+interface IIpClient {
+ oneway void completedPreDhcpAction();
+ oneway void confirmConfiguration();
+ oneway void readPacketFilterComplete(in byte[] data);
+ oneway void shutdown();
+ oneway void startProvisioning(in android.net.ProvisioningConfigurationParcelable req);
+ oneway void stop();
+ oneway void setTcpBufferSizes(in String tcpBufferSizes);
+ oneway void setHttpProxy(in android.net.ProxyInfo proxyInfo);
+ oneway void setMulticastFilter(boolean enabled);
+ oneway void addKeepalivePacketFilter(int slot, in android.net.TcpKeepalivePacketDataParcelable pkt);
+ oneway void removeKeepalivePacketFilter(int slot);
+ oneway void setL2KeyAndGroupHint(in String l2Key, in String groupHint);
+ oneway void addNattKeepalivePacketFilter(int slot, in android.net.NattKeepalivePacketDataParcelable pkt);
+}
diff --git a/services/net/aidl/networkstack/3/android/net/ip/IIpClientCallbacks.aidl b/services/net/aidl/networkstack/3/android/net/ip/IIpClientCallbacks.aidl
new file mode 100644
index 0000000..d6bc808
--- /dev/null
+++ b/services/net/aidl/networkstack/3/android/net/ip/IIpClientCallbacks.aidl
@@ -0,0 +1,16 @@
+package android.net.ip;
+interface IIpClientCallbacks {
+ oneway void onIpClientCreated(in android.net.ip.IIpClient ipClient);
+ oneway void onPreDhcpAction();
+ oneway void onPostDhcpAction();
+ oneway void onNewDhcpResults(in android.net.DhcpResultsParcelable dhcpResults);
+ oneway void onProvisioningSuccess(in android.net.LinkProperties newLp);
+ oneway void onProvisioningFailure(in android.net.LinkProperties newLp);
+ oneway void onLinkPropertiesChange(in android.net.LinkProperties newLp);
+ oneway void onReachabilityLost(in String logMsg);
+ oneway void onQuit();
+ oneway void installPacketFilter(in byte[] filter);
+ oneway void startReadPacketFilter();
+ oneway void setFallbackMulticastFilter(boolean enabled);
+ oneway void setNeighborDiscoveryOffload(boolean enable);
+}
diff --git a/services/net/java/android/net/ip/IIpClient.aidl b/services/net/java/android/net/ip/IIpClient.aidl
index 1e77264..9989c52 100644
--- a/services/net/java/android/net/ip/IIpClient.aidl
+++ b/services/net/java/android/net/ip/IIpClient.aidl
@@ -17,6 +17,7 @@
import android.net.ProxyInfo;
import android.net.ProvisioningConfigurationParcelable;
+import android.net.NattKeepalivePacketDataParcelable;
import android.net.TcpKeepalivePacketDataParcelable;
/** @hide */
@@ -33,4 +34,5 @@
void addKeepalivePacketFilter(int slot, in TcpKeepalivePacketDataParcelable pkt);
void removeKeepalivePacketFilter(int slot);
void setL2KeyAndGroupHint(in String l2Key, in String groupHint);
+ void addNattKeepalivePacketFilter(int slot, in NattKeepalivePacketDataParcelable pkt);
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
index c0a11b2..6517303 100644
--- a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
@@ -263,6 +263,9 @@
mService.onStart();
spyOn(mService.mHandler);
+ // Stubbing the handler. Test should simulate any handling of messages synchronously.
+ doReturn(true).when(mService.mHandler).sendMessageAtTime(any(Message.class), anyLong());
+
assertEquals(mService.mSystemUiUid, SYSTEM_UI_UID);
assertEquals(mService.mClockReceiver, mClockReceiver);
assertEquals(mService.mWakeLock, mWakeLock);
@@ -617,11 +620,9 @@
testQuotasNoDeferral(STANDBY_BUCKET_RARE);
}
- private void sendAndHandleBucketChanged(int bucket) {
+ private void assertAndHandleBucketChanged(int bucket) {
when(mUsageStatsManagerInternal.getAppStandbyBucket(eq(TEST_CALLING_PACKAGE), anyInt(),
anyLong())).thenReturn(bucket);
- // Stubbing the handler call to simulate it synchronously here.
- doReturn(true).when(mService.mHandler).sendMessage(any(Message.class));
mAppStandbyListener.onAppIdleStateChanged(TEST_CALLING_PACKAGE,
UserHandle.getUserId(TEST_CALLING_UID), false, bucket, 0);
final ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
@@ -652,7 +653,7 @@
// The next upcoming alarm in queue should also be set as expected.
assertEquals(firstTrigger + workingQuota - 1, mTestTimer.getElapsed());
// Downgrading the bucket now
- sendAndHandleBucketChanged(STANDBY_BUCKET_RARE);
+ assertAndHandleBucketChanged(STANDBY_BUCKET_RARE);
final int rareQuota = mService.getQuotaForBucketLocked(STANDBY_BUCKET_RARE);
// The last alarm should now be deferred.
final long expectedNextTrigger = (firstTrigger + workingQuota - 1 - rareQuota)
@@ -680,15 +681,13 @@
assertEquals(deferredTrigger, mTestTimer.getElapsed());
// Upgrading the bucket now
- sendAndHandleBucketChanged(STANDBY_BUCKET_ACTIVE);
+ assertAndHandleBucketChanged(STANDBY_BUCKET_ACTIVE);
// The last alarm should now be rescheduled to go as per original expectations
final long originalTrigger = firstTrigger + frequentQuota;
assertEquals("Incorrect next alarm trigger", originalTrigger, mTestTimer.getElapsed());
}
- private void sendAndHandleParoleChanged(boolean parole) {
- // Stubbing the handler call to simulate it synchronously here.
- doReturn(true).when(mService.mHandler).sendMessage(any(Message.class));
+ private void assertAndHandleParoleChanged(boolean parole) {
mAppStandbyListener.onParoleStateChanged(parole);
final ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
verify(mService.mHandler, atLeastOnce()).sendMessage(messageCaptor.capture());
@@ -719,7 +718,7 @@
// Any subsequent alarms in queue should all be deferred
assertEquals(firstTrigger + mAppStandbyWindow + 1, mTestTimer.getElapsed());
// Paroling now
- sendAndHandleParoleChanged(true);
+ assertAndHandleParoleChanged(true);
// Subsequent alarms should now go off as per original expectations.
for (int i = 0; i < 5; i++) {
@@ -728,7 +727,7 @@
mTestTimer.expire();
}
// Come out of parole
- sendAndHandleParoleChanged(false);
+ assertAndHandleParoleChanged(false);
// Subsequent alarms should again get deferred
final long expectedNextTrigger = (firstTrigger + 5) + 1 + mAppStandbyWindow;
@@ -938,6 +937,26 @@
}
@Test
+ public void alarmCountOnRemoveFromPendingWhileIdle() {
+ mService.mPendingIdleUntil = mock(AlarmManagerService.Alarm.class);
+ final int numAlarms = 15;
+ final PendingIntent[] pis = new PendingIntent[numAlarms];
+ for (int i = 0; i < numAlarms; i++) {
+ pis[i] = getNewMockPendingIntent();
+ setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 5, pis[i]);
+ }
+ assertEquals(numAlarms, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
+ assertEquals(numAlarms, mService.mPendingWhileIdleAlarms.size());
+ final int toRemove = 8;
+ for (int i = 0; i < toRemove; i++) {
+ mService.removeLocked(pis[i], null);
+ assertEquals(numAlarms - i - 1, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0));
+ }
+ mService.removeLocked(TEST_CALLING_UID);
+ assertEquals(0, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0));
+ }
+
+ @Test
public void alarmCountOnAlarmRemoved() {
final int numAlarms = 10;
final PendingIntent[] pis = new PendingIntent[numAlarms];
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
new file mode 100644
index 0000000..f7edf65
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
@@ -0,0 +1,437 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.job;
+
+import static android.text.format.DateUtils.HOUR_IN_MILLIS;
+import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
+import android.app.IActivityManager;
+import android.app.job.JobInfo;
+import android.app.usage.UsageStatsManagerInternal;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
+import android.content.res.Resources;
+import android.net.ConnectivityManager;
+import android.net.NetworkPolicyManager;
+import android.os.BatteryManagerInternal;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.os.SystemClock;
+
+import com.android.server.AppStateTracker;
+import com.android.server.DeviceIdleController;
+import com.android.server.LocalServices;
+import com.android.server.job.controllers.JobStatus;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+
+import java.time.Clock;
+import java.time.Duration;
+import java.time.ZoneOffset;
+
+public class JobSchedulerServiceTest {
+ private JobSchedulerService mService;
+
+ private MockitoSession mMockingSession;
+ @Mock
+ private ActivityManagerInternal mActivityMangerInternal;
+ @Mock
+ private Context mContext;
+
+ private class TestJobSchedulerService extends JobSchedulerService {
+ TestJobSchedulerService(Context context) {
+ super(context);
+ }
+
+ @Override
+ public boolean isChainedAttributionEnabled() {
+ return false;
+ }
+ }
+
+ @Before
+ public void setUp() {
+ mMockingSession = mockitoSession()
+ .initMocks(this)
+ .strictness(Strictness.LENIENT)
+ .mockStatic(LocalServices.class)
+ .startMocking();
+
+ // Called in JobSchedulerService constructor.
+ when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
+ doReturn(mActivityMangerInternal)
+ .when(() -> LocalServices.getService(ActivityManagerInternal.class));
+ doReturn(mock(UsageStatsManagerInternal.class))
+ .when(() -> LocalServices.getService(UsageStatsManagerInternal.class));
+ // Called in BackgroundJobsController constructor.
+ doReturn(mock(AppStateTracker.class))
+ .when(() -> LocalServices.getService(AppStateTracker.class));
+ // Called in BatteryController constructor.
+ doReturn(mock(BatteryManagerInternal.class))
+ .when(() -> LocalServices.getService(BatteryManagerInternal.class));
+ // Called in ConnectivityController constructor.
+ when(mContext.getSystemService(ConnectivityManager.class))
+ .thenReturn(mock(ConnectivityManager.class));
+ when(mContext.getSystemService(NetworkPolicyManager.class))
+ .thenReturn(mock(NetworkPolicyManager.class));
+ // Called in DeviceIdleJobsController constructor.
+ doReturn(mock(DeviceIdleController.LocalService.class))
+ .when(() -> LocalServices.getService(DeviceIdleController.LocalService.class));
+ // Used in JobStatus.
+ doReturn(mock(PackageManagerInternal.class))
+ .when(() -> LocalServices.getService(PackageManagerInternal.class));
+ // Called via IdleController constructor.
+ when(mContext.getPackageManager()).thenReturn(mock(PackageManager.class));
+ when(mContext.getResources()).thenReturn(mock(Resources.class));
+ // Called in QuotaController constructor.
+ IActivityManager activityManager = ActivityManager.getService();
+ spyOn(activityManager);
+ try {
+ doNothing().when(activityManager).registerUidObserver(any(), anyInt(), anyInt(), any());
+ } catch (RemoteException e) {
+ fail("registerUidObserver threw exception: " + e.getMessage());
+ }
+
+ JobSchedulerService.sSystemClock = Clock.fixed(Clock.systemUTC().instant(), ZoneOffset.UTC);
+ JobSchedulerService.sElapsedRealtimeClock =
+ Clock.fixed(SystemClock.elapsedRealtimeClock().instant(), ZoneOffset.UTC);
+
+ mService = new TestJobSchedulerService(mContext);
+ }
+
+ @After
+ public void tearDown() {
+ if (mMockingSession != null) {
+ mMockingSession.finishMocking();
+ }
+ }
+
+ private Clock getAdvancedClock(Clock clock, long incrementMs) {
+ return Clock.offset(clock, Duration.ofMillis(incrementMs));
+ }
+
+ private void advanceElapsedClock(long incrementMs) {
+ JobSchedulerService.sElapsedRealtimeClock = getAdvancedClock(
+ JobSchedulerService.sElapsedRealtimeClock, incrementMs);
+ }
+
+ private static JobInfo.Builder createJobInfo() {
+ return new JobInfo.Builder(351, new ComponentName("foo", "bar"));
+ }
+
+ private JobStatus createJobStatus(String testTag, JobInfo.Builder jobInfoBuilder) {
+ return JobStatus.createFromJobInfo(
+ jobInfoBuilder.build(), 1234, "com.android.test", 0, testTag);
+ }
+
+ /**
+ * Confirm that {@link JobSchedulerService#getRescheduleJobForPeriodic(JobStatus)} returns a job
+ * with the correct delay and deadline constraints if the periodic job is completed and
+ * rescheduled while run in its expected running window.
+ */
+ @Test
+ public void testGetRescheduleJobForPeriodic_insideWindow() {
+ final long now = sElapsedRealtimeClock.millis();
+ JobStatus job = createJobStatus("testGetRescheduleJobForPeriodic_insideWindow",
+ createJobInfo().setPeriodic(HOUR_IN_MILLIS));
+ final long nextWindowStartTime = now + HOUR_IN_MILLIS;
+ final long nextWindowEndTime = now + 2 * HOUR_IN_MILLIS;
+
+ JobStatus rescheduledJob = mService.getRescheduleJobForPeriodic(job);
+ assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+ assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+ advanceElapsedClock(10 * MINUTE_IN_MILLIS); // now + 10 minutes
+
+ rescheduledJob = mService.getRescheduleJobForPeriodic(job);
+ assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+ assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+ advanceElapsedClock(45 * MINUTE_IN_MILLIS); // now + 55 minutes
+
+ rescheduledJob = mService.getRescheduleJobForPeriodic(job);
+ assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+ assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+ advanceElapsedClock(4 * MINUTE_IN_MILLIS); // now + 59 minutes
+
+ rescheduledJob = mService.getRescheduleJobForPeriodic(job);
+ assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+ assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+ }
+
+ /**
+ * Confirm that {@link JobSchedulerService#getRescheduleJobForPeriodic(JobStatus)} returns a job
+ * with the correct delay and deadline constraints if the periodic job with a custom flex
+ * setting is completed and rescheduled while run in its expected running window.
+ */
+ @Test
+ public void testGetRescheduleJobForPeriodic_insideWindow_flex() {
+ JobStatus job = createJobStatus("testGetRescheduleJobForPeriodic_insideWindow_flex",
+ createJobInfo().setPeriodic(HOUR_IN_MILLIS, 30 * MINUTE_IN_MILLIS));
+ // First window starts 30 minutes from now.
+ advanceElapsedClock(30 * MINUTE_IN_MILLIS);
+ final long now = sElapsedRealtimeClock.millis();
+ final long nextWindowStartTime = now + HOUR_IN_MILLIS;
+ final long nextWindowEndTime = now + 90 * MINUTE_IN_MILLIS;
+
+ JobStatus rescheduledJob = mService.getRescheduleJobForPeriodic(job);
+ assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+ assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+ advanceElapsedClock(10 * MINUTE_IN_MILLIS); // now + 10 minutes
+
+ rescheduledJob = mService.getRescheduleJobForPeriodic(job);
+ assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+ assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+ advanceElapsedClock(15 * MINUTE_IN_MILLIS); // now + 25 minutes
+
+ rescheduledJob = mService.getRescheduleJobForPeriodic(job);
+ assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+ assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+ advanceElapsedClock(4 * MINUTE_IN_MILLIS); // now + 29 minutes
+
+ rescheduledJob = mService.getRescheduleJobForPeriodic(job);
+ assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+ assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+ }
+
+ /**
+ * Confirm that {@link JobSchedulerService#getRescheduleJobForPeriodic(JobStatus)} returns a job
+ * with the correct delay and deadline constraints if the periodic job failed but then ran
+ * successfully and was rescheduled while run in its expected running window.
+ */
+ @Test
+ public void testGetRescheduleJobForPeriodic_insideWindow_failedJob() {
+ final long now = sElapsedRealtimeClock.millis();
+ final long nextWindowStartTime = now + HOUR_IN_MILLIS;
+ final long nextWindowEndTime = now + 2 * HOUR_IN_MILLIS;
+ JobStatus job = createJobStatus("testGetRescheduleJobForPeriodic_insideWindow_failedJob",
+ createJobInfo().setPeriodic(HOUR_IN_MILLIS));
+ JobStatus failedJob = mService.getRescheduleJobForFailureLocked(job);
+
+ JobStatus rescheduledJob = mService.getRescheduleJobForPeriodic(failedJob);
+ assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+ assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+ advanceElapsedClock(5 * MINUTE_IN_MILLIS); // now + 5 minutes
+ failedJob = mService.getRescheduleJobForFailureLocked(job);
+ advanceElapsedClock(5 * MINUTE_IN_MILLIS); // now + 10 minutes
+
+ rescheduledJob = mService.getRescheduleJobForPeriodic(failedJob);
+ assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+ assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+ advanceElapsedClock(35 * MINUTE_IN_MILLIS); // now + 45 minutes
+ failedJob = mService.getRescheduleJobForFailureLocked(job);
+ advanceElapsedClock(10 * MINUTE_IN_MILLIS); // now + 55 minutes
+
+ rescheduledJob = mService.getRescheduleJobForPeriodic(failedJob);
+ assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+ assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+ advanceElapsedClock(2 * MINUTE_IN_MILLIS); // now + 57 minutes
+ failedJob = mService.getRescheduleJobForFailureLocked(job);
+ advanceElapsedClock(2 * MINUTE_IN_MILLIS); // now + 59 minutes
+
+ rescheduledJob = mService.getRescheduleJobForPeriodic(failedJob);
+ assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+ assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+ }
+
+ /**
+ * Confirm that {@link JobSchedulerService#getRescheduleJobForPeriodic(JobStatus)} returns a job
+ * with the correct delay and deadline constraints if the periodic job is completed and
+ * rescheduled when run after its expected running window.
+ */
+ @Test
+ public void testGetRescheduleJobForPeriodic_outsideWindow() {
+ JobStatus job = createJobStatus("testGetRescheduleJobForPeriodic_outsideWindow",
+ createJobInfo().setPeriodic(HOUR_IN_MILLIS));
+ long now = sElapsedRealtimeClock.millis();
+ long nextWindowStartTime = now + HOUR_IN_MILLIS;
+ long nextWindowEndTime = now + 2 * HOUR_IN_MILLIS;
+
+ advanceElapsedClock(HOUR_IN_MILLIS + MINUTE_IN_MILLIS);
+ // Say the job ran at the very end of its previous window. The intended JSS behavior is to
+ // have consistent windows, so the new window should start as soon as the previous window
+ // ended and end PERIOD time after the previous window ended.
+ JobStatus rescheduledJob = mService.getRescheduleJobForPeriodic(job);
+ assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+ assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+ advanceElapsedClock(2 * HOUR_IN_MILLIS);
+ // Say that the job ran at this point, possibly due to device idle.
+ // The next window should be consistent (start and end at the time it would have had the job
+ // run normally in previous windows).
+ nextWindowStartTime += 2 * HOUR_IN_MILLIS;
+ nextWindowEndTime += 2 * HOUR_IN_MILLIS;
+
+ rescheduledJob = mService.getRescheduleJobForPeriodic(job);
+ assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+ assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+ }
+
+ /**
+ * Confirm that {@link JobSchedulerService#getRescheduleJobForPeriodic(JobStatus)} returns a job
+ * with the correct delay and deadline constraints if the periodic job with a custom flex
+ * setting is completed and rescheduled when run after its expected running window.
+ */
+ @Test
+ public void testGetRescheduleJobForPeriodic_outsideWindow_flex() {
+ JobStatus job = createJobStatus("testGetRescheduleJobForPeriodic_outsideWindow_flex",
+ createJobInfo().setPeriodic(HOUR_IN_MILLIS, 30 * MINUTE_IN_MILLIS));
+ // First window starts 30 minutes from now.
+ advanceElapsedClock(30 * MINUTE_IN_MILLIS);
+ long now = sElapsedRealtimeClock.millis();
+ long nextWindowStartTime = now + HOUR_IN_MILLIS;
+ long nextWindowEndTime = now + 90 * MINUTE_IN_MILLIS;
+
+ advanceElapsedClock(31 * MINUTE_IN_MILLIS);
+ // Say the job ran at the very end of its previous window. The intended JSS behavior is to
+ // have consistent windows, so the new window should start as soon as the previous window
+ // ended and end PERIOD time after the previous window ended.
+ JobStatus rescheduledJob = mService.getRescheduleJobForPeriodic(job);
+ assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+ assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+ // 5 minutes before the start of the next window. It's too close to the next window, so the
+ // returned job should be for the window after.
+ advanceElapsedClock(24 * MINUTE_IN_MILLIS);
+ nextWindowStartTime += HOUR_IN_MILLIS;
+ nextWindowEndTime += HOUR_IN_MILLIS;
+ rescheduledJob = mService.getRescheduleJobForPeriodic(job);
+ assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+ assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+ advanceElapsedClock(2 * HOUR_IN_MILLIS + 10 * MINUTE_IN_MILLIS);
+ // Say that the job ran at this point, possibly due to device idle.
+ // The next window should be consistent (start and end at the time it would have had the job
+ // run normally in previous windows).
+ nextWindowStartTime += 2 * HOUR_IN_MILLIS;
+ nextWindowEndTime += 2 * HOUR_IN_MILLIS;
+
+ rescheduledJob = mService.getRescheduleJobForPeriodic(job);
+ assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+ assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+ }
+
+ /**
+ * Confirm that {@link JobSchedulerService#getRescheduleJobForPeriodic(JobStatus)} returns a job
+ * with the correct delay and deadline constraints if the periodic job failed but then ran
+ * successfully and was rescheduled when run after its expected running window.
+ */
+ @Test
+ public void testGetRescheduleJobForPeriodic_outsideWindow_failedJob() {
+ JobStatus job = createJobStatus("testGetRescheduleJobForPeriodic_outsideWindow_failedJob",
+ createJobInfo().setPeriodic(HOUR_IN_MILLIS));
+ JobStatus failedJob = mService.getRescheduleJobForFailureLocked(job);
+ long now = sElapsedRealtimeClock.millis();
+ long nextWindowStartTime = now + HOUR_IN_MILLIS;
+ long nextWindowEndTime = now + 2 * HOUR_IN_MILLIS;
+
+ advanceElapsedClock(HOUR_IN_MILLIS + MINUTE_IN_MILLIS);
+ // Say the job ran at the very end of its previous window. The intended JSS behavior is to
+ // have consistent windows, so the new window should start as soon as the previous window
+ // ended and end PERIOD time after the previous window ended.
+ JobStatus rescheduledJob = mService.getRescheduleJobForPeriodic(failedJob);
+ assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+ assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+ advanceElapsedClock(2 * HOUR_IN_MILLIS);
+ // Say that the job ran at this point, possibly due to device idle.
+ // The next window should be consistent (start and end at the time it would have had the job
+ // run normally in previous windows).
+ nextWindowStartTime += 2 * HOUR_IN_MILLIS;
+ nextWindowEndTime += 2 * HOUR_IN_MILLIS;
+
+ rescheduledJob = mService.getRescheduleJobForPeriodic(failedJob);
+ assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+ assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+ }
+
+ /**
+ * Confirm that {@link JobSchedulerService#getRescheduleJobForPeriodic(JobStatus)} returns a job
+ * with the correct delay and deadline constraints if the periodic job with a custom flex
+ * setting failed but then ran successfully and was rescheduled when run after its expected
+ * running window.
+ */
+ @Test
+ public void testGetRescheduleJobForPeriodic_outsideWindow_flex_failedJob() {
+ JobStatus job = createJobStatus(
+ "testGetRescheduleJobForPeriodic_outsideWindow_flex_failedJob",
+ createJobInfo().setPeriodic(HOUR_IN_MILLIS, 30 * MINUTE_IN_MILLIS));
+ JobStatus failedJob = mService.getRescheduleJobForFailureLocked(job);
+ // First window starts 30 minutes from now.
+ advanceElapsedClock(30 * MINUTE_IN_MILLIS);
+ long now = sElapsedRealtimeClock.millis();
+ long nextWindowStartTime = now + HOUR_IN_MILLIS;
+ long nextWindowEndTime = now + 90 * MINUTE_IN_MILLIS;
+
+ advanceElapsedClock(31 * MINUTE_IN_MILLIS);
+ // Say the job ran at the very end of its previous window. The intended JSS behavior is to
+ // have consistent windows, so the new window should start as soon as the previous window
+ // ended and end PERIOD time after the previous window ended.
+ JobStatus rescheduledJob = mService.getRescheduleJobForPeriodic(failedJob);
+ assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+ assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+ // 5 minutes before the start of the next window. It's too close to the next window, so the
+ // returned job should be for the window after.
+ advanceElapsedClock(24 * MINUTE_IN_MILLIS);
+ nextWindowStartTime += HOUR_IN_MILLIS;
+ nextWindowEndTime += HOUR_IN_MILLIS;
+ rescheduledJob = mService.getRescheduleJobForPeriodic(job);
+ assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+ assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+
+ advanceElapsedClock(2 * HOUR_IN_MILLIS);
+ // Say that the job ran at this point, possibly due to device idle.
+ // The next window should be consistent (start and end at the time it would have had the job
+ // run normally in previous windows).
+ nextWindowStartTime += 2 * HOUR_IN_MILLIS;
+ nextWindowEndTime += 2 * HOUR_IN_MILLIS;
+
+ rescheduledJob = mService.getRescheduleJobForPeriodic(failedJob);
+ assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
+ assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index 7c30f25..2e7283c 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -105,8 +105,9 @@
private static final int SOURCE_USER_ID = 0;
private BroadcastReceiver mChargingReceiver;
- private Constants mConstants;
+ private Constants mJsConstants;
private QuotaController mQuotaController;
+ private QuotaController.QcConstants mQcConstants;
private int mSourceUid;
private IUidObserver mUidObserver;
@@ -132,13 +133,13 @@
.mockStatic(LocalServices.class)
.startMocking();
// Make sure constants turn on QuotaController.
- mConstants = new Constants();
- mConstants.USE_HEARTBEATS = false;
+ mJsConstants = new Constants();
+ mJsConstants.USE_HEARTBEATS = false;
// Called in StateController constructor.
when(mJobSchedulerService.getTestableContext()).thenReturn(mContext);
when(mJobSchedulerService.getLock()).thenReturn(mJobSchedulerService);
- when(mJobSchedulerService.getConstants()).thenReturn(mConstants);
+ when(mJobSchedulerService.getConstants()).thenReturn(mJsConstants);
// Called in QuotaController constructor.
IActivityManager activityManager = ActivityManager.getService();
spyOn(activityManager);
@@ -196,6 +197,7 @@
} catch (RemoteException e) {
fail(e.getMessage());
}
+ mQcConstants = mQuotaController.getQcConstants();
}
@After
@@ -531,7 +533,7 @@
expectedStats.executionTimeInMaxPeriodMs = 22 * MINUTE_IN_MILLIS;
expectedStats.bgJobCountInMaxPeriod = 15;
expectedStats.quotaCutoffTimeElapsed = now - (2 * HOUR_IN_MILLIS - MINUTE_IN_MILLIS)
- + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS;
+ + mQcConstants.IN_QUOTA_BUFFER_MS;
mQuotaController.updateExecutionStatsLocked(0, "com.android.test", inputStats);
assertEquals(expectedStats, inputStats);
@@ -544,7 +546,7 @@
expectedStats.executionTimeInMaxPeriodMs = 22 * MINUTE_IN_MILLIS;
expectedStats.bgJobCountInMaxPeriod = 15;
expectedStats.quotaCutoffTimeElapsed = now - (2 * HOUR_IN_MILLIS - MINUTE_IN_MILLIS)
- + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS;
+ + mQcConstants.IN_QUOTA_BUFFER_MS;
mQuotaController.updateExecutionStatsLocked(0, "com.android.test", inputStats);
assertEquals(expectedStats, inputStats);
@@ -557,7 +559,7 @@
expectedStats.executionTimeInMaxPeriodMs = 22 * MINUTE_IN_MILLIS;
expectedStats.bgJobCountInMaxPeriod = 15;
expectedStats.quotaCutoffTimeElapsed = now - (2 * HOUR_IN_MILLIS - MINUTE_IN_MILLIS)
- + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS;
+ + mQcConstants.IN_QUOTA_BUFFER_MS;
mQuotaController.updateExecutionStatsLocked(0, "com.android.test", inputStats);
assertEquals(expectedStats, inputStats);
@@ -574,7 +576,7 @@
expectedStats.executionTimeInMaxPeriodMs = 23 * MINUTE_IN_MILLIS;
expectedStats.bgJobCountInMaxPeriod = 18;
expectedStats.quotaCutoffTimeElapsed = now - (2 * HOUR_IN_MILLIS - MINUTE_IN_MILLIS)
- + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS;
+ + mQcConstants.IN_QUOTA_BUFFER_MS;
mQuotaController.updateExecutionStatsLocked(0, "com.android.test", inputStats);
assertEquals(expectedStats, inputStats);
@@ -590,7 +592,7 @@
expectedStats.executionTimeInMaxPeriodMs = 24 * MINUTE_IN_MILLIS;
expectedStats.bgJobCountInMaxPeriod = 20;
expectedStats.quotaCutoffTimeElapsed = now - (2 * HOUR_IN_MILLIS - MINUTE_IN_MILLIS)
- + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS;
+ + mQcConstants.IN_QUOTA_BUFFER_MS;
mQuotaController.updateExecutionStatsLocked(0, "com.android.test", inputStats);
assertEquals(expectedStats, inputStats);
}
@@ -630,7 +632,7 @@
expectedStats.executionTimeInMaxPeriodMs = 33 * MINUTE_IN_MILLIS;
expectedStats.bgJobCountInMaxPeriod = 20;
expectedStats.quotaCutoffTimeElapsed = now - (2 * HOUR_IN_MILLIS - 3 * MINUTE_IN_MILLIS)
- + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS;
+ + mQcConstants.IN_QUOTA_BUFFER_MS;
assertEquals(expectedStats,
mQuotaController.getExecutionStatsLocked(0, "com.android.test", WORKING_INDEX));
@@ -642,7 +644,7 @@
expectedStats.executionTimeInMaxPeriodMs = 33 * MINUTE_IN_MILLIS;
expectedStats.bgJobCountInMaxPeriod = 20;
expectedStats.quotaCutoffTimeElapsed = now - (2 * HOUR_IN_MILLIS - 3 * MINUTE_IN_MILLIS)
- + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS;
+ + mQcConstants.IN_QUOTA_BUFFER_MS;
assertEquals(expectedStats,
mQuotaController.getExecutionStatsLocked(0, "com.android.test", FREQUENT_INDEX));
@@ -654,7 +656,7 @@
expectedStats.executionTimeInMaxPeriodMs = 33 * MINUTE_IN_MILLIS;
expectedStats.bgJobCountInMaxPeriod = 20;
expectedStats.quotaCutoffTimeElapsed = now - (2 * HOUR_IN_MILLIS - 3 * MINUTE_IN_MILLIS)
- + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS;
+ + mQcConstants.IN_QUOTA_BUFFER_MS;
assertEquals(expectedStats,
mQuotaController.getExecutionStatsLocked(0, "com.android.test", RARE_INDEX));
}
@@ -685,8 +687,8 @@
// Advance clock so that the working stats shouldn't be the same.
advanceElapsedClock(MINUTE_IN_MILLIS);
// Change frequent bucket size so that the stats need to be recalculated.
- mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS = 6 * HOUR_IN_MILLIS;
- mQuotaController.onConstantsUpdatedLocked();
+ mQcConstants.WINDOW_SIZE_FREQUENT_MS = 6 * HOUR_IN_MILLIS;
+ mQcConstants.updateConstants();
ExecutionStats expectedStats = new ExecutionStats();
expectedStats.windowSizeMs = originalStatsActive.windowSizeMs;
@@ -778,7 +780,7 @@
setStandbyBucket(ACTIVE_INDEX);
assertEquals(7 * MINUTE_IN_MILLIS,
mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
- assertEquals(mConstants.QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS - 9 * MINUTE_IN_MILLIS,
+ assertEquals(mQcConstants.MAX_EXECUTION_TIME_MS - 9 * MINUTE_IN_MILLIS,
mQuotaController.getTimeUntilQuotaConsumedLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
}
@@ -901,7 +903,7 @@
public void testIsWithinQuotaLocked_UnderDuration_OverJobCount() {
setDischarging();
final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
- final int jobCount = mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME;
+ final int jobCount = mQcConstants.MAX_JOB_COUNT_PER_ALLOWED_TIME;
mQuotaController.saveTimingSession(0, "com.android.test.spam",
createTimingSession(now - (HOUR_IN_MILLIS), 15 * MINUTE_IN_MILLIS, 25));
mQuotaController.saveTimingSession(0, "com.android.test.spam",
@@ -936,7 +938,7 @@
public void testIsWithinQuotaLocked_OverDuration_OverJobCount() {
setDischarging();
final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
- final int jobCount = mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME;
+ final int jobCount = mQcConstants.MAX_JOB_COUNT_PER_ALLOWED_TIME;
mQuotaController.saveTimingSession(0, "com.android.test",
createTimingSession(now - (HOUR_IN_MILLIS), 15 * MINUTE_IN_MILLIS, 25));
mQuotaController.saveTimingSession(0, "com.android.test",
@@ -1098,8 +1100,7 @@
final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
// Test with timing sessions out of window but still under max execution limit.
final long expectedAlarmTime =
- (now - 18 * HOUR_IN_MILLIS) + 24 * HOUR_IN_MILLIS
- + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS;
+ (now - 18 * HOUR_IN_MILLIS) + 24 * HOUR_IN_MILLIS + mQcConstants.IN_QUOTA_BUFFER_MS;
mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
createTimingSession(now - 18 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, 1));
mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
@@ -1156,8 +1157,7 @@
final long end = now - (2 * HOUR_IN_MILLIS - 5 * MINUTE_IN_MILLIS);
// Counting backwards, the quota will come back one minute before the end.
final long expectedAlarmTime =
- end - MINUTE_IN_MILLIS + 2 * HOUR_IN_MILLIS
- + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS;
+ end - MINUTE_IN_MILLIS + 2 * HOUR_IN_MILLIS + mQcConstants.IN_QUOTA_BUFFER_MS;
mQuotaController.saveTimingSession(0, "com.android.test",
new TimingSession(now - 2 * HOUR_IN_MILLIS, end, 1));
mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket);
@@ -1207,8 +1207,7 @@
// Test with timing sessions in window but still in quota.
final long start = now - (6 * HOUR_IN_MILLIS);
- final long expectedAlarmTime =
- start + 8 * HOUR_IN_MILLIS + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS;
+ final long expectedAlarmTime = start + 8 * HOUR_IN_MILLIS + mQcConstants.IN_QUOTA_BUFFER_MS;
mQuotaController.saveTimingSession(0, "com.android.test",
createTimingSession(start, 5 * MINUTE_IN_MILLIS, 1));
mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket);
@@ -1262,7 +1261,7 @@
// needs to be excluded.
final long expectedAlarmTime =
start + MINUTE_IN_MILLIS + 24 * HOUR_IN_MILLIS
- + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS;
+ + mQcConstants.IN_QUOTA_BUFFER_MS;
mQuotaController.saveTimingSession(0, "com.android.test",
createTimingSession(start, 5 * MINUTE_IN_MILLIS, 1));
mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket);
@@ -1324,21 +1323,21 @@
// And down from there.
final long expectedWorkingAlarmTime =
outOfQuotaTime + (2 * HOUR_IN_MILLIS)
- + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS;
+ + mQcConstants.IN_QUOTA_BUFFER_MS;
mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", WORKING_INDEX);
inOrder.verify(mAlarmManager, times(1))
.set(anyInt(), eq(expectedWorkingAlarmTime), eq(TAG_QUOTA_CHECK), any(), any());
final long expectedFrequentAlarmTime =
outOfQuotaTime + (8 * HOUR_IN_MILLIS)
- + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS;
+ + mQcConstants.IN_QUOTA_BUFFER_MS;
mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", FREQUENT_INDEX);
inOrder.verify(mAlarmManager, times(1))
.set(anyInt(), eq(expectedFrequentAlarmTime), eq(TAG_QUOTA_CHECK), any(), any());
final long expectedRareAlarmTime =
outOfQuotaTime + (24 * HOUR_IN_MILLIS)
- + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS;
+ + mQcConstants.IN_QUOTA_BUFFER_MS;
mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", RARE_INDEX);
inOrder.verify(mAlarmManager, times(1))
.set(anyInt(), eq(expectedRareAlarmTime), eq(TAG_QUOTA_CHECK), any(), any());
@@ -1365,7 +1364,7 @@
ExecutionStats stats = mQuotaController.getExecutionStatsLocked(SOURCE_USER_ID,
SOURCE_PACKAGE, standbyBucket);
stats.jobCountInAllowedTime =
- mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME + 2;
+ mQcConstants.MAX_JOB_COUNT_PER_ALLOWED_TIME + 2;
// Invalid time in the past, so the count shouldn't be used.
stats.jobCountExpirationTimeElapsed =
@@ -1400,8 +1399,8 @@
@Test
public void testMaybeScheduleStartAlarmLocked_SmallRollingQuota_UpdatedBufferSize() {
// Make sure any new value is used correctly.
- mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS *= 2;
- mQuotaController.onConstantsUpdatedLocked();
+ mQcConstants.IN_QUOTA_BUFFER_MS *= 2;
+ mQcConstants.updateConstants();
runTestMaybeScheduleStartAlarmLocked_SmallRollingQuota_AllowedTimeCheck();
mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE).clear();
runTestMaybeScheduleStartAlarmLocked_SmallRollingQuota_MaxTimeCheck();
@@ -1410,8 +1409,8 @@
@Test
public void testMaybeScheduleStartAlarmLocked_SmallRollingQuota_UpdatedAllowedTime() {
// Make sure any new value is used correctly.
- mConstants.QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS /= 2;
- mQuotaController.onConstantsUpdatedLocked();
+ mQcConstants.ALLOWED_TIME_PER_PERIOD_MS /= 2;
+ mQcConstants.updateConstants();
runTestMaybeScheduleStartAlarmLocked_SmallRollingQuota_AllowedTimeCheck();
mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE).clear();
runTestMaybeScheduleStartAlarmLocked_SmallRollingQuota_MaxTimeCheck();
@@ -1420,8 +1419,8 @@
@Test
public void testMaybeScheduleStartAlarmLocked_SmallRollingQuota_UpdatedMaxTime() {
// Make sure any new value is used correctly.
- mConstants.QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS /= 2;
- mQuotaController.onConstantsUpdatedLocked();
+ mQcConstants.MAX_EXECUTION_TIME_MS /= 2;
+ mQcConstants.updateConstants();
runTestMaybeScheduleStartAlarmLocked_SmallRollingQuota_AllowedTimeCheck();
mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE).clear();
runTestMaybeScheduleStartAlarmLocked_SmallRollingQuota_MaxTimeCheck();
@@ -1430,10 +1429,10 @@
@Test
public void testMaybeScheduleStartAlarmLocked_SmallRollingQuota_UpdatedEverything() {
// Make sure any new value is used correctly.
- mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS *= 2;
- mConstants.QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS /= 2;
- mConstants.QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS /= 2;
- mQuotaController.onConstantsUpdatedLocked();
+ mQcConstants.IN_QUOTA_BUFFER_MS *= 2;
+ mQcConstants.ALLOWED_TIME_PER_PERIOD_MS /= 2;
+ mQcConstants.MAX_EXECUTION_TIME_MS /= 2;
+ mQcConstants.updateConstants();
runTestMaybeScheduleStartAlarmLocked_SmallRollingQuota_AllowedTimeCheck();
mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE).clear();
runTestMaybeScheduleStartAlarmLocked_SmallRollingQuota_MaxTimeCheck();
@@ -1448,9 +1447,8 @@
final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
// Working set window size is 2 hours.
final int standbyBucket = WORKING_INDEX;
- final long contributionMs = mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS / 2;
- final long remainingTimeMs =
- mConstants.QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS - contributionMs;
+ final long contributionMs = mQcConstants.IN_QUOTA_BUFFER_MS / 2;
+ final long remainingTimeMs = mQcConstants.ALLOWED_TIME_PER_PERIOD_MS - contributionMs;
// Session straddles edge of bucket window. Only the contribution should be counted towards
// the quota.
@@ -1462,7 +1460,7 @@
// Expected alarm time should be when the app will have QUOTA_BUFFER_MS time of quota, which
// is 2 hours + (QUOTA_BUFFER_MS - contributionMs) after the start of the second session.
final long expectedAlarmTime = now - HOUR_IN_MILLIS + 2 * HOUR_IN_MILLIS
- + (mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS - contributionMs);
+ + (mQcConstants.IN_QUOTA_BUFFER_MS - contributionMs);
mQuotaController.maybeScheduleStartAlarmLocked(SOURCE_USER_ID, SOURCE_PACKAGE,
standbyBucket);
verify(mAlarmManager, times(1))
@@ -1479,9 +1477,8 @@
final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
// Working set window size is 2 hours.
final int standbyBucket = WORKING_INDEX;
- final long contributionMs = mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS / 2;
- final long remainingTimeMs =
- mConstants.QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS - contributionMs;
+ final long contributionMs = mQcConstants.IN_QUOTA_BUFFER_MS / 2;
+ final long remainingTimeMs = mQcConstants.MAX_EXECUTION_TIME_MS - contributionMs;
// Session straddles edge of 24 hour window. Only the contribution should be counted towards
// the quota.
@@ -1493,9 +1490,8 @@
// Expected alarm time should be when the app will have QUOTA_BUFFER_MS time of quota, which
// is 24 hours + (QUOTA_BUFFER_MS - contributionMs) after the start of the second session.
final long expectedAlarmTime = now - 20 * HOUR_IN_MILLIS
- //+ mConstants.QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS
+ 24 * HOUR_IN_MILLIS
- + (mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS - contributionMs);
+ + (mQcConstants.IN_QUOTA_BUFFER_MS - contributionMs);
mQuotaController.maybeScheduleStartAlarmLocked(SOURCE_USER_ID, SOURCE_PACKAGE,
standbyBucket);
verify(mAlarmManager, times(1))
@@ -1515,12 +1511,12 @@
mQuotaController.maybeStartTrackingJobLocked(jobStatus, null);
assertFalse(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
- mConstants.USE_HEARTBEATS = true;
+ mJsConstants.USE_HEARTBEATS = true;
mQuotaController.onConstantsUpdatedLocked();
Thread.sleep(SECOND_IN_MILLIS); // Job updates are done in the background.
assertTrue(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
- mConstants.USE_HEARTBEATS = false;
+ mJsConstants.USE_HEARTBEATS = false;
mQuotaController.onConstantsUpdatedLocked();
Thread.sleep(SECOND_IN_MILLIS); // Job updates are done in the background.
assertFalse(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
@@ -1528,20 +1524,20 @@
@Test
public void testConstantsUpdating_ValidValues() {
- mConstants.QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS = 5 * MINUTE_IN_MILLIS;
- mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS = 2 * MINUTE_IN_MILLIS;
- mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS = 15 * MINUTE_IN_MILLIS;
- mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS = 30 * MINUTE_IN_MILLIS;
- mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS = 45 * MINUTE_IN_MILLIS;
- mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS = 60 * MINUTE_IN_MILLIS;
- mConstants.QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS = 3 * HOUR_IN_MILLIS;
- mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE = 5000;
- mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING = 4000;
- mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT = 3000;
- mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE = 2000;
- mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME = 500;
+ mQcConstants.ALLOWED_TIME_PER_PERIOD_MS = 5 * MINUTE_IN_MILLIS;
+ mQcConstants.IN_QUOTA_BUFFER_MS = 2 * MINUTE_IN_MILLIS;
+ mQcConstants.WINDOW_SIZE_ACTIVE_MS = 15 * MINUTE_IN_MILLIS;
+ mQcConstants.WINDOW_SIZE_WORKING_MS = 30 * MINUTE_IN_MILLIS;
+ mQcConstants.WINDOW_SIZE_FREQUENT_MS = 45 * MINUTE_IN_MILLIS;
+ mQcConstants.WINDOW_SIZE_RARE_MS = 60 * MINUTE_IN_MILLIS;
+ mQcConstants.MAX_EXECUTION_TIME_MS = 3 * HOUR_IN_MILLIS;
+ mQcConstants.MAX_JOB_COUNT_ACTIVE = 5000;
+ mQcConstants.MAX_JOB_COUNT_WORKING = 4000;
+ mQcConstants.MAX_JOB_COUNT_FREQUENT = 3000;
+ mQcConstants.MAX_JOB_COUNT_RARE = 2000;
+ mQcConstants.MAX_JOB_COUNT_PER_ALLOWED_TIME = 500;
- mQuotaController.onConstantsUpdatedLocked();
+ mQcConstants.updateConstants();
assertEquals(5 * MINUTE_IN_MILLIS, mQuotaController.getAllowedTimePerPeriodMs());
assertEquals(2 * MINUTE_IN_MILLIS, mQuotaController.getInQuotaBufferMs());
@@ -1561,20 +1557,20 @@
@Test
public void testConstantsUpdating_InvalidValues() {
// Test negatives/too low.
- mConstants.QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS = -MINUTE_IN_MILLIS;
- mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS = -MINUTE_IN_MILLIS;
- mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS = -MINUTE_IN_MILLIS;
- mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS = -MINUTE_IN_MILLIS;
- mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS = -MINUTE_IN_MILLIS;
- mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS = -MINUTE_IN_MILLIS;
- mConstants.QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS = -MINUTE_IN_MILLIS;
- mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE = -1;
- mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING = 1;
- mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT = 1;
- mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE = 1;
- mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME = 0;
+ mQcConstants.ALLOWED_TIME_PER_PERIOD_MS = -MINUTE_IN_MILLIS;
+ mQcConstants.IN_QUOTA_BUFFER_MS = -MINUTE_IN_MILLIS;
+ mQcConstants.WINDOW_SIZE_ACTIVE_MS = -MINUTE_IN_MILLIS;
+ mQcConstants.WINDOW_SIZE_WORKING_MS = -MINUTE_IN_MILLIS;
+ mQcConstants.WINDOW_SIZE_FREQUENT_MS = -MINUTE_IN_MILLIS;
+ mQcConstants.WINDOW_SIZE_RARE_MS = -MINUTE_IN_MILLIS;
+ mQcConstants.MAX_EXECUTION_TIME_MS = -MINUTE_IN_MILLIS;
+ mQcConstants.MAX_JOB_COUNT_ACTIVE = -1;
+ mQcConstants.MAX_JOB_COUNT_WORKING = 1;
+ mQcConstants.MAX_JOB_COUNT_FREQUENT = 1;
+ mQcConstants.MAX_JOB_COUNT_RARE = 1;
+ mQcConstants.MAX_JOB_COUNT_PER_ALLOWED_TIME = 0;
- mQuotaController.onConstantsUpdatedLocked();
+ mQcConstants.updateConstants();
assertEquals(MINUTE_IN_MILLIS, mQuotaController.getAllowedTimePerPeriodMs());
assertEquals(0, mQuotaController.getInQuotaBufferMs());
@@ -1590,15 +1586,15 @@
assertEquals(100, mQuotaController.getBucketMaxJobCounts()[RARE_INDEX]);
// Test larger than a day. Controller should cap at one day.
- mConstants.QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS = 25 * HOUR_IN_MILLIS;
- mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS = 25 * HOUR_IN_MILLIS;
- mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS = 25 * HOUR_IN_MILLIS;
- mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS = 25 * HOUR_IN_MILLIS;
- mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS = 25 * HOUR_IN_MILLIS;
- mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS = 25 * HOUR_IN_MILLIS;
- mConstants.QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS = 25 * HOUR_IN_MILLIS;
+ mQcConstants.ALLOWED_TIME_PER_PERIOD_MS = 25 * HOUR_IN_MILLIS;
+ mQcConstants.IN_QUOTA_BUFFER_MS = 25 * HOUR_IN_MILLIS;
+ mQcConstants.WINDOW_SIZE_ACTIVE_MS = 25 * HOUR_IN_MILLIS;
+ mQcConstants.WINDOW_SIZE_WORKING_MS = 25 * HOUR_IN_MILLIS;
+ mQcConstants.WINDOW_SIZE_FREQUENT_MS = 25 * HOUR_IN_MILLIS;
+ mQcConstants.WINDOW_SIZE_RARE_MS = 25 * HOUR_IN_MILLIS;
+ mQcConstants.MAX_EXECUTION_TIME_MS = 25 * HOUR_IN_MILLIS;
- mQuotaController.onConstantsUpdatedLocked();
+ mQcConstants.updateConstants();
assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getAllowedTimePerPeriodMs());
assertEquals(5 * MINUTE_IN_MILLIS, mQuotaController.getInQuotaBufferMs());
@@ -2219,7 +2215,7 @@
verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
// Ran jobs up to the job limit. All of them should be allowed to run.
- for (int i = 0; i < mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME; ++i) {
+ for (int i = 0; i < mQcConstants.MAX_JOB_COUNT_PER_ALLOWED_TIME; ++i) {
JobStatus job = createJobStatus("testStartAlarmScheduled_JobCount_AllowedTime", i);
mQuotaController.maybeStartTrackingJobLocked(job, null);
assertTrue(job.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
@@ -2240,7 +2236,7 @@
ExecutionStats stats = mQuotaController.getExecutionStatsLocked(SOURCE_USER_ID,
SOURCE_PACKAGE, standbyBucket);
final long expectedWorkingAlarmTime =
- stats.jobCountExpirationTimeElapsed + mConstants.QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS;
+ stats.jobCountExpirationTimeElapsed + mQcConstants.ALLOWED_TIME_PER_PERIOD_MS;
verify(mAlarmManager, times(1))
.set(anyInt(), eq(expectedWorkingAlarmTime), eq(TAG_QUOTA_CHECK), any(), any());
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java
index 494677d..19369db 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java
@@ -39,6 +39,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManagerInternal;
+import android.os.Looper;
import android.os.SystemClock;
import androidx.test.runner.AndroidJUnit4;
@@ -70,7 +71,7 @@
private static final String SOURCE_PACKAGE = "com.android.frameworks.mockingservicestests";
private static final int SOURCE_USER_ID = 0;
- private Constants mConstants;
+ private TimeController.TcConstants mConstants;
private TimeController mTimeController;
private MockitoSession mMockingSession;
@@ -88,14 +89,13 @@
.strictness(Strictness.LENIENT)
.mockStatic(LocalServices.class)
.startMocking();
- // Use default constants for now.
- mConstants = new Constants();
// Called in StateController constructor.
when(mJobSchedulerService.getTestableContext()).thenReturn(mContext);
when(mJobSchedulerService.getLock()).thenReturn(mJobSchedulerService);
- when(mJobSchedulerService.getConstants()).thenReturn(mConstants);
+ when(mJobSchedulerService.getConstants()).thenReturn(mock(Constants.class));
// Called in TimeController constructor.
+ when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
when(mContext.getSystemService(Context.ALARM_SERVICE)).thenReturn(mAlarmManager);
// Used in JobStatus.
doReturn(mock(PackageManagerInternal.class))
@@ -111,6 +111,7 @@
// Initialize real objects.
mTimeController = new TimeController(mJobSchedulerService);
+ mConstants = mTimeController.getTcConstants();
spyOn(mTimeController);
}
@@ -159,7 +160,7 @@
@Test
public void testMaybeStartTrackingJobLocked_DelayInOrder_NoSkipping() {
- mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = false;
+ mConstants.SKIP_NOT_READY_JOBS = false;
mTimeController.onConstantsUpdatedLocked();
runTestMaybeStartTrackingJobLocked_DelayInOrder();
@@ -167,7 +168,7 @@
@Test
public void testMaybeStartTrackingJobLocked_DelayInOrder_WithSkipping_AllReady() {
- mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true;
+ mConstants.SKIP_NOT_READY_JOBS = true;
mTimeController.onConstantsUpdatedLocked();
doReturn(true).when(mTimeController).wouldBeReadyWithConstraintLocked(any(), anyInt());
@@ -201,7 +202,7 @@
@Test
public void testMaybeStartTrackingJobLocked_DelayInOrder_WithSkipping_SomeNotReady() {
- mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true;
+ mConstants.SKIP_NOT_READY_JOBS = true;
mTimeController.onConstantsUpdatedLocked();
final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
@@ -235,7 +236,7 @@
@Test
public void testMaybeStartTrackingJobLocked_DelayReverseOrder_NoSkipping() {
- mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = false;
+ mConstants.SKIP_NOT_READY_JOBS = false;
mTimeController.onConstantsUpdatedLocked();
runTestMaybeStartTrackingJobLocked_DelayReverseOrder();
@@ -243,7 +244,7 @@
@Test
public void testMaybeStartTrackingJobLocked_DelayReverseOrder_WithSkipping_AllReady() {
- mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true;
+ mConstants.SKIP_NOT_READY_JOBS = true;
mTimeController.onConstantsUpdatedLocked();
doReturn(true).when(mTimeController).wouldBeReadyWithConstraintLocked(any(), anyInt());
@@ -279,7 +280,7 @@
@Test
public void testMaybeStartTrackingJobLocked_DelayReverseOrder_WithSkipping_SomeNotReady() {
- mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true;
+ mConstants.SKIP_NOT_READY_JOBS = true;
mTimeController.onConstantsUpdatedLocked();
final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
@@ -315,7 +316,7 @@
@Test
public void testMaybeStartTrackingJobLocked_DeadlineInOrder_NoSkipping() {
- mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = false;
+ mConstants.SKIP_NOT_READY_JOBS = false;
mTimeController.onConstantsUpdatedLocked();
runTestMaybeStartTrackingJobLocked_DeadlineInOrder();
@@ -323,7 +324,7 @@
@Test
public void testMaybeStartTrackingJobLocked_DeadlineInOrder_WithSkipping_AllReady() {
- mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true;
+ mConstants.SKIP_NOT_READY_JOBS = true;
mTimeController.onConstantsUpdatedLocked();
doReturn(true).when(mTimeController).wouldBeReadyWithConstraintLocked(any(), anyInt());
@@ -357,7 +358,7 @@
@Test
public void testMaybeStartTrackingJobLocked_DeadlineInOrder_WithSkipping_SomeNotReady() {
- mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true;
+ mConstants.SKIP_NOT_READY_JOBS = true;
mTimeController.onConstantsUpdatedLocked();
final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
@@ -391,7 +392,7 @@
@Test
public void testMaybeStartTrackingJobLocked_DeadlineReverseOrder_NoSkipping() {
- mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = false;
+ mConstants.SKIP_NOT_READY_JOBS = false;
mTimeController.onConstantsUpdatedLocked();
runTestMaybeStartTrackingJobLocked_DeadlineReverseOrder();
@@ -399,7 +400,7 @@
@Test
public void testMaybeStartTrackingJobLocked_DeadlineReverseOrder_WithSkipping_AllReady() {
- mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true;
+ mConstants.SKIP_NOT_READY_JOBS = true;
mTimeController.onConstantsUpdatedLocked();
doReturn(true).when(mTimeController).wouldBeReadyWithConstraintLocked(any(), anyInt());
@@ -438,7 +439,7 @@
@Test
public void testMaybeStartTrackingJobLocked_DeadlineReverseOrder_WithSkipping_SomeNotReady() {
- mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true;
+ mConstants.SKIP_NOT_READY_JOBS = true;
mTimeController.onConstantsUpdatedLocked();
final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
@@ -493,8 +494,8 @@
.wouldBeReadyWithConstraintLocked(eq(jobEarliest), anyInt());
// Starting off with the skipping off, we should still set an alarm for the earlier job.
- mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = false;
- mTimeController.onConstantsUpdatedLocked();
+ mConstants.SKIP_NOT_READY_JOBS = false;
+ mTimeController.recheckAlarmsLocked();
InOrder inOrder = inOrder(mAlarmManager);
mTimeController.maybeStartTrackingJobLocked(jobEarliest, null);
@@ -504,16 +505,16 @@
eq(TAG_DEADLINE), any(), any(), any());
// Turn it on, use alarm for later job.
- mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true;
- mTimeController.onConstantsUpdatedLocked();
+ mConstants.SKIP_NOT_READY_JOBS = true;
+ mTimeController.recheckAlarmsLocked();
inOrder.verify(mAlarmManager, times(1))
.set(anyInt(), eq(now + HOUR_IN_MILLIS), anyLong(), anyLong(), eq(TAG_DEADLINE),
any(), any(), any());
// Back off, use alarm for earlier job.
- mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = false;
- mTimeController.onConstantsUpdatedLocked();
+ mConstants.SKIP_NOT_READY_JOBS = false;
+ mTimeController.recheckAlarmsLocked();
inOrder.verify(mAlarmManager, times(1))
.set(anyInt(), eq(now + 5 * MINUTE_IN_MILLIS), anyLong(), anyLong(),
@@ -522,16 +523,16 @@
@Test
public void testCheckExpiredDelaysAndResetAlarm_NoSkipping() {
- mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = false;
- mTimeController.onConstantsUpdatedLocked();
+ mConstants.SKIP_NOT_READY_JOBS = false;
+ mTimeController.recheckAlarmsLocked();
runTestCheckExpiredDelaysAndResetAlarm();
}
@Test
public void testCheckExpiredDelaysAndResetAlarm_WithSkipping_AllReady() {
- mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true;
- mTimeController.onConstantsUpdatedLocked();
+ mConstants.SKIP_NOT_READY_JOBS = true;
+ mTimeController.recheckAlarmsLocked();
doReturn(true).when(mTimeController).wouldBeReadyWithConstraintLocked(any(), anyInt());
@@ -589,8 +590,8 @@
@Test
public void testCheckExpiredDelaysAndResetAlarm_WithSkipping_SomeNotReady() {
- mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true;
- mTimeController.onConstantsUpdatedLocked();
+ mConstants.SKIP_NOT_READY_JOBS = true;
+ mTimeController.recheckAlarmsLocked();
final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
JobStatus jobLatest = createJobStatus("testCheckExpiredDelaysAndResetAlarm",
@@ -639,16 +640,16 @@
@Test
public void testCheckExpiredDeadlinesAndResetAlarm_NoSkipping() {
- mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = false;
- mTimeController.onConstantsUpdatedLocked();
+ mConstants.SKIP_NOT_READY_JOBS = false;
+ mTimeController.recheckAlarmsLocked();
runTestCheckExpiredDeadlinesAndResetAlarm();
}
@Test
public void testCheckExpiredDeadlinesAndResetAlarm_WithSkipping_AllReady() {
- mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true;
- mTimeController.onConstantsUpdatedLocked();
+ mConstants.SKIP_NOT_READY_JOBS = true;
+ mTimeController.recheckAlarmsLocked();
doReturn(true).when(mTimeController).wouldBeReadyWithConstraintLocked(any(), anyInt());
@@ -706,8 +707,8 @@
@Test
public void testCheckExpiredDeadlinesAndResetAlarm_WithSkipping_SomeNotReady() {
- mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true;
- mTimeController.onConstantsUpdatedLocked();
+ mConstants.SKIP_NOT_READY_JOBS = true;
+ mTimeController.recheckAlarmsLocked();
final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
JobStatus jobLatest = createJobStatus("testCheckExpiredDeadlinesAndResetAlarm",
@@ -756,8 +757,8 @@
@Test
public void testEvaluateStateLocked_SkippingOff() {
- mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = false;
- mTimeController.onConstantsUpdatedLocked();
+ mConstants.SKIP_NOT_READY_JOBS = false;
+ mTimeController.recheckAlarmsLocked();
JobStatus job = createJobStatus("testEvaluateStateLocked_SkippingOff",
createJob().setOverrideDeadline(HOUR_IN_MILLIS));
@@ -768,8 +769,8 @@
@Test
public void testEvaluateStateLocked_SkippingOn_Delay() {
- mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true;
- mTimeController.onConstantsUpdatedLocked();
+ mConstants.SKIP_NOT_READY_JOBS = true;
+ mTimeController.recheckAlarmsLocked();
final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
JobStatus jobLatest = createJobStatus("testEvaluateStateLocked_SkippingOn_Delay",
@@ -827,8 +828,8 @@
@Test
public void testEvaluateStateLocked_SkippingOn_Deadline() {
- mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true;
- mTimeController.onConstantsUpdatedLocked();
+ mConstants.SKIP_NOT_READY_JOBS = true;
+ mTimeController.recheckAlarmsLocked();
final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
JobStatus jobLatest = createJobStatus("testEvaluateStateLocked_SkippingOn_Deadline",
diff --git a/services/tests/mockingservicestests/src/com/android/server/testables/TestableDeviceConfig.java b/services/tests/mockingservicestests/src/com/android/server/testables/TestableDeviceConfig.java
index eb90295..dae3d30 100644
--- a/services/tests/mockingservicestests/src/com/android/server/testables/TestableDeviceConfig.java
+++ b/services/tests/mockingservicestests/src/com/android/server/testables/TestableDeviceConfig.java
@@ -137,7 +137,6 @@
return mKeyValueMap.get(getKey(namespace, name));
}).when(() -> DeviceConfig.getProperty(anyString(), anyString()));
-
return new TestWatcher() {
@Override
protected void succeeded(Description description) {
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java
index bac8414..7a20af4 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java
@@ -329,6 +329,31 @@
assertEquals(serialNumber, mRecoverableKeyStoreDb.getUserSerialNumbers().get(userId));
}
+ @Test
+ public void setPlatformKeyGenerationId_invalidatesExistingKeysForUser() {
+ int userId = 42;
+ int generationId = 110;
+ int uid = 1009;
+ int status = 120;
+ String alias = "test";
+ byte[] nonce = getUtf8Bytes("nonce");
+ byte[] keyMaterial = getUtf8Bytes("keymaterial");
+ byte[] keyMetadata = null;
+
+ WrappedKey wrappedKey =
+ new WrappedKey(nonce, keyMaterial, keyMetadata, generationId, status);
+ mRecoverableKeyStoreDb.insertKey(userId, uid, alias, wrappedKey);
+
+ WrappedKey retrievedKey = mRecoverableKeyStoreDb.getKey(uid, alias);
+ assertThat(retrievedKey.getRecoveryStatus()).isEqualTo(status);
+
+ mRecoverableKeyStoreDb.setPlatformKeyGenerationId(userId, generationId + 1);
+
+ retrievedKey = mRecoverableKeyStoreDb.getKey(uid, alias);
+ assertThat(retrievedKey.getRecoveryStatus())
+ .isEqualTo(RecoveryController.RECOVERY_STATUS_PERMANENT_FAILURE);
+ }
+
@Test
public void removeUserFromAllTables_removesData() throws Exception {
@@ -439,7 +464,7 @@
}
@Test
- public void testInvalidateKeysWithOldGenerationId_withSingleKey() {
+ public void testInvalidateKeysForUser_withSingleKey() {
int userId = 12;
int uid = 1009;
int generationId = 6;
@@ -458,7 +483,7 @@
assertThat(retrievedKey.getRecoveryStatus()).isEqualTo(status);
mRecoverableKeyStoreDb.setRecoveryStatus(uid, alias, status2);
- mRecoverableKeyStoreDb.invalidateKeysWithOldGenerationId(userId, generationId + 1);
+ mRecoverableKeyStoreDb.invalidateKeysForUser(userId);
retrievedKey = mRecoverableKeyStoreDb.getKey(uid, alias);
assertThat(retrievedKey.getRecoveryStatus())
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index 99b827c..bdc46ec 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -263,6 +263,7 @@
private static final int INVALID_CARRIER_CONFIG_VALUE = -9999;
private long mDefaultWarningBytes; // filled in with the actual default before tests are run
private long mDefaultLimitBytes; // filled in with the actual default before tests are run
+ private PersistableBundle mCarrierConfig = CarrierConfigManager.getDefaultConfig();
private static final int APP_ID_A = android.os.Process.FIRST_APPLICATION_UID + 4;
private static final int APP_ID_B = android.os.Process.FIRST_APPLICATION_UID + 8;
@@ -409,6 +410,9 @@
doNothing().when(mConnectivityManager)
.registerNetworkCallback(any(), mNetworkCallbackCaptor.capture());
+ // Create the expected carrier config
+ mCarrierConfig.putBoolean(CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true);
+
// Prepare NPMS.
mService.systemReady(mService.networkScoreAndNetworkManagementServiceReady());
@@ -1086,6 +1090,25 @@
isA(Notification.class), eq(UserHandle.ALL));
}
+ // Push over warning, but with a config that isn't from an identified carrier
+ {
+ history.clear();
+ history.recordData(start, end,
+ new NetworkStats.Entry(DataUnit.MEGABYTES.toBytes(1799), 0L, 0L, 0L, 0));
+
+ reset(mTelephonyManager, mNetworkManager, mNotifManager);
+ expectMobileDefaults();
+ expectDefaultCarrierConfig();
+
+ mService.updateNetworks();
+
+ verify(mTelephonyManager, atLeastOnce()).setPolicyDataEnabled(true, TEST_SUB_ID);
+ verify(mNetworkManager, atLeastOnce()).setInterfaceQuota(TEST_IFACE,
+ DataUnit.MEGABYTES.toBytes(1800 - 1799));
+ // Since this isn't from the identified carrier, there should be no notifications
+ verify(mNotifManager, never()).notifyAsUser(any(), anyInt(), any(), any());
+ }
+
// Push over limit
{
history.clear();
@@ -1812,7 +1835,7 @@
private void expectNetworkState(boolean roaming) throws Exception {
when(mCarrierConfigManager.getConfigForSubId(eq(TEST_SUB_ID)))
- .thenReturn(CarrierConfigManager.getDefaultConfig());
+ .thenReturn(mCarrierConfig);
when(mConnManager.getAllNetworkState()).thenReturn(new NetworkState[] {
new NetworkState(buildNetworkInfo(),
buildLinkProperties(TEST_IFACE),
@@ -1821,10 +1844,16 @@
});
}
+ private void expectDefaultCarrierConfig() throws Exception {
+ when(mCarrierConfigManager.getConfigForSubId(eq(TEST_SUB_ID)))
+ .thenReturn(CarrierConfigManager.getDefaultConfig());
+ }
+
private void expectMobileDefaults() throws Exception {
when(mSubscriptionManager.getActiveSubscriptionIdList()).thenReturn(
new int[] { TEST_SUB_ID });
when(mTelephonyManager.getSubscriberId(TEST_SUB_ID)).thenReturn(TEST_IMSI);
+ doNothing().when(mTelephonyManager).setPolicyDataEnabled(anyBoolean(), anyInt());
expectNetworkState(false /* roaming */);
}
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 cbca087..3ce1317 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -62,6 +62,7 @@
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
@@ -96,6 +97,7 @@
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
+import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.drawable.Icon;
@@ -327,6 +329,8 @@
LocalServices.removeServiceForTest(WindowManagerInternal.class);
LocalServices.addService(WindowManagerInternal.class, mWindowManagerInternal);
+ doNothing().when(mContext).sendBroadcastAsUser(any(), any(), any());
+
mService = new TestableNotificationManagerService(mContext);
// Use this testable looper.
@@ -375,20 +379,16 @@
when(mAssistants.isAdjustmentAllowed(anyString())).thenReturn(true);
- try {
- mService.init(mTestableLooper.getLooper(),
- mPackageManager, mPackageManagerClient, mockLightsManager,
- mListeners, mAssistants, mConditionProviders,
- mCompanionMgr, mSnoozeHelper, mUsageStats, mPolicyFile, mActivityManager,
- mGroupHelper, mAm, mAppUsageStats,
- mock(DevicePolicyManagerInternal.class), mUgm, mUgmInternal,
- mAppOpsManager, mUm);
- mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
- } catch (SecurityException e) {
- if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
- throw e;
- }
- }
+
+ mService.init(mTestableLooper.getLooper(),
+ mPackageManager, mPackageManagerClient, mockLightsManager,
+ mListeners, mAssistants, mConditionProviders,
+ mCompanionMgr, mSnoozeHelper, mUsageStats, mPolicyFile, mActivityManager,
+ mGroupHelper, mAm, mAppUsageStats,
+ mock(DevicePolicyManagerInternal.class), mUgm, mUgmInternal,
+ mAppOpsManager, mUm);
+ mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
+
mService.setAudioManager(mAudioManager);
// Tests call directly into the Binder.
@@ -2080,14 +2080,8 @@
public void testSetListenerAccessForUser() throws Exception {
UserHandle user = UserHandle.of(10);
ComponentName c = ComponentName.unflattenFromString("package/Component");
- try {
- mBinderService.setNotificationListenerAccessGrantedForUser(
- c, user.getIdentifier(), true);
- } catch (SecurityException e) {
- if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
- throw e;
- }
- }
+ mBinderService.setNotificationListenerAccessGrantedForUser(c, user.getIdentifier(), true);
+
verify(mContext, times(1)).sendBroadcastAsUser(any(), eq(user), any());
verify(mListeners, times(1)).setPackageOrComponentEnabled(
@@ -2101,15 +2095,14 @@
@Test
public void testSetAssistantAccessForUser() throws Exception {
UserHandle user = UserHandle.of(10);
+ List<UserInfo> uis = new ArrayList<>();
+ UserInfo ui = new UserInfo();
+ ui.id = 10;
+ uis.add(ui);
ComponentName c = ComponentName.unflattenFromString("package/Component");
- try {
- mBinderService.setNotificationAssistantAccessGrantedForUser(
- c, user.getIdentifier(), true);
- } catch (SecurityException e) {
- if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
- throw e;
- }
- }
+ when(mUm.getEnabledProfiles(10)).thenReturn(uis);
+
+ mBinderService.setNotificationAssistantAccessGrantedForUser(c, user.getIdentifier(), true);
verify(mContext, times(1)).sendBroadcastAsUser(any(), eq(user), any());
verify(mAssistants, times(1)).setPackageOrComponentEnabled(
@@ -2150,14 +2143,8 @@
public void testSetDndAccessForUser() throws Exception {
UserHandle user = UserHandle.of(10);
ComponentName c = ComponentName.unflattenFromString("package/Component");
- try {
- mBinderService.setNotificationPolicyAccessGrantedForUser(
- c.getPackageName(), user.getIdentifier(), true);
- } catch (SecurityException e) {
- if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
- throw e;
- }
- }
+ mBinderService.setNotificationPolicyAccessGrantedForUser(
+ c.getPackageName(), user.getIdentifier(), true);
verify(mContext, times(1)).sendBroadcastAsUser(any(), eq(user), any());
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
@@ -2171,13 +2158,7 @@
@Test
public void testSetListenerAccess() throws Exception {
ComponentName c = ComponentName.unflattenFromString("package/Component");
- try {
- mBinderService.setNotificationListenerAccessGranted(c, true);
- } catch (SecurityException e) {
- if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
- throw e;
- }
- }
+ mBinderService.setNotificationListenerAccessGranted(c, true);
verify(mListeners, times(1)).setPackageOrComponentEnabled(
c.flattenToString(), 0, true, true);
@@ -2189,14 +2170,14 @@
@Test
public void testSetAssistantAccess() throws Exception {
+ List<UserInfo> uis = new ArrayList<>();
+ UserInfo ui = new UserInfo();
+ ui.id = 0;
+ uis.add(ui);
+ when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
ComponentName c = ComponentName.unflattenFromString("package/Component");
- try {
- mBinderService.setNotificationAssistantAccessGranted(c, true);
- } catch (SecurityException e) {
- if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
- throw e;
- }
- }
+
+ mBinderService.setNotificationAssistantAccessGranted(c, true);
verify(mAssistants, times(1)).setPackageOrComponentEnabled(
c.flattenToString(), 0, true, true);
@@ -2207,19 +2188,44 @@
}
@Test
+ public void testSetAssistantAccess_multiProfile() throws Exception {
+ List<UserInfo> uis = new ArrayList<>();
+ UserInfo ui = new UserInfo();
+ ui.id = 0;
+ uis.add(ui);
+ UserInfo ui10 = new UserInfo();
+ ui10.id = 10;
+ uis.add(ui10);
+ when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
+ ComponentName c = ComponentName.unflattenFromString("package/Component");
+
+ mBinderService.setNotificationAssistantAccessGranted(c, true);
+
+ verify(mAssistants, times(1)).setPackageOrComponentEnabled(
+ c.flattenToString(), 0, true, true);
+ verify(mAssistants, times(1)).setPackageOrComponentEnabled(
+ c.flattenToString(), 10, true, true);
+ verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
+ c.flattenToString(), 0, false, true);
+ verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
+ c.flattenToString(), 10, false, true);
+ verify(mListeners, never()).setPackageOrComponentEnabled(
+ any(), anyInt(), anyBoolean(), anyBoolean());
+ }
+
+ @Test
public void testSetAssistantAccess_nullWithAllowedAssistant() throws Exception {
ArrayList<ComponentName> componentList = new ArrayList<>();
ComponentName c = ComponentName.unflattenFromString("package/Component");
componentList.add(c);
when(mAssistants.getAllowedComponents(anyInt())).thenReturn(componentList);
+ List<UserInfo> uis = new ArrayList<>();
+ UserInfo ui = new UserInfo();
+ ui.id = 0;
+ uis.add(ui);
+ when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
- try {
- mBinderService.setNotificationAssistantAccessGranted(null, true);
- } catch (SecurityException e) {
- if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
- throw e;
- }
- }
+ mBinderService.setNotificationAssistantAccessGranted(null, true);
verify(mAssistants, times(1)).setPackageOrComponentEnabled(
c.flattenToString(), 0, true, false);
@@ -2231,23 +2237,23 @@
@Test
public void testSetAssistantAccessForUser_nullWithAllowedAssistant() throws Exception {
- UserHandle user = UserHandle.of(10);
+ List<UserInfo> uis = new ArrayList<>();
+ UserInfo ui = new UserInfo();
+ ui.id = 10;
+ uis.add(ui);
+ UserHandle user = ui.getUserHandle();
ArrayList<ComponentName> componentList = new ArrayList<>();
ComponentName c = ComponentName.unflattenFromString("package/Component");
componentList.add(c);
when(mAssistants.getAllowedComponents(anyInt())).thenReturn(componentList);
+ when(mUm.getEnabledProfiles(10)).thenReturn(uis);
- try {
- mBinderService.setNotificationAssistantAccessGrantedForUser(
- null, user.getIdentifier(), true);
- } catch (SecurityException e) {
- if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
- throw e;
- }
- }
+ mBinderService.setNotificationAssistantAccessGrantedForUser(
+ null, user.getIdentifier(), true);
verify(mAssistants, times(1)).setPackageOrComponentEnabled(
c.flattenToString(), user.getIdentifier(), true, false);
+ verify(mAssistants).setUserSet(10, true);
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
c.flattenToString(), user.getIdentifier(), false, false);
verify(mListeners, never()).setPackageOrComponentEnabled(
@@ -2255,15 +2261,44 @@
}
@Test
+ public void testSetAssistantAccessForUser_workProfile_nullWithAllowedAssistant()
+ throws Exception {
+ List<UserInfo> uis = new ArrayList<>();
+ UserInfo ui = new UserInfo();
+ ui.id = 0;
+ uis.add(ui);
+ UserInfo ui10 = new UserInfo();
+ ui10.id = 10;
+ uis.add(ui10);
+ UserHandle user = ui.getUserHandle();
+ ArrayList<ComponentName> componentList = new ArrayList<>();
+ ComponentName c = ComponentName.unflattenFromString("package/Component");
+ componentList.add(c);
+ when(mAssistants.getAllowedComponents(anyInt())).thenReturn(componentList);
+ when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
+
+ mBinderService.setNotificationAssistantAccessGrantedForUser(
+ null, user.getIdentifier(), true);
+
+ verify(mAssistants, times(1)).setPackageOrComponentEnabled(
+ c.flattenToString(), user.getIdentifier(), true, false);
+ verify(mAssistants, times(1)).setPackageOrComponentEnabled(
+ c.flattenToString(), ui10.id, true, false);
+ verify(mAssistants).setUserSet(0, true);
+ verify(mAssistants).setUserSet(10, true);
+ verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
+ c.flattenToString(), user.getIdentifier(), false, false);
+ verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
+ c.flattenToString(), ui10.id, false, false);
+ verify(mListeners, never()).setPackageOrComponentEnabled(
+ any(), anyInt(), anyBoolean(), anyBoolean());
+ }
+
+ @Test
public void testSetDndAccess() throws Exception {
ComponentName c = ComponentName.unflattenFromString("package/Component");
- try {
- mBinderService.setNotificationPolicyAccessGranted(c.getPackageName(), true);
- } catch (SecurityException e) {
- if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
- throw e;
- }
- }
+
+ mBinderService.setNotificationPolicyAccessGranted(c.getPackageName(), true);
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
c.getPackageName(), 0, true, true);
@@ -2291,6 +2326,12 @@
public void testSetAssistantAccess_doesNothingOnLowRam() throws Exception {
when(mActivityManager.isLowRamDevice()).thenReturn(true);
ComponentName c = ComponentName.unflattenFromString("package/Component");
+ List<UserInfo> uis = new ArrayList<>();
+ UserInfo ui = new UserInfo();
+ ui.id = 0;
+ uis.add(ui);
+ when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
+
mBinderService.setNotificationAssistantAccessGranted(c, true);
verify(mListeners, never()).setPackageOrComponentEnabled(
@@ -2320,13 +2361,8 @@
when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(true);
when(mActivityManager.isLowRamDevice()).thenReturn(true);
ComponentName c = ComponentName.unflattenFromString("package/Component");
- try {
- mBinderService.setNotificationListenerAccessGranted(c, true);
- } catch (SecurityException e) {
- if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
- throw e;
- }
- }
+
+ mBinderService.setNotificationListenerAccessGranted(c, true);
verify(mListeners, times(1)).setPackageOrComponentEnabled(
c.flattenToString(), 0, true, true);
@@ -2341,13 +2377,13 @@
when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(true);
when(mActivityManager.isLowRamDevice()).thenReturn(true);
ComponentName c = ComponentName.unflattenFromString("package/Component");
- try {
- mBinderService.setNotificationAssistantAccessGranted(c, true);
- } catch (SecurityException e) {
- if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
- throw e;
- }
- }
+ List<UserInfo> uis = new ArrayList<>();
+ UserInfo ui = new UserInfo();
+ ui.id = 0;
+ uis.add(ui);
+ when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
+
+ mBinderService.setNotificationAssistantAccessGranted(c, true);
verify(mListeners, never()).setPackageOrComponentEnabled(
anyString(), anyInt(), anyBoolean(), anyBoolean());
@@ -2362,13 +2398,8 @@
when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(true);
when(mActivityManager.isLowRamDevice()).thenReturn(true);
ComponentName c = ComponentName.unflattenFromString("package/Component");
- try {
- mBinderService.setNotificationPolicyAccessGranted(c.getPackageName(), true);
- } catch (SecurityException e) {
- if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
- throw e;
- }
- }
+
+ mBinderService.setNotificationPolicyAccessGranted(c.getPackageName(), true);
verify(mListeners, never()).setPackageOrComponentEnabled(
anyString(), anyInt(), anyBoolean(), anyBoolean());
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index afd4ec1..2991dff 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -41,6 +41,7 @@
import android.app.ActivityManagerInternal;
import android.app.ActivityOptions;
+import android.app.AppOpsManager;
import android.app.IApplicationThread;
import android.content.ComponentName;
import android.content.Context;
@@ -413,12 +414,18 @@
ActivityStackSupervisor mTestStackSupervisor;
ActivityDisplay mDefaultDisplay;
+ AppOpsService mAppOpsService;
TestActivityTaskManagerService(Context context) {
super(context);
spyOn(this);
mUgmInternal = mock(UriGrantsManagerInternal.class);
+ mAppOpsService = mock(AppOpsService.class);
+
+ // Make sure permission checks aren't overridden.
+ doReturn(AppOpsManager.MODE_DEFAULT)
+ .when(mAppOpsService).noteOperation(anyInt(), anyInt(), anyString());
mSupportsMultiWindow = true;
mSupportsMultiDisplay = true;
@@ -482,6 +489,11 @@
}
@Override
+ AppOpsService getAppOpsService() {
+ return mAppOpsService;
+ }
+
+ @Override
void updateCpuStats() {
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java b/services/tests/wmtests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java
index 380f7c6..5cd649f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java
@@ -27,6 +27,7 @@
import android.platform.test.annotations.Presubmit;
+import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import org.junit.Before;
@@ -80,6 +81,7 @@
}
@Test
+ @FlakyTest(bugId = 131005232)
public void testContainerRemoved() {
final AppWindowToken window1 = createAppWindowToken(mDisplayContent,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
index 83c0af9..777e4f4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
@@ -38,6 +38,7 @@
import android.view.RemoteAnimationDefinition;
import android.view.RemoteAnimationTarget;
+import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import org.junit.Test;
@@ -96,6 +97,7 @@
}
@Test
+ @FlakyTest(bugId = 131005232)
public void testModeChangeRemoteAnimatorNoSnapshot() {
// setup currently defaults to no snapshot.
setUpOnDisplay(mDisplayContent);
@@ -113,6 +115,7 @@
}
@Test
+ @FlakyTest(bugId = 131005232)
public void testCancelPendingChangeOnRemove() {
// setup currently defaults to no snapshot.
setUpOnDisplay(mDisplayContent);
@@ -132,6 +135,7 @@
}
@Test
+ @FlakyTest(bugId = 131005232)
public void testNoChangeWhenMoveDisplay() {
mDisplayContent.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
final DisplayContent dc1 = createNewDisplay(Display.STATE_ON);
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
index b1ffbbd..2d1dd39 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -31,6 +31,7 @@
import android.platform.test.annotations.Presubmit;
import android.view.WindowManager;
+import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import org.junit.Before;
@@ -52,6 +53,7 @@
}
@Test
+ @FlakyTest(bugId = 131005232)
public void testTranslucentOpen() {
synchronized (mWm.mGlobalLock) {
final AppWindowToken behind = createAppWindowToken(mDisplayContent,
@@ -69,6 +71,7 @@
}
@Test
+ @FlakyTest(bugId = 131005232)
public void testTranslucentClose() {
synchronized (mWm.mGlobalLock) {
final AppWindowToken behind = createAppWindowToken(mDisplayContent,
@@ -84,6 +87,7 @@
}
@Test
+ @FlakyTest(bugId = 131005232)
public void testChangeIsNotOverwritten() {
synchronized (mWm.mGlobalLock) {
final AppWindowToken behind = createAppWindowToken(mDisplayContent,
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
index 6e09167..9cdea9a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -39,6 +39,7 @@
import org.junit.Before;
import org.junit.Test;
+import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
/**
@@ -78,6 +79,7 @@
}
@Test
+ @FlakyTest(bugId = 131005232)
public void testForceOverride() {
mWm.prepareAppTransition(TRANSIT_KEYGUARD_UNOCCLUDE, false /* alwaysKeepCurrent */);
mDc.prepareAppTransition(TRANSIT_ACTIVITY_OPEN,
@@ -93,6 +95,7 @@
}
@Test
+ @FlakyTest(bugId = 131005232)
public void testKeepKeyguard_withCrashing() {
mWm.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, false /* alwaysKeepCurrent */);
mWm.prepareAppTransition(TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
@@ -100,6 +103,7 @@
}
@Test
+ @FlakyTest(bugId = 131005232)
public void testAppTransitionStateForMultiDisplay() {
// Create 2 displays & presume both display the state is ON for ready to display & animate.
final DisplayContent dc1 = createNewDisplay(Display.STATE_ON);
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowThumbnailTest.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowThumbnailTest.java
index fa0c384..b8f8e21 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowThumbnailTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowThumbnailTest.java
@@ -28,6 +28,7 @@
import android.view.Surface;
import android.view.SurfaceControl;
+import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import org.junit.Test;
@@ -53,6 +54,7 @@
}
@Test
+ @FlakyTest(bugId = 131005232)
public void testDestroy_nullsSurface() {
final AppWindowThumbnail t = buildThumbnail();
assertNotNull(t.getSurfaceControl());
diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
index 196cc21..0110e94 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
@@ -39,6 +39,7 @@
import android.view.SurfaceSession;
import android.view.View;
+import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import com.android.server.LocalServices;
@@ -146,16 +147,19 @@
}
@Test
+ @FlakyTest(bugId = 131005232)
public void testDragFlow() {
dragFlow(0, ClipData.newPlainText("label", "Test"), 0, 0);
}
@Test
+ @FlakyTest(bugId = 131005232)
public void testPerformDrag_NullDataWithGrantUri() {
dragFlow(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_READ, null, 0, 0);
}
@Test
+ @FlakyTest(bugId = 131005232)
public void testPerformDrag_NullDataToOtherUser() {
final WindowState otherUsersWindow =
createDropTargetWindow("Other user's window", 1 * UserHandle.PER_USER_RANGE);
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
index a0546d7..86ee75e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
@@ -31,6 +31,7 @@
import android.view.InsetsSource;
import android.view.InsetsState;
+import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import org.junit.Before;
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
index 2d906d1..9fce78b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
@@ -58,6 +58,7 @@
}
@Test
+ @FlakyTest(bugId = 131005232)
public void testStripForDispatch_notOwn() {
final WindowState topBar = createWindow(null, TYPE_APPLICATION, "parentWindow");
final WindowState app = createWindow(null, TYPE_APPLICATION, "parentWindow");
diff --git a/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java b/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java
index b769fce..103c3ab 100644
--- a/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java
@@ -24,6 +24,7 @@
import android.platform.test.annotations.Presubmit;
import android.view.RemoteAnimationAdapter;
+import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import com.android.server.testutils.OffsettableClock;
@@ -73,6 +74,7 @@
}
@Test
+ @FlakyTest(bugId = 131005232)
public void testTimeout() {
mRegistry.addPendingAnimation("com.android.test", mAdapter);
mClock.fastForward(5000);
diff --git a/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java b/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java
index 4673992..027f903 100644
--- a/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java
@@ -110,6 +110,7 @@
}
@Test
+ @FlakyTest(bugId = 131005232)
public void testProcessOneItem_Flush() throws Exception {
mFactory.setExpectedProcessedItemNumber(1);
mListener.setExpectedOnPreProcessItemCallbackTimes(1);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index 0c2ce61..385748c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -21,6 +21,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.atLeast;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
@@ -166,6 +167,25 @@
verify(mAnimationCallbacks).onAnimationFinished(REORDER_KEEP_IN_PLACE, true, false);
}
+ @Test
+ public void testShouldAnimateWhenNoCancelWithDeferredScreenshot() {
+ mWm.setRecentsAnimationController(mController);
+ final AppWindowToken appWindow = createAppWindowToken(mDisplayContent,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ final WindowState win1 = createWindow(null, TYPE_BASE_APPLICATION, appWindow, "win1");
+ appWindow.addWindow(win1);
+ assertEquals(appWindow.getTask().getTopVisibleAppToken(), appWindow);
+ assertEquals(appWindow.findMainWindow(), win1);
+
+ mController.addAnimation(appWindow.getTask(), false /* isRecentTaskInvisible */);
+ assertTrue(mController.isAnimatingTask(appWindow.getTask()));
+
+ // Assume appWindow transition should animate when no
+ // IRecentsAnimationController#setCancelWithDeferredScreenshot called.
+ assertFalse(mController.shouldCancelWithDeferredScreenshot());
+ assertTrue(appWindow.shouldAnimate(TRANSIT_ACTIVITY_CLOSE));
+ }
+
private static void verifyNoMoreInteractionsExceptAsBinder(IInterface binder) {
verify(binder, atLeast(0)).asBinder();
verifyNoMoreInteractions(binder);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index 6d27e6d..bac1ecd 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -31,7 +31,6 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.server.wm.ActivityDisplay.POSITION_TOP;
@@ -56,7 +55,6 @@
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ResolveInfo;
-import android.content.res.Resources;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.util.Pair;
@@ -539,71 +537,6 @@
}
/**
- * Tests that the default secondary home activity is always picked when it is in forced by
- * config_useSystemProvidedLauncherForSecondary.
- */
- @Test
- public void testResolveSecondaryHomeActivityForced() {
- Resources resources = mContext.getResources();
- spyOn(resources);
- final String defaultSecondaryHome =
- "com.android.test/com.android.test.TestDefaultSecondaryHome";
- final ComponentName secondaryComp = ComponentName.unflattenFromString(defaultSecondaryHome);
- doReturn(defaultSecondaryHome).when(resources).getString(
- com.android.internal.R.string.config_secondaryHomeComponent);
- doReturn(true).when(resources).getBoolean(
- com.android.internal.R.bool.config_useSystemProvidedLauncherForSecondary);
-
- final Intent secondaryHomeIntent = mService.getSecondaryHomeIntent(null);
- assertEquals(secondaryComp, secondaryHomeIntent.getComponent());
-
- final ActivityInfo aInfoSecondary = new ActivityInfo();
- aInfoSecondary.name = secondaryComp.getClassName();
- aInfoSecondary.applicationInfo = new ApplicationInfo();
- aInfoSecondary.applicationInfo.packageName = secondaryComp.getPackageName();
- doReturn(aInfoSecondary).when(mRootActivityContainer).resolveHomeActivity(anyInt(),
- refEq(secondaryHomeIntent));
-
- final Intent homeIntent = mService.getHomeIntent();
- final ActivityInfo aInfoDefault = new ActivityInfo();
- aInfoDefault.name = "fakeHomeActivity";
- aInfoDefault.applicationInfo = new ApplicationInfo();
- aInfoDefault.applicationInfo.packageName = "fakeHomePackage";
- doReturn(aInfoDefault).when(mRootActivityContainer).resolveHomeActivity(anyInt(),
- refEq(homeIntent));
-
- // Let resolveActivities call to validate both main launcher and second launcher so that
- // resolveActivities call does not work as enabler for secondary.
- final List<ResolveInfo> resolutions1 = new ArrayList<>();
- final ResolveInfo resolveInfo1 = new ResolveInfo();
- resolveInfo1.activityInfo = new ActivityInfo();
- resolveInfo1.activityInfo.name = aInfoDefault.name;
- resolveInfo1.activityInfo.applicationInfo = aInfoDefault.applicationInfo;
- resolutions1.add(resolveInfo1);
- doReturn(resolutions1).when(mRootActivityContainer).resolveActivities(anyInt(),
- refEq(homeIntent));
- final List<ResolveInfo> resolutions2 = new ArrayList<>();
- final ResolveInfo resolveInfo2 = new ResolveInfo();
- resolveInfo2.activityInfo = new ActivityInfo();
- resolveInfo2.activityInfo.name = aInfoSecondary.name;
- resolveInfo2.activityInfo.applicationInfo = aInfoSecondary.applicationInfo;
- resolutions2.add(resolveInfo2);
- doReturn(resolutions2).when(mRootActivityContainer).resolveActivities(anyInt(),
- refEq(secondaryHomeIntent));
-
- doReturn(true).when(mRootActivityContainer).canStartHomeOnDisplay(
- any(), anyInt(), anyBoolean());
-
- final Pair<ActivityInfo, Intent> resolvedInfo = mRootActivityContainer
- .resolveSecondaryHomeActivity(0 /* userId */, 1 /* displayId */);
-
- assertEquals(secondaryComp.getClassName(), resolvedInfo.first.name);
- assertEquals(secondaryComp.getPackageName(),
- resolvedInfo.first.applicationInfo.packageName);
- assertEquals(aInfoSecondary.name, resolvedInfo.first.name);
- }
-
- /**
* Tests that secondary home should be selected if default home not support secondary displays
* or there is no matched activity in the same package as selected default home.
*/
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java
index 9dfeadf..9fc1602 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java
@@ -29,6 +29,8 @@
import android.platform.test.annotations.Presubmit;
import android.util.SparseBooleanArray;
+import androidx.test.filters.FlakyTest;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -72,6 +74,7 @@
}
@Test
+ @FlakyTest(bugId = 131005232)
public void testTaskIdsPersistence() {
SparseBooleanArray taskIdsOnFile = new SparseBooleanArray();
for (int i = 0; i < 100; i++) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 715353e..98d055c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -476,4 +476,21 @@
root.prepareWindowToDisplayDuringRelayout(wasVisible /*wasVisible*/);
verify(sPowerManagerWrapper).wakeUp(anyLong(), anyInt(), anyString());
}
+
+ @Test
+ public void testVisibilityChangeSwitchUser() {
+ final WindowState window = createWindow(null, TYPE_APPLICATION, "app");
+ window.mHasSurface = true;
+ window.setShowToOwnerOnlyLocked(true);
+
+ mWm.mCurrentUserId = 1;
+ window.switchUser();
+ assertFalse(window.isVisible());
+ assertFalse(window.isVisibleByPolicy());
+
+ mWm.mCurrentUserId = 0;
+ window.switchUser();
+ assertTrue(window.isVisible());
+ assertTrue(window.isVisibleByPolicy());
+ }
}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerLogger.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerLogger.java
new file mode 100644
index 0000000..73b4ce7
--- /dev/null
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerLogger.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.soundtrigger;
+
+import android.util.Log;
+
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.LinkedList;
+
+/**
+* Constructor SoundTriggerLogger class
+*/
+public class SoundTriggerLogger {
+
+ // ring buffer of events to log.
+ private final LinkedList<Event> mEvents;
+
+ private final String mTitle;
+
+ // the maximum number of events to keep in log
+ private final int mMemSize;
+
+ /**
+ * Constructor for Event class.
+ */
+ public abstract static class Event {
+ // formatter for timestamps
+ private static final SimpleDateFormat sFormat = new SimpleDateFormat("MM-dd HH:mm:ss:SSS");
+
+ private final long mTimestamp;
+
+ Event() {
+ mTimestamp = System.currentTimeMillis();
+ }
+
+ /**
+ * Convert event to String
+ * @return StringBuilder
+ */
+ public String toString() {
+ return (new StringBuilder(sFormat.format(new Date(mTimestamp))))
+ .append(" ").append(eventToString()).toString();
+ }
+
+ /**
+ * Causes the string message for the event to appear in the logcat.
+ * Here is an example of how to create a new event (a StringEvent), adding it to the logger
+ * (an instance of SoundTriggerLogger) while also making it show in the logcat:
+ * <pre>
+ * myLogger.log(
+ * (new StringEvent("something for logcat and logger")).printLog(MyClass.TAG) );
+ * </pre>
+ * @param tag the tag for the android.util.Log.v
+ * @return the same instance of the event
+ */
+ public Event printLog(String tag) {
+ Log.i(tag, eventToString());
+ return this;
+ }
+
+ /**
+ * Convert event to String.
+ * This method is only called when the logger history is about to the dumped,
+ * so this method is where expensive String conversions should be made, not when the Event
+ * subclass is created.
+ * Timestamp information will be automatically added, do not include it.
+ * @return a string representation of the event that occurred.
+ */
+ public abstract String eventToString();
+ }
+
+ /**
+ * Constructor StringEvent class
+ */
+ public static class StringEvent extends Event {
+ private final String mMsg;
+
+ public StringEvent(String msg) {
+ mMsg = msg;
+ }
+
+ @Override
+ public String eventToString() {
+ return mMsg;
+ }
+ }
+
+ /**
+ * Constructor for logger.
+ * @param size the maximum number of events to keep in log
+ * @param title the string displayed before the recorded log
+ */
+ public SoundTriggerLogger(int size, String title) {
+ mEvents = new LinkedList<Event>();
+ mMemSize = size;
+ mTitle = title;
+ }
+
+ /**
+ * Constructor for logger.
+ * @param evt the maximum number of events to keep in log
+ */
+ public synchronized void log(Event evt) {
+ if (mEvents.size() >= mMemSize) {
+ mEvents.removeFirst();
+ }
+ mEvents.add(evt);
+ }
+
+ /**
+ * Constructor for logger.
+ * @param pw the maximum number of events to keep in log
+ */
+ public synchronized void dump(PrintWriter pw) {
+ pw.println("ST Event log: " + mTitle);
+ for (Event evt : mEvents) {
+ pw.println(evt.toString());
+ }
+ }
+}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
index 697469a..9c4c099 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -180,9 +180,16 @@
Slog.i(TAG, "startRecognition(): Uuid : " + parcelUuid);
}
+ sEventLogger.log(new SoundTriggerLogger.StringEvent("startRecognition(): Uuid : "
+ + parcelUuid));
+
GenericSoundModel model = getSoundModel(parcelUuid);
if (model == null) {
Slog.e(TAG, "Null model in database for id: " + parcelUuid);
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(
+ "startRecognition(): Null model in database for id: " + parcelUuid));
+
return STATUS_ERROR;
}
@@ -196,6 +203,10 @@
if (DEBUG) {
Slog.i(TAG, "stopRecognition(): Uuid : " + parcelUuid);
}
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent("stopRecognition(): Uuid : "
+ + parcelUuid));
+
if (!isInitialized()) return STATUS_ERROR;
return mSoundTriggerHelper.stopGenericRecognition(parcelUuid.getUuid(), callback);
}
@@ -206,6 +217,10 @@
if (DEBUG) {
Slog.i(TAG, "getSoundModel(): id = " + soundModelId);
}
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent("getSoundModel(): id = "
+ + soundModelId));
+
SoundTrigger.GenericSoundModel model = mDbHelper.getGenericSoundModel(
soundModelId.getUuid());
return model;
@@ -217,6 +232,10 @@
if (DEBUG) {
Slog.i(TAG, "updateSoundModel(): model = " + soundModel);
}
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent("updateSoundModel(): model = "
+ + soundModel));
+
mDbHelper.updateGenericSoundModel(soundModel);
}
@@ -226,6 +245,10 @@
if (DEBUG) {
Slog.i(TAG, "deleteSoundModel(): id = " + soundModelId);
}
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent("deleteSoundModel(): id = "
+ + soundModelId));
+
// Unload the model if it is loaded.
mSoundTriggerHelper.unloadGenericSoundModel(soundModelId.getUuid());
mDbHelper.deleteGenericSoundModel(soundModelId.getUuid());
@@ -237,11 +260,19 @@
if (!isInitialized()) return STATUS_ERROR;
if (soundModel == null || soundModel.uuid == null) {
Slog.e(TAG, "Invalid sound model");
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(
+ "loadGenericSoundModel(): Invalid sound model"));
+
return STATUS_ERROR;
}
if (DEBUG) {
Slog.i(TAG, "loadGenericSoundModel(): id = " + soundModel.uuid);
}
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent("loadGenericSoundModel(): id = "
+ + soundModel.uuid));
+
synchronized (mLock) {
SoundModel oldModel = mLoadedModels.get(soundModel.uuid);
// If the model we're loading is actually different than what we had loaded, we
@@ -264,15 +295,28 @@
if (!isInitialized()) return STATUS_ERROR;
if (soundModel == null || soundModel.uuid == null) {
Slog.e(TAG, "Invalid sound model");
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(
+ "loadKeyphraseSoundModel(): Invalid sound model"));
+
return STATUS_ERROR;
}
if (soundModel.keyphrases == null || soundModel.keyphrases.length != 1) {
Slog.e(TAG, "Only one keyphrase per model is currently supported.");
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(
+ "loadKeyphraseSoundModel(): Only one keyphrase per model"
+ + " is currently supported."));
+
return STATUS_ERROR;
}
if (DEBUG) {
Slog.i(TAG, "loadKeyphraseSoundModel(): id = " + soundModel.uuid);
}
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent("loadKeyphraseSoundModel(): id = "
+ + soundModel.uuid));
+
synchronized (mLock) {
SoundModel oldModel = mLoadedModels.get(soundModel.uuid);
// If the model we're loading is actually different than what we had loaded, we
@@ -303,6 +347,9 @@
Slog.i(TAG, "startRecognition(): id = " + soundModelId);
}
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(
+ "startRecognitionForService(): id = " + soundModelId));
+
IRecognitionStatusCallback callback =
new RemoteSoundTriggerDetectionService(soundModelId.getUuid(), params,
detectionService, Binder.getCallingUserHandle(), config);
@@ -311,6 +358,10 @@
SoundModel soundModel = mLoadedModels.get(soundModelId.getUuid());
if (soundModel == null) {
Slog.e(TAG, soundModelId + " is not loaded");
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(
+ "startRecognitionForService():" + soundModelId + " is not loaded"));
+
return STATUS_ERROR;
}
IRecognitionStatusCallback existingCallback = null;
@@ -319,6 +370,11 @@
}
if (existingCallback != null) {
Slog.e(TAG, soundModelId + " is already running");
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(
+ "startRecognitionForService():"
+ + soundModelId + " is already running"));
+
return STATUS_ERROR;
}
int ret;
@@ -329,11 +385,19 @@
break;
default:
Slog.e(TAG, "Unknown model type");
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(
+ "startRecognitionForService(): Unknown model type"));
+
return STATUS_ERROR;
}
if (ret != STATUS_OK) {
Slog.e(TAG, "Failed to start model: " + ret);
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(
+ "startRecognitionForService(): Failed to start model:"));
+
return ret;
}
synchronized (mCallbacksLock) {
@@ -351,10 +415,18 @@
Slog.i(TAG, "stopRecognition(): id = " + soundModelId);
}
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(
+ "stopRecognitionForService(): id = " + soundModelId));
+
synchronized (mLock) {
SoundModel soundModel = mLoadedModels.get(soundModelId.getUuid());
if (soundModel == null) {
Slog.e(TAG, soundModelId + " is not loaded");
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(
+ "stopRecognitionForService(): " + soundModelId
+ + " is not loaded"));
+
return STATUS_ERROR;
}
IRecognitionStatusCallback callback = null;
@@ -363,6 +435,11 @@
}
if (callback == null) {
Slog.e(TAG, soundModelId + " is not running");
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(
+ "stopRecognitionForService(): " + soundModelId
+ + " is not running"));
+
return STATUS_ERROR;
}
int ret;
@@ -372,11 +449,19 @@
break;
default:
Slog.e(TAG, "Unknown model type");
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(
+ "stopRecognitionForService(): Unknown model type"));
+
return STATUS_ERROR;
}
if (ret != STATUS_OK) {
Slog.e(TAG, "Failed to stop model: " + ret);
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(
+ "stopRecognitionForService(): Failed to stop model: " + ret));
+
return ret;
}
synchronized (mCallbacksLock) {
@@ -394,10 +479,17 @@
Slog.i(TAG, "unloadSoundModel(): id = " + soundModelId);
}
+ sEventLogger.log(new SoundTriggerLogger.StringEvent("unloadSoundModel(): id = "
+ + soundModelId));
+
synchronized (mLock) {
SoundModel soundModel = mLoadedModels.get(soundModelId.getUuid());
if (soundModel == null) {
Slog.e(TAG, soundModelId + " is not loaded");
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(
+ "unloadSoundModel(): " + soundModelId + " is not loaded"));
+
return STATUS_ERROR;
}
int ret;
@@ -411,10 +503,18 @@
break;
default:
Slog.e(TAG, "Unknown model type");
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(
+ "unloadSoundModel(): Unknown model type"));
+
return STATUS_ERROR;
}
if (ret != STATUS_OK) {
Slog.e(TAG, "Failed to unload model");
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(
+ "unloadSoundModel(): Failed to unload model"));
+
return ret;
}
mLoadedModels.remove(soundModelId.getUuid());
@@ -444,10 +544,17 @@
Slog.i(TAG, "getModelState(): id = " + soundModelId);
}
+ sEventLogger.log(new SoundTriggerLogger.StringEvent("getModelState(): id = "
+ + soundModelId));
+
synchronized (mLock) {
SoundModel soundModel = mLoadedModels.get(soundModelId.getUuid());
if (soundModel == null) {
Slog.e(TAG, soundModelId + " is not loaded");
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent("getModelState(): "
+ + soundModelId + " is not loaded"));
+
return ret;
}
switch (soundModel.type) {
@@ -459,6 +566,10 @@
break;
default:
Slog.e(TAG, "Unknown model type");
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(
+ "getModelState(): Unknown model type"));
+
break;
}
@@ -708,6 +819,10 @@
mService.removeClient(mPuuid);
} catch (Exception e) {
Slog.e(TAG, mPuuid + ": Cannot remove client", e);
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(mPuuid
+ + ": Cannot remove client"));
+
}
mService = null;
@@ -730,6 +845,8 @@
private void destroy() {
if (DEBUG) Slog.v(TAG, mPuuid + ": destroy");
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(mPuuid + ": destroy"));
+
synchronized (mRemoteServiceLock) {
disconnectLocked();
@@ -761,6 +878,10 @@
} catch (Exception e) {
Slog.e(TAG, mPuuid + ": Could not stop operation "
+ mRunningOpIds.valueAt(i), e);
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(mPuuid
+ + ": Could not stop operation " + mRunningOpIds.valueAt(i)));
+
}
}
@@ -786,6 +907,10 @@
if (ri == null) {
Slog.w(TAG, mPuuid + ": " + mServiceName + " not found");
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(mPuuid
+ + ": " + mServiceName + " not found"));
+
return;
}
@@ -793,6 +918,11 @@
.equals(ri.serviceInfo.permission)) {
Slog.w(TAG, mPuuid + ": " + mServiceName + " does not require "
+ BIND_SOUND_TRIGGER_DETECTION_SERVICE);
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(mPuuid
+ + ": " + mServiceName + " does not require "
+ + BIND_SOUND_TRIGGER_DETECTION_SERVICE));
+
return;
}
@@ -803,6 +933,10 @@
mRemoteServiceWakeLock.acquire();
} else {
Slog.w(TAG, mPuuid + ": Could not bind to " + mServiceName);
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(mPuuid
+ + ": Could not bind to " + mServiceName));
+
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -821,6 +955,9 @@
Slog.w(TAG, mPuuid + ": Dropped operation as already destroyed or marked for "
+ "destruction");
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(mPuuid
+ + ":Dropped operation as already destroyed or marked for destruction"));
+
op.drop();
return;
}
@@ -847,11 +984,20 @@
if (DEBUG || opsAllowed + 10 > opsAdded) {
Slog.w(TAG, mPuuid + ": Dropped operation as too many operations "
+ "were run in last 24 hours");
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(mPuuid
+ + ": Dropped operation as too many operations "
+ + "were run in last 24 hours"));
+
}
op.drop();
} catch (Exception e) {
Slog.e(TAG, mPuuid + ": Could not drop operation", e);
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(mPuuid
+ + ": Could not drop operation"));
+
}
} else {
mNumOps.addOp(currentTime);
@@ -866,10 +1012,17 @@
try {
if (DEBUG) Slog.v(TAG, mPuuid + ": runOp " + opId);
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(mPuuid
+ + ": runOp " + opId));
+
op.run(opId, mService);
mRunningOpIds.add(opId);
} catch (Exception e) {
Slog.e(TAG, mPuuid + ": Could not run operation " + opId, e);
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(mPuuid
+ + ": Could not run operation " + opId));
+
}
}
@@ -897,6 +1050,10 @@
public void onKeyphraseDetected(SoundTrigger.KeyphraseRecognitionEvent event) {
Slog.w(TAG, mPuuid + "->" + mServiceName + ": IGNORED onKeyphraseDetected(" + event
+ ")");
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(mPuuid + "->" + mServiceName
+ + ": IGNORED onKeyphraseDetected(" + event + ")"));
+
}
/**
@@ -928,6 +1085,8 @@
: AudioFormat.CHANNEL_IN_MONO,
captureFormat.getEncoding());
+ sEventLogger.log(new SoundTriggerLogger.StringEvent("createAudioRecordForEvent"));
+
return new AudioRecord(attributes, captureFormat, bufferSize,
event.getCaptureSession());
}
@@ -936,6 +1095,9 @@
public void onGenericSoundTriggerDetected(SoundTrigger.GenericRecognitionEvent event) {
if (DEBUG) Slog.v(TAG, mPuuid + ": Generic sound trigger event: " + event);
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(mPuuid
+ + ": Generic sound trigger event: " + event));
+
runOrAddOperation(new Operation(
// always execute:
() -> {
@@ -966,6 +1128,9 @@
public void onError(int status) {
if (DEBUG) Slog.v(TAG, mPuuid + ": onError: " + status);
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(mPuuid
+ + ": onError: " + status));
+
runOrAddOperation(
new Operation(
// always execute:
@@ -985,17 +1150,28 @@
@Override
public void onRecognitionPaused() {
Slog.i(TAG, mPuuid + "->" + mServiceName + ": IGNORED onRecognitionPaused");
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(mPuuid
+ + "->" + mServiceName + ": IGNORED onRecognitionPaused"));
+
}
@Override
public void onRecognitionResumed() {
Slog.i(TAG, mPuuid + "->" + mServiceName + ": IGNORED onRecognitionResumed");
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(mPuuid
+ + "->" + mServiceName + ": IGNORED onRecognitionResumed"));
+
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
if (DEBUG) Slog.v(TAG, mPuuid + ": onServiceConnected(" + service + ")");
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(mPuuid
+ + ": onServiceConnected(" + service + ")"));
+
synchronized (mRemoteServiceLock) {
mService = ISoundTriggerDetectionService.Stub.asInterface(service);
@@ -1016,6 +1192,9 @@
public void onServiceDisconnected(ComponentName name) {
if (DEBUG) Slog.v(TAG, mPuuid + ": onServiceDisconnected");
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(mPuuid
+ + ": onServiceDisconnected"));
+
synchronized (mRemoteServiceLock) {
mService = null;
}
@@ -1025,6 +1204,9 @@
public void onBindingDied(ComponentName name) {
if (DEBUG) Slog.v(TAG, mPuuid + ": onBindingDied");
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(mPuuid
+ + ": onBindingDied"));
+
synchronized (mRemoteServiceLock) {
destroy();
}
@@ -1034,6 +1216,9 @@
public void onNullBinding(ComponentName name) {
Slog.w(TAG, name + " for model " + mPuuid + " returned a null binding");
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(name + " for model "
+ + mPuuid + " returned a null binding"));
+
synchronized (mRemoteServiceLock) {
disconnectLocked();
}
@@ -1082,11 +1267,17 @@
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!isInitialized()) return;
mSoundTriggerHelper.dump(fd, pw, args);
+ // log
+ sEventLogger.dump(pw);
}
private synchronized boolean isInitialized() {
if (mSoundTriggerHelper == null ) {
Slog.e(TAG, "SoundTriggerHelper not initialized.");
+
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(
+ "SoundTriggerHelper not initialized."));
+
return false;
}
return true;
@@ -1099,4 +1290,11 @@
throw new SecurityException("Caller does not hold the permission " + permission);
}
}
+
+ //=================================================================
+ // For logging
+
+ private static final SoundTriggerLogger sEventLogger = new SoundTriggerLogger(200,
+ "SoundTrigger activity");
+
}
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index a814c03..5cd46ca 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -301,4 +301,9 @@
void setTestAutoModeApp(String packageName);
+ /**
+ * @see TelecomServiceImpl#setTestDefaultDialer
+ */
+ void setTestDefaultDialer(in String packageName);
+
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 2d8a280..69500d7 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -3313,7 +3313,7 @@
});
sDefaults.putStringArray(KEY_EMERGENCY_NUMBER_PREFIX_STRING_ARRAY, new String[0]);
sDefaults.putBoolean(KEY_USE_USIM_BOOL, false);
- sDefaults.putBoolean(KEY_SHOW_WFC_LOCATION_PRIVACY_POLICY_BOOL, true);
+ sDefaults.putBoolean(KEY_SHOW_WFC_LOCATION_PRIVACY_POLICY_BOOL, false);
sDefaults.putBoolean(KEY_AUTO_CANCEL_CS_REJECT_NOTIFICATION, false);
sDefaults.putString(KEY_SMART_FORWARDING_CONFIG_COMPONENT_NAME_STRING, "");
sDefaults.putBoolean(KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN,
@@ -3371,8 +3371,7 @@
* May throw an {@link IllegalArgumentException} if {@code overrideValues} contains invalid
* values for the specified config keys.
*
- * NOTE: This API is meant for testing purposes only and may only be accessed from the shell UID
- * during instrumentation testing.
+ * NOTE: This API is meant for testing purposes only.
*
* @param subscriptionId The subscription ID for which the override should be done.
* @param overrideValues Key-value pairs of the values that are to be overridden. If set to
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 373c5d2..3ce28a4 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -38,6 +38,8 @@
import java.util.Map;
import java.util.concurrent.Executor;
+import dalvik.system.VMRuntime;
+
/**
* A listener class for monitoring changes in specific telephony states
* on the device, including service state, signal strength, message
@@ -400,8 +402,12 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public PhoneStateListener(Integer subId) {
this(subId, Looper.myLooper());
+ if (subId != null && VMRuntime.getRuntime().getTargetSdkVersion()
+ >= Build.VERSION_CODES.Q) {
+ throw new IllegalArgumentException("PhoneStateListener with subId: "
+ + subId + " is not supported, use default constructor");
+ }
}
-
/**
* Create a PhoneStateListener for the Phone using the specified subscription
* and non-null Looper.
@@ -410,6 +416,11 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public PhoneStateListener(Integer subId, Looper looper) {
this(subId, new HandlerExecutor(new Handler(looper)));
+ if (subId != null && VMRuntime.getRuntime().getTargetSdkVersion()
+ >= Build.VERSION_CODES.Q) {
+ throw new IllegalArgumentException("PhoneStateListener with subId: "
+ + subId + " is not supported, use default constructor");
+ }
}
/**
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index ccf49c9..903e533 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -108,6 +108,8 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import dalvik.system.VMRuntime;
+
/**
* Provides access to information about the telephony services on
* the device. Applications can use the methods in this class to
@@ -3321,7 +3323,7 @@
}
/**
- * Gets information about currently inserted UICCs and enabled eUICCs.
+ * Gets information about currently inserted UICCs and eUICCs.
* <p>
* Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
* <p>
@@ -4863,18 +4865,22 @@
* Registers a listener object to receive notification of changes
* in specified telephony states.
* <p>
- * To register a listener, pass a {@link PhoneStateListener}
- * and specify at least one telephony state of interest in
- * the events argument.
+ * To register a listener, pass a {@link PhoneStateListener} and specify at least one telephony
+ * state of interest in the events argument.
*
- * At registration, and when a specified telephony state
- * changes, the telephony manager invokes the appropriate
- * callback method on the listener object and passes the
- * current (updated) values.
+ * At registration, and when a specified telephony state changes, the telephony manager invokes
+ * the appropriate callback method on the listener object and passes the current (updated)
+ * values.
* <p>
- * To unregister a listener, pass the listener object and set the
- * events argument to
+ * To un-register a listener, pass the listener object and set the events argument to
* {@link PhoneStateListener#LISTEN_NONE LISTEN_NONE} (0).
+ *
+ * If this TelephonyManager object has been created with {@link #createForSubscriptionId},
+ * applies to the given subId. Otherwise, applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}. To listen events for multiple subIds,
+ * pass a separate listener object to each TelephonyManager object created with
+ * {@link #createForSubscriptionId}.
+ *
* Note: if you call this method while in the middle of a binder transaction, you <b>must</b>
* call {@link android.os.Binder#clearCallingIdentity()} before calling this method. A
* {@link SecurityException} will be thrown otherwise.
@@ -4889,17 +4895,26 @@
if (mContext == null) return;
try {
boolean notifyNow = (getITelephony() != null);
- // If the listener has not explicitly set the subId (for example, created with the
- // default constructor), replace the subId so it will listen to the account the
- // telephony manager is created with.
- if (listener.mSubId == null) {
- listener.mSubId = mSubId;
- }
-
ITelephonyRegistry registry = getTelephonyRegistry();
if (registry != null) {
- registry.listenForSubscriber(listener.mSubId, getOpPackageName(),
+ int subId;
+ // subId from phonestatelistner is deprecated Q on forward, use the subId from
+ // TelephonyManager instance.
+ if (VMRuntime.getRuntime().getTargetSdkVersion() >= Build.VERSION_CODES.Q
+ || listener.mSubId == null) {
+ subId = mSubId;
+ } else {
+ subId = listener.mSubId;
+ }
+
+ registry.listenForSubscriber(subId, getOpPackageName(),
listener.callback, events, notifyNow);
+ // TODO: remove this once we remove PhoneStateListener constructor with subId.
+ if (events == PhoneStateListener.LISTEN_NONE) {
+ listener.mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ } else {
+ listener.mSubId = subId;
+ }
} else {
Rlog.w(TAG, "telephony registry not ready.");
}
diff --git a/telephony/java/android/telephony/UiccCardInfo.java b/telephony/java/android/telephony/UiccCardInfo.java
index 2c98c4d..b438920 100644
--- a/telephony/java/android/telephony/UiccCardInfo.java
+++ b/telephony/java/android/telephony/UiccCardInfo.java
@@ -101,7 +101,7 @@
/**
* Get the embedded ID (EID) of the eUICC. If the UiccCardInfo is not an eUICC
- * (see {@link #isEuicc()}), returns null.
+ * (see {@link #isEuicc()}), or the EID is not available, returns null.
* <p>
* Note that this field may be omitted if the caller does not have the correct permissions
* (see {@link TelephonyManager#getUiccCardsInfo()}).
@@ -115,7 +115,7 @@
}
/**
- * Get the ICCID of the UICC.
+ * Get the ICCID of the UICC. If the ICCID is not availble, returns null.
* <p>
* Note that this field may be omitted if the caller does not have the correct permissions
* (see {@link TelephonyManager#getUiccCardsInfo()}).
diff --git a/telephony/java/android/telephony/UiccSlotInfo.java b/telephony/java/android/telephony/UiccSlotInfo.java
index 785d7ae..9a8d7cd 100644
--- a/telephony/java/android/telephony/UiccSlotInfo.java
+++ b/telephony/java/android/telephony/UiccSlotInfo.java
@@ -140,6 +140,10 @@
return mIsEuicc;
}
+ /**
+ * Returns the ICCID of a the UICC in the given slot, or the EID if it is an eUICC. Note that if
+ * the value is unavailble this will return null.
+ */
public String getCardId() {
return mCardId;
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 0169c26..f226bb1 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1594,7 +1594,7 @@
int getCardIdForDefaultEuicc(int subId, String callingPackage);
/**
- * Gets information about currently inserted UICCs and enabled eUICCs.
+ * Gets information about currently inserted UICCs and eUICCs.
* <p>
* Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
* <p>
diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
index 12b20ef..64c1830 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
@@ -419,7 +419,8 @@
// settings to individually disable the new restrictions for privileged, preloaded
// non-privileged, and non-preinstalled apps.
if (!isIdentifierCheckDisabled() && (
- (!isPreinstalled && !relax3PDeviceIdentifierCheck)
+ (isPrivApp && !relaxPrivDeviceIdentifierCheck)
+ || (!isPreinstalled && !relax3PDeviceIdentifierCheck)
|| (isPreinstalled && !isPrivApp && !relaxNonPrivDeviceIdentifierCheck))) {
// The current package should only be reported in StatsLog if it has not previously been
// reported for the currently invoked device identifier method.
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
index 13e737e..eb19361 100644
--- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -18,25 +18,27 @@
import static android.service.watchdog.ExplicitHealthCheckService.PackageConfig;
-import static com.android.server.PackageWatchdog.MonitoredPackage;
-import static com.android.server.PackageWatchdog.TRIGGER_FAILURE_COUNT;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import android.Manifest;
import android.content.Context;
import android.content.pm.VersionedPackage;
import android.os.Handler;
import android.os.test.TestLooper;
+import android.provider.DeviceConfig;
import android.util.AtomicFile;
import androidx.test.InstrumentationRegistry;
+import com.android.server.PackageWatchdog.MonitoredPackage;
import com.android.server.PackageWatchdog.PackageHealthObserver;
import com.android.server.PackageWatchdog.PackageHealthObserverImpact;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -73,8 +75,13 @@
public void setUp() throws Exception {
new File(InstrumentationRegistry.getContext().getFilesDir(),
"package-watchdog.xml").delete();
+ adoptShellPermissions(Manifest.permission.READ_DEVICE_CONFIG);
mTestLooper = new TestLooper();
- mTestLooper.startAutoDispatch();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ dropShellPermissions();
}
/**
@@ -204,7 +211,7 @@
// Verify random observer not saved returns null
assertNull(watchdog2.getPackages(new TestObserver(OBSERVER_NAME_3)));
- // Then regiser observer1
+ // Then register observer1
watchdog2.registerHealthObserver(observer1);
watchdog2.registerHealthObserver(observer2);
@@ -231,7 +238,7 @@
watchdog.startObservingHealth(observer1, Arrays.asList(APP_A), SHORT_DURATION);
// Then fail APP_A below the threshold
- for (int i = 0; i < TRIGGER_FAILURE_COUNT - 1; i++) {
+ for (int i = 0; i < watchdog.getTriggerFailureCount() - 1; i++) {
watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
}
@@ -258,7 +265,7 @@
watchdog.startObservingHealth(observer1, Arrays.asList(APP_B), SHORT_DURATION);
// Then fail APP_C (not observed) above the threshold
- for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
+ for (int i = 0; i < watchdog.getTriggerFailureCount(); i++) {
watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_C, VERSION_CODE)));
}
@@ -292,7 +299,7 @@
watchdog.startObservingHealth(observer, Arrays.asList(APP_A), SHORT_DURATION);
// Then fail APP_A (different version) above the threshold
- for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
+ for (int i = 0; i < watchdog.getTriggerFailureCount(); i++) {
watchdog.onPackageFailure(Arrays.asList(
new VersionedPackage(APP_A, differentVersionCode)));
}
@@ -331,7 +338,7 @@
SHORT_DURATION);
// Then fail all apps above the threshold
- for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
+ for (int i = 0; i < watchdog.getTriggerFailureCount(); i++) {
watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE),
new VersionedPackage(APP_B, VERSION_CODE),
new VersionedPackage(APP_C, VERSION_CODE),
@@ -384,7 +391,7 @@
watchdog.startObservingHealth(observerSecond, Arrays.asList(APP_A), LONG_DURATION);
// Then fail APP_A above the threshold
- for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
+ for (int i = 0; i < watchdog.getTriggerFailureCount(); i++) {
watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
}
// Run handler so package failures are dispatched to observers
@@ -401,7 +408,7 @@
observerSecond.mFailedPackages.clear();
// Then fail APP_A again above the threshold
- for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
+ for (int i = 0; i < watchdog.getTriggerFailureCount(); i++) {
watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
}
// Run handler so package failures are dispatched to observers
@@ -418,7 +425,7 @@
observerSecond.mFailedPackages.clear();
// Then fail APP_A again above the threshold
- for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
+ for (int i = 0; i < watchdog.getTriggerFailureCount(); i++) {
watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
}
// Run handler so package failures are dispatched to observers
@@ -435,7 +442,7 @@
observerSecond.mFailedPackages.clear();
// Then fail APP_A again above the threshold
- for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
+ for (int i = 0; i < watchdog.getTriggerFailureCount(); i++) {
watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
}
// Run handler so package failures are dispatched to observers
@@ -462,7 +469,7 @@
watchdog.startObservingHealth(observer1, Arrays.asList(APP_A), SHORT_DURATION);
// Then fail APP_A above the threshold
- for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
+ for (int i = 0; i < watchdog.getTriggerFailureCount(); i++) {
watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
}
@@ -539,6 +546,10 @@
*/
@Test
public void testExplicitHealthCheckStateChanges() throws Exception {
+ adoptShellPermissions(
+ Manifest.permission.WRITE_DEVICE_CONFIG,
+ Manifest.permission.READ_DEVICE_CONFIG);
+
TestController controller = new TestController();
PackageWatchdog watchdog = createWatchdog(controller, true /* withPackagesReady */);
TestObserver observer = new TestObserver(OBSERVER_NAME_1,
@@ -559,7 +570,7 @@
assertEquals(APP_B, requestedPackages.get(1));
// Disable explicit health checks (marks APP_A and APP_B as passed)
- watchdog.setExplicitHealthCheckEnabled(false);
+ setExplicitHealthCheckEnabled(false);
// Run handler so requests/cancellations are dispatched to the controller
mTestLooper.dispatchAll();
@@ -575,7 +586,7 @@
assertEquals(0, observer.mFailedPackages.size());
// Re-enable explicit health checks
- watchdog.setExplicitHealthCheckEnabled(true);
+ setExplicitHealthCheckEnabled(true);
// Run handler so requests/cancellations are dispatched to the controller
mTestLooper.dispatchAll();
@@ -643,11 +654,13 @@
/** Tests {@link MonitoredPackage} health check state transitions. */
@Test
public void testPackageHealthCheckStateTransitions() {
- MonitoredPackage m1 = new MonitoredPackage(APP_A, LONG_DURATION,
+ TestController controller = new TestController();
+ PackageWatchdog wd = createWatchdog(controller, true /* withPackagesReady */);
+ MonitoredPackage m1 = wd.new MonitoredPackage(APP_A, LONG_DURATION,
false /* hasPassedHealthCheck */);
- MonitoredPackage m2 = new MonitoredPackage(APP_B, LONG_DURATION, false);
- MonitoredPackage m3 = new MonitoredPackage(APP_C, LONG_DURATION, false);
- MonitoredPackage m4 = new MonitoredPackage(APP_D, LONG_DURATION, SHORT_DURATION, true);
+ MonitoredPackage m2 = wd.new MonitoredPackage(APP_B, LONG_DURATION, false);
+ MonitoredPackage m3 = wd.new MonitoredPackage(APP_C, LONG_DURATION, false);
+ MonitoredPackage m4 = wd.new MonitoredPackage(APP_D, LONG_DURATION, SHORT_DURATION, true);
// Verify transition: inactive -> active -> passed
// Verify initially inactive
@@ -683,6 +696,32 @@
assertEquals(MonitoredPackage.STATE_PASSED, m4.handleElapsedTimeLocked(LONG_DURATION));
}
+ private void adoptShellPermissions(String... permissions) {
+ InstrumentationRegistry
+ .getInstrumentation()
+ .getUiAutomation()
+ .adoptShellPermissionIdentity(permissions);
+ }
+
+ private void dropShellPermissions() {
+ InstrumentationRegistry
+ .getInstrumentation()
+ .getUiAutomation()
+ .dropShellPermissionIdentity();
+ }
+
+ private void setExplicitHealthCheckEnabled(boolean enabled) {
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
+ PackageWatchdog.PROPERTY_WATCHDOG_EXPLICIT_HEALTH_CHECK_ENABLED,
+ Boolean.toString(enabled), /*makeDefault*/false);
+ //give time for DeviceConfig to broadcast the property value change
+ try {
+ Thread.sleep(SHORT_DURATION);
+ } catch (InterruptedException e) {
+ fail("Thread.sleep unexpectedly failed!");
+ }
+ }
+
private PackageWatchdog createWatchdog() {
return createWatchdog(new TestController(), true /* withPackagesReady */);
}
diff --git a/tests/RollbackTest/Android.bp b/tests/RollbackTest/Android.bp
index dfc3b6e..e556b0a 100644
--- a/tests/RollbackTest/Android.bp
+++ b/tests/RollbackTest/Android.bp
@@ -88,6 +88,15 @@
installable: false,
}
+apex {
+ name: "com.android.tests.rollback.testapex.RollbackTestApexV3",
+ manifest: "TestApex/RollbackTestApexV3.json",
+ file_contexts: "apex.test",
+ prebuilts: ["RollbackTestApex.prebuilt.txt"],
+ key: "RollbackTestApex.key",
+ installable: false,
+}
+
apex_key {
name: "RollbackTestApex.key",
public_key: "TestApex/com.android.tests.rollback.testapex.avbpubkey",
@@ -116,6 +125,7 @@
":RollbackTestAppASplitV2",
":com.android.tests.rollback.testapex.RollbackTestApexV1",
":com.android.tests.rollback.testapex.RollbackTestApexV2",
+ ":com.android.tests.rollback.testapex.RollbackTestApexV3",
],
test_config: "RollbackTest.xml",
sdk_version: "test_current",
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
index 7e711c2..3b0e2a5 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -26,6 +26,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import org.junit.After;
@@ -54,6 +55,8 @@
"com.android.tests.rollback.testapex.RollbackTestApexV1.apex";
private static final String TEST_APEX_V2 =
"com.android.tests.rollback.testapex.RollbackTestApexV2.apex";
+ private static final String TEST_APEX_V3 =
+ "com.android.tests.rollback.testapex.RollbackTestApexV3.apex";
/**
* Adopts common shell permissions needed for rollback tests.
@@ -145,26 +148,13 @@
/**
* Test rollbacks of staged installs an apk and an apex.
- * Prepare apex (and apk) phase.
- */
- @Test
- public void testApkAndApexPrepare() throws Exception {
- RollbackTestUtils.uninstall(TEST_APP_A);
- assertEquals(-1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
-
- // Note: can't uninstall the apex. See note in #testApexOnlyPrepareApex().
- RollbackTestUtils.installStaged(false, TEST_APP_A_V1, TEST_APEX_V1);
-
- // At this point, the host test driver will reboot the device and run
- // testApkAndApexEnableRollback().
- }
-
- /**
- * Test rollbacks of staged installs an apk and an apex.
* Enable rollback phase.
*/
@Test
public void testApkAndApexEnableRollback() throws Exception {
+ RollbackTestUtils.uninstall(TEST_APP_A);
+ RollbackTestUtils.install(TEST_APP_A_V1, false);
+
assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APEX_PKG));
assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
@@ -225,22 +215,6 @@
/**
* Test rollbacks of staged installs involving only apex.
- * Prepare apex phase.
- */
- @Test
- public void testApexOnlyPrepareApex() throws Exception {
- // Note: We can't uninstall the apex if it is already on device,
- // because that isn't supported yet (b/123667725). As long as nothing
- // is failing, this should be fine because we don't expect the tests
- // to leave the device with v2 of the apex installed.
- RollbackTestUtils.installStaged(false, TEST_APEX_V1);
-
- // At this point, the host test driver will reboot the device and run
- // testApexOnlyEnableRollback().
- }
-
- /**
- * Test rollbacks of staged installs involving only apex.
* Enable rollback phase.
*/
@Test
@@ -291,4 +265,51 @@
public void testApexOnlyConfirmRollback() throws Exception {
assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APEX_PKG));
}
+
+ /**
+ * Tests that apex update expires existing rollbacks for that apex.
+ * Enable rollback phase.
+ */
+ @Test
+ public void testApexRollbackExpirationEnableRollback() throws Exception {
+ assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APEX_PKG));
+ RollbackTestUtils.installStaged(true, TEST_APEX_V2);
+
+ // At this point, the host test driver will reboot the device and run
+ // testApexRollbackExpirationUpdateApex().
+ }
+
+ /**
+ * Tests that apex update expires existing rollbacks for that apex.
+ * Update apex phase.
+ */
+ @Test
+ public void testApexRollbackExpirationUpdateApex() throws Exception {
+ assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APEX_PKG));
+ RollbackTestUtils.installStaged(false, TEST_APEX_V3);
+
+ // At this point, the host test driver will reboot the device and run
+ // testApexRollbackExpirationConfirmExpiration().
+ }
+
+ /**
+ * Tests that apex update expires existing rollbacks for that apex.
+ * Confirm expiration phase.
+ */
+ @Test
+ public void testApexRollbackExpirationConfirmExpiration() throws Exception {
+ assertEquals(3, RollbackTestUtils.getInstalledVersion(TEST_APEX_PKG));
+
+ RollbackManager rm = RollbackTestUtils.getRollbackManager();
+ assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APEX_PKG));
+ }
+
+ /**
+ * Helper function called by the host test to install v1 of the test apex,
+ * assuming the test apex is not installed.
+ */
+ @Test
+ public void installTestApexV1() throws Exception {
+ RollbackTestUtils.installStaged(false, TEST_APEX_V1);
+ }
}
diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
index ac7f634..1f87ed8 100644
--- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
+++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
@@ -18,6 +18,7 @@
import static org.junit.Assert.assertTrue;
+import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
@@ -30,6 +31,8 @@
@RunWith(DeviceJUnit4ClassRunner.class)
public class StagedRollbackTest extends BaseHostJUnit4Test {
+ private static final String TEST_APEX_PKG = "com.android.tests.rollback.testapex";
+
/**
* Runs the given phase of a test by calling into the device.
* Throws an exception if the test phase fails.
@@ -59,8 +62,7 @@
*/
@Test
public void testApexOnly() throws Exception {
- runPhase("testApexOnlyPrepareApex");
- getDevice().reboot();
+ installTestApexV1();
runPhase("testApexOnlyEnableRollback");
getDevice().reboot();
runPhase("testApexOnlyCommitRollback");
@@ -73,12 +75,45 @@
*/
@Test
public void testApkAndApex() throws Exception {
- runPhase("testApkAndApexPrepare");
- getDevice().reboot();
+ installTestApexV1();
runPhase("testApkAndApexEnableRollback");
getDevice().reboot();
runPhase("testApkAndApexCommitRollback");
getDevice().reboot();
runPhase("testApkAndApexConfirmRollback");
}
+
+ /**
+ * Tests that apex update expires existing rollbacks for that apex.
+ */
+ @Test
+ public void testApexRollbackExpiration() throws Exception {
+ installTestApexV1();
+ runPhase("testApexRollbackExpirationEnableRollback");
+ getDevice().reboot();
+ runPhase("testApexRollbackExpirationUpdateApex");
+ getDevice().reboot();
+ runPhase("testApexRollbackExpirationConfirmExpiration");
+ }
+
+ /**
+ * Do whatever is necessary to get version 1 of the test apex installed on
+ * the device. Try to do so without extra reboots where possible to keep
+ * the test execution time down.
+ */
+ private void installTestApexV1() throws Exception {
+ for (ITestDevice.ApexInfo apexInfo : getDevice().getActiveApexes()) {
+ if (TEST_APEX_PKG.equals(apexInfo.name)) {
+ if (apexInfo.versionCode == 1) {
+ return;
+ }
+ getDevice().uninstallPackage(TEST_APEX_PKG);
+ getDevice().reboot();
+ break;
+ }
+ }
+
+ runPhase("installTestApexV1");
+ getDevice().reboot();
+ }
}
diff --git a/tests/RollbackTest/TestApex/RollbackTestApexV3.json b/tests/RollbackTest/TestApex/RollbackTestApexV3.json
new file mode 100644
index 0000000..87a2c9d
--- /dev/null
+++ b/tests/RollbackTest/TestApex/RollbackTestApexV3.json
@@ -0,0 +1,4 @@
+{
+ "name": "com.android.tests.rollback.testapex",
+ "version": 3
+}
diff --git a/tests/net/common/Android.bp b/tests/net/common/Android.bp
index 9ee5858..3b2e34a 100644
--- a/tests/net/common/Android.bp
+++ b/tests/net/common/Android.bp
@@ -18,7 +18,7 @@
// They must be fast and stable, and exercise public or test APIs.
java_library {
name: "FrameworksNetCommonTests",
- srcs: ["java/**/*.java"],
+ srcs: ["java/**/*.java", "java/**/*.kt"],
static_libs: [
"androidx.test.rules",
"frameworks-net-testutils",
diff --git a/tests/net/common/java/android/net/LinkPropertiesTest.java b/tests/net/common/java/android/net/LinkPropertiesTest.java
index 4177291..709f5f6 100644
--- a/tests/net/common/java/android/net/LinkPropertiesTest.java
+++ b/tests/net/common/java/android/net/LinkPropertiesTest.java
@@ -868,12 +868,12 @@
source.setNat64Prefix(new IpPrefix("2001:db8:1:2:64:64::/96"));
- TestUtils.assertParcelingIsLossless(source, LinkProperties.CREATOR);
+ TestUtils.assertParcelingIsLossless(source);
}
@Test
public void testParcelUninitialized() throws Exception {
LinkProperties empty = new LinkProperties();
- TestUtils.assertParcelingIsLossless(empty, LinkProperties.CREATOR);
+ TestUtils.assertParcelingIsLossless(empty);
}
}
diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
index ad76388..6bc7c1b 100644
--- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
@@ -33,6 +33,8 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;
import static android.net.NetworkCapabilities.RESTRICTED_CAPABILITIES;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_TEST;
+import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.NetworkCapabilities.UNRESTRICTED_CAPABILITIES;
@@ -585,4 +587,20 @@
nc2.set(nc1); // Overwrites, as opposed to combineCapabilities
assertEquals(nc1, nc2);
}
+
+ @Test
+ public void testGetTransportTypes() {
+ final NetworkCapabilities nc = new NetworkCapabilities();
+ nc.addTransportType(TRANSPORT_CELLULAR);
+ nc.addTransportType(TRANSPORT_WIFI);
+ nc.addTransportType(TRANSPORT_VPN);
+ nc.addTransportType(TRANSPORT_TEST);
+
+ final int[] transportTypes = nc.getTransportTypes();
+ assertEquals(4, transportTypes.length);
+ assertEquals(TRANSPORT_CELLULAR, transportTypes[0]);
+ assertEquals(TRANSPORT_WIFI, transportTypes[1]);
+ assertEquals(TRANSPORT_VPN, transportTypes[2]);
+ assertEquals(TRANSPORT_TEST, transportTypes[3]);
+ }
}
diff --git a/tests/net/common/java/android/net/NetworkTest.java b/tests/net/common/java/android/net/NetworkTest.java
index 0bee7cd..bef66b2 100644
--- a/tests/net/common/java/android/net/NetworkTest.java
+++ b/tests/net/common/java/android/net/NetworkTest.java
@@ -155,4 +155,12 @@
private static <T> void assertNotEqual(T t1, T t2) {
assertFalse(Objects.equals(t1, t2));
}
+
+ @Test
+ public void testGetPrivateDnsBypassingCopy() {
+ final Network copy = mNetwork.getPrivateDnsBypassingCopy();
+ assertEquals(mNetwork.netId, copy.netId);
+ assertNotEqual(copy.netId, copy.getNetIdForResolv());
+ assertNotEqual(mNetwork.getNetIdForResolv(), copy.getNetIdForResolv());
+ }
}
diff --git a/tests/net/common/java/android/net/StaticIpConfigurationTest.java b/tests/net/common/java/android/net/StaticIpConfigurationTest.java
index 8449ca7..5096be2 100644
--- a/tests/net/common/java/android/net/StaticIpConfigurationTest.java
+++ b/tests/net/common/java/android/net/StaticIpConfigurationTest.java
@@ -31,7 +31,9 @@
import org.junit.runner.RunWith;
import java.net.InetAddress;
+import java.util.ArrayList;
import java.util.HashSet;
+import java.util.List;
import java.util.Objects;
@RunWith(AndroidJUnit4.class)
@@ -46,6 +48,7 @@
private static final InetAddress DNS2 = IpAddress("8.8.4.4");
private static final InetAddress DNS3 = IpAddress("4.2.2.2");
private static final String IFACE = "eth0";
+ private static final String FAKE_DOMAINS = "google.com";
private static InetAddress IpAddress(String addr) {
return InetAddress.parseNumericAddress(addr);
@@ -69,7 +72,7 @@
s.dnsServers.add(DNS1);
s.dnsServers.add(DNS2);
s.dnsServers.add(DNS3);
- s.domains = "google.com";
+ s.domains = FAKE_DOMAINS;
return s;
}
@@ -178,8 +181,8 @@
expected.addDnsServer(DNS3);
assertEquals(expected, s.toLinkProperties(IFACE));
- s.domains = "google.com";
- expected.setDomains("google.com");
+ s.domains = FAKE_DOMAINS;
+ expected.setDomains(FAKE_DOMAINS);
assertEquals(expected, s.toLinkProperties(IFACE));
s.gateway = null;
@@ -218,4 +221,53 @@
StaticIpConfiguration s2 = passThroughParcel(s);
assertEquals(s, s2);
}
+
+ @Test
+ public void testBuilder() {
+ final ArrayList<InetAddress> dnsServers = new ArrayList<>();
+ dnsServers.add(DNS1);
+
+ final StaticIpConfiguration s = new StaticIpConfiguration.Builder()
+ .setIpAddress(ADDR)
+ .setGateway(GATEWAY)
+ .setDomains(FAKE_DOMAINS)
+ .setDnsServers(dnsServers)
+ .build();
+
+ assertEquals(s.ipAddress, s.getIpAddress());
+ assertEquals(ADDR, s.getIpAddress());
+ assertEquals(s.gateway, s.getGateway());
+ assertEquals(GATEWAY, s.getGateway());
+ assertEquals(s.domains, s.getDomains());
+ assertEquals(FAKE_DOMAINS, s.getDomains());
+ assertTrue(s.dnsServers.equals(s.getDnsServers()));
+ assertEquals(1, s.getDnsServers().size());
+ assertEquals(DNS1, s.getDnsServers().get(0));
+ }
+
+ @Test
+ public void testAddDnsServers() {
+ final StaticIpConfiguration s = new StaticIpConfiguration((StaticIpConfiguration) null);
+ checkEmpty(s);
+
+ s.addDnsServer(DNS1);
+ assertEquals(1, s.getDnsServers().size());
+ assertEquals(DNS1, s.getDnsServers().get(0));
+
+ s.addDnsServer(DNS2);
+ s.addDnsServer(DNS3);
+ assertEquals(3, s.getDnsServers().size());
+ assertEquals(DNS2, s.getDnsServers().get(1));
+ assertEquals(DNS3, s.getDnsServers().get(2));
+ }
+
+ @Test
+ public void testGetRoutes() {
+ final StaticIpConfiguration s = makeTestObject();
+ final List<RouteInfo> routeInfoList = s.getRoutes(IFACE);
+
+ assertEquals(2, routeInfoList.size());
+ assertEquals(new RouteInfo(ADDR, (InetAddress) null, IFACE), routeInfoList.get(0));
+ assertEquals(new RouteInfo((IpPrefix) null, GATEWAY, IFACE), routeInfoList.get(1));
+ }
}
diff --git a/tests/net/common/java/android/net/apf/ApfCapabilitiesTest.java b/tests/net/common/java/android/net/apf/ApfCapabilitiesTest.java
index 7238895..3ed8a86 100644
--- a/tests/net/common/java/android/net/apf/ApfCapabilitiesTest.java
+++ b/tests/net/common/java/android/net/apf/ApfCapabilitiesTest.java
@@ -36,7 +36,7 @@
final ApfCapabilities caps = new ApfCapabilities(123, 456, 789);
ParcelableTestUtil.assertFieldCountEquals(3, ApfCapabilities.class);
- TestUtils.assertParcelingIsLossless(caps, ApfCapabilities.CREATOR);
+ TestUtils.assertParcelingIsLossless(caps);
}
@Test
diff --git a/tests/net/common/java/android/net/metrics/DhcpErrorEventTest.kt b/tests/net/common/java/android/net/metrics/DhcpErrorEventTest.kt
new file mode 100644
index 0000000..e191953
--- /dev/null
+++ b/tests/net/common/java/android/net/metrics/DhcpErrorEventTest.kt
@@ -0,0 +1,67 @@
+package android.net.metrics
+
+import android.net.metrics.DhcpErrorEvent.errorCodeWithOption
+import android.net.metrics.DhcpErrorEvent.DHCP_INVALID_OPTION_LENGTH
+import androidx.test.filters.SmallTest
+import androidx.test.runner.AndroidJUnit4
+import com.android.internal.util.TestUtils.parcelingRoundTrip
+import java.lang.reflect.Modifier
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNotNull
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+
+private const val TEST_ERROR_CODE = 12345
+/**
+ * DHCP Optional Type: DHCP Subnet Mask (Copy from DhcpPacket.java)
+ */
+private const val DHCP_SUBNET_MASK = 1
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class DhcpErrorEventTest {
+
+ @Test
+ fun testConstructor() {
+ val event = DhcpErrorEvent(TEST_ERROR_CODE)
+ assertEquals(TEST_ERROR_CODE, event.errorCode)
+ }
+
+ @Test
+ fun testParcelUnparcel() {
+ val event = DhcpErrorEvent(TEST_ERROR_CODE)
+ val parceled = parcelingRoundTrip(event)
+ assertEquals(TEST_ERROR_CODE, parceled.errorCode)
+ }
+
+ @Test
+ fun testErrorCodeWithOption() {
+ val errorCode = errorCodeWithOption(DHCP_INVALID_OPTION_LENGTH, DHCP_SUBNET_MASK);
+ assertTrue((DHCP_INVALID_OPTION_LENGTH and errorCode) == DHCP_INVALID_OPTION_LENGTH);
+ assertTrue((DHCP_SUBNET_MASK and errorCode) == DHCP_SUBNET_MASK);
+ }
+
+ @Test
+ fun testToString() {
+ val names = listOf("L2_ERROR", "L3_ERROR", "L4_ERROR", "DHCP_ERROR", "MISC_ERROR")
+ val errorFields = DhcpErrorEvent::class.java.declaredFields.filter {
+ it.type == Int::class.javaPrimitiveType
+ && Modifier.isPublic(it.modifiers) && Modifier.isStatic(it.modifiers)
+ && it.name !in names
+ }
+
+ errorFields.forEach {
+ val intValue = it.getInt(null)
+ val stringValue = DhcpErrorEvent(intValue).toString()
+ assertTrue("Invalid string for error 0x%08X (field %s): %s".format(intValue, it.name,
+ stringValue),
+ stringValue.contains(it.name))
+ }
+ }
+
+ @Test
+ fun testToString_InvalidErrorCode() {
+ assertNotNull(DhcpErrorEvent(TEST_ERROR_CODE).toString())
+ }
+}
\ No newline at end of file
diff --git a/tests/net/java/android/net/TcpKeepalivePacketDataTest.java b/tests/net/java/android/net/TcpKeepalivePacketDataTest.java
index e0b7227..583d3fd 100644
--- a/tests/net/java/android/net/TcpKeepalivePacketDataTest.java
+++ b/tests/net/java/android/net/TcpKeepalivePacketDataTest.java
@@ -79,7 +79,7 @@
assertEquals(testInfo.tos, resultData.ipTos);
assertEquals(testInfo.ttl, resultData.ipTtl);
- TestUtils.assertParcelingIsLossless(resultData, TcpKeepalivePacketData.CREATOR);
+ TestUtils.assertParcelingIsLossless(resultData);
final byte[] packet = resultData.getPacket();
// IP version and IHL
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index c15775f..363ac9c 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -567,6 +567,16 @@
protected void preventAutomaticReconnect() {
mPreventReconnectReceived.open();
}
+
+ @Override
+ protected void addKeepalivePacketFilter(Message msg) {
+ Log.i(TAG, "Add keepalive packet filter.");
+ }
+
+ @Override
+ protected void removeKeepalivePacketFilter(Message msg) {
+ Log.i(TAG, "Remove keepalive packet filter.");
+ }
};
assertEquals(mNetworkAgent.netId, nmNetworkCaptor.getValue().netId);
diff --git a/tests/net/util/java/com/android/internal/util/TestUtils.java b/tests/net/util/java/com/android/internal/util/TestUtils.java
index 75329a8..a99cd47 100644
--- a/tests/net/util/java/com/android/internal/util/TestUtils.java
+++ b/tests/net/util/java/com/android/internal/util/TestUtils.java
@@ -69,9 +69,17 @@
}
}
- // TODO : fetch the creator through reflection or something instead of passing it
- public static <T extends Parcelable, C extends Parcelable.Creator<T>>
- void assertParcelingIsLossless(T source, C creator) {
+ /**
+ * Return a new instance of {@code T} after being parceled then unparceled.
+ */
+ public static <T extends Parcelable> T parcelingRoundTrip(T source) {
+ final Parcelable.Creator<T> creator;
+ try {
+ creator = (Parcelable.Creator<T>) source.getClass().getField("CREATOR").get(null);
+ } catch (IllegalAccessException | NoSuchFieldException e) {
+ fail("Missing CREATOR field: " + e.getMessage());
+ return null;
+ }
Parcel p = Parcel.obtain();
source.writeToParcel(p, /* flags */ 0);
p.setDataPosition(0);
@@ -79,7 +87,14 @@
p = Parcel.obtain();
p.unmarshall(marshalled, 0, marshalled.length);
p.setDataPosition(0);
- T dest = creator.createFromParcel(p);
- assertEquals(source, dest);
+ return creator.createFromParcel(p);
+ }
+
+ /**
+ * Assert that after being parceled then unparceled, {@code source} is equal to the original
+ * object.
+ */
+ public static <T extends Parcelable> void assertParcelingIsLossless(T source) {
+ assertEquals(source, parcelingRoundTrip(source));
}
}
diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py
index 97ca6dc..f41426d 100644
--- a/tools/apilint/apilint.py
+++ b/tools/apilint/apilint.py
@@ -2132,6 +2132,10 @@
# Remove all existing things so we're left with new
for prev_clazz in prev.values():
+ if prev_clazz.fullname not in cur:
+ # The class was removed this release; we can safely ignore it.
+ continue
+
cur_clazz = cur[prev_clazz.fullname]
if not is_interesting(cur_clazz): continue