Merge "idmap2: fix clang-tidy warnings [modernize-*]"
diff --git a/api/current.txt b/api/current.txt
index d4aa34c..bf3a1f4 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -11302,6 +11302,7 @@
method public void updateSessionAppLabel(int, java.lang.CharSequence);
field public static final java.lang.String ACTION_SESSION_COMMITTED = "android.content.pm.action.SESSION_COMMITTED";
field public static final java.lang.String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS";
+ field public static final java.lang.String ACTION_SESSION_UPDATED = "android.content.pm.action.SESSION_UPDATED";
field public static final java.lang.String EXTRA_OTHER_PACKAGE_NAME = "android.content.pm.extra.OTHER_PACKAGE_NAME";
field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME";
field public static final java.lang.String EXTRA_SESSION = "android.content.pm.extra.SESSION";
diff --git a/cmds/incident_helper/src/TextParserBase.h b/cmds/incident_helper/src/TextParserBase.h
index 784c181..a6074e7 100644
--- a/cmds/incident_helper/src/TextParserBase.h
+++ b/cmds/incident_helper/src/TextParserBase.h
@@ -30,7 +30,7 @@
public:
String8 name;
- TextParserBase(String8 name) : name(name) {};
+ explicit TextParserBase(String8 name) : name(name) {};
virtual ~TextParserBase() {};
virtual status_t Parse(const int in, const int out) const = 0;
diff --git a/cmds/incident_helper/src/ih_util.h b/cmds/incident_helper/src/ih_util.h
index c02a349..09dc8e6 100644
--- a/cmds/incident_helper/src/ih_util.h
+++ b/cmds/incident_helper/src/ih_util.h
@@ -109,7 +109,7 @@
class Reader
{
public:
- Reader(const int fd);
+ explicit Reader(const int fd);
~Reader();
bool readLine(std::string* line);
@@ -162,7 +162,7 @@
class Message
{
public:
- Message(Table* table);
+ explicit Message(Table* table);
~Message();
// Reconstructs the typical proto message by adding its message fields.
diff --git a/cmds/incidentd/src/IncidentService.h b/cmds/incidentd/src/IncidentService.h
index 6252ad2..c63a183 100644
--- a/cmds/incidentd/src/IncidentService.h
+++ b/cmds/incidentd/src/IncidentService.h
@@ -97,7 +97,7 @@
// ================================================================================
class IncidentService : public BnIncidentManager {
public:
- IncidentService(const sp<Looper>& handlerLooper);
+ explicit IncidentService(const sp<Looper>& handlerLooper);
virtual ~IncidentService();
virtual Status reportIncident(const IncidentReportArgs& args);
diff --git a/cmds/incidentd/src/Privacy.h b/cmds/incidentd/src/Privacy.h
index a3df490..a0159d9 100644
--- a/cmds/incidentd/src/Privacy.h
+++ b/cmds/incidentd/src/Privacy.h
@@ -83,7 +83,7 @@
static PrivacySpec new_spec(int dest);
private:
- PrivacySpec(uint8_t dest) : dest(dest) {}
+ explicit PrivacySpec(uint8_t dest) : dest(dest) {}
};
} // namespace incidentd
diff --git a/cmds/incidentd/src/Reporter.h b/cmds/incidentd/src/Reporter.h
index 45fd944..2a3abd7 100644
--- a/cmds/incidentd/src/Reporter.h
+++ b/cmds/incidentd/src/Reporter.h
@@ -89,7 +89,7 @@
ReportRequestSet batch;
Reporter(); // PROD must use this constructor.
- Reporter(const char* directory); // For testing purpose only.
+ explicit Reporter(const char* directory); // For testing purpose only.
virtual ~Reporter();
// Run the report as described in the batch and args parameters.
diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp
index 10d2268..32ec1ba 100644
--- a/cmds/incidentd/src/Section.cpp
+++ b/cmds/incidentd/src/Section.cpp
@@ -415,7 +415,7 @@
bool workerDone;
status_t workerError;
- WorkerThreadData(const WorkerThreadSection* section);
+ explicit WorkerThreadData(const WorkerThreadSection* section);
virtual ~WorkerThreadData();
};
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 0114ff4..f0b751d 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -216,6 +216,7 @@
"tests/anomaly/AnomalyTracker_test.cpp",
"tests/ConfigManager_test.cpp",
"tests/external/puller_util_test.cpp",
+ "tests/external/StatsPuller_test.cpp",
"tests/indexed_priority_queue_test.cpp",
"tests/LogEntryMatcher_test.cpp",
"tests/LogEvent_test.cpp",
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 50b64b9..f2a4663 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -704,7 +704,7 @@
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;
- if (mPullerManager->Pull(s, getElapsedRealtimeNs(), &stats)) {
+ if (mPullerManager->Pull(s, &stats)) {
for (const auto& it : stats) {
dprintf(out, "Pull from %d: %s\n", s, it->ToString().c_str());
}
diff --git a/cmds/statsd/src/anomaly/AlarmMonitor.h b/cmds/statsd/src/anomaly/AlarmMonitor.h
index 3badb1f..bca858e 100644
--- a/cmds/statsd/src/anomaly/AlarmMonitor.h
+++ b/cmds/statsd/src/anomaly/AlarmMonitor.h
@@ -42,7 +42,7 @@
* Timestamps are in seconds since epoch in a uint32, so will fail in year 2106.
*/
struct InternalAlarm : public RefBase {
- InternalAlarm(uint32_t timestampSec) : timestampSec(timestampSec) {
+ explicit InternalAlarm(uint32_t timestampSec) : timestampSec(timestampSec) {
}
const uint32_t timestampSec;
diff --git a/cmds/statsd/src/condition/ConditionWizard.h b/cmds/statsd/src/condition/ConditionWizard.h
index a6f88af..2c88147 100644
--- a/cmds/statsd/src/condition/ConditionWizard.h
+++ b/cmds/statsd/src/condition/ConditionWizard.h
@@ -29,7 +29,7 @@
class ConditionWizard : public virtual android::RefBase {
public:
ConditionWizard(){}; // for testing
- ConditionWizard(std::vector<sp<ConditionTracker>>& conditionTrackers)
+ explicit ConditionWizard(std::vector<sp<ConditionTracker>>& conditionTrackers)
: mAllConditions(conditionTrackers){};
virtual ~ConditionWizard(){};
diff --git a/cmds/statsd/src/config/ConfigKey.h b/cmds/statsd/src/config/ConfigKey.h
index dc79519..4cc9393 100644
--- a/cmds/statsd/src/config/ConfigKey.h
+++ b/cmds/statsd/src/config/ConfigKey.h
@@ -33,7 +33,7 @@
class ConfigKey {
public:
ConfigKey();
- explicit ConfigKey(const ConfigKey& that);
+ ConfigKey(const ConfigKey& that);
ConfigKey(int uid, const int64_t& id);
~ConfigKey();
diff --git a/cmds/statsd/src/external/PowerStatsPuller.h b/cmds/statsd/src/external/PowerStatsPuller.h
index dd5ff8f..6f15bd6 100644
--- a/cmds/statsd/src/external/PowerStatsPuller.h
+++ b/cmds/statsd/src/external/PowerStatsPuller.h
@@ -28,6 +28,8 @@
class PowerStatsPuller : public StatsPuller {
public:
PowerStatsPuller();
+
+private:
bool PullInternal(vector<std::shared_ptr<LogEvent>>* data) override;
};
diff --git a/cmds/statsd/src/external/ResourceHealthManagerPuller.h b/cmds/statsd/src/external/ResourceHealthManagerPuller.h
index 9b238eaf5..f650fcc 100644
--- a/cmds/statsd/src/external/ResourceHealthManagerPuller.h
+++ b/cmds/statsd/src/external/ResourceHealthManagerPuller.h
@@ -28,7 +28,9 @@
*/
class ResourceHealthManagerPuller : public StatsPuller {
public:
- ResourceHealthManagerPuller(int tagId);
+ explicit ResourceHealthManagerPuller(int tagId);
+
+private:
bool PullInternal(vector<std::shared_ptr<LogEvent>>* data) override;
};
diff --git a/cmds/statsd/src/external/ResourceThermalManagerPuller.h b/cmds/statsd/src/external/ResourceThermalManagerPuller.h
index 13c675a..5313792 100644
--- a/cmds/statsd/src/external/ResourceThermalManagerPuller.h
+++ b/cmds/statsd/src/external/ResourceThermalManagerPuller.h
@@ -29,6 +29,8 @@
class ResourceThermalManagerPuller : public StatsPuller {
public:
ResourceThermalManagerPuller();
+
+private:
bool PullInternal(vector<std::shared_ptr<LogEvent>>* data) override;
};
diff --git a/cmds/statsd/src/external/StatsCompanionServicePuller.h b/cmds/statsd/src/external/StatsCompanionServicePuller.h
index 0a49732..2e13320 100644
--- a/cmds/statsd/src/external/StatsCompanionServicePuller.h
+++ b/cmds/statsd/src/external/StatsCompanionServicePuller.h
@@ -25,14 +25,14 @@
class StatsCompanionServicePuller : public StatsPuller {
public:
- StatsCompanionServicePuller(int tagId);
- bool PullInternal(vector<std::shared_ptr<LogEvent> >* data) override;
+ explicit StatsCompanionServicePuller(int tagId);
void SetStatsCompanionService(sp<IStatsCompanionService> statsCompanionService) override;
private:
Mutex mStatsCompanionServiceLock;
sp<IStatsCompanionService> mStatsCompanionService = nullptr;
+ bool PullInternal(vector<std::shared_ptr<LogEvent> >* data) override;
};
} // namespace statsd
diff --git a/cmds/statsd/src/external/StatsPuller.cpp b/cmds/statsd/src/external/StatsPuller.cpp
index 7043d66..c7c22ee 100644
--- a/cmds/statsd/src/external/StatsPuller.cpp
+++ b/cmds/statsd/src/external/StatsPuller.cpp
@@ -34,48 +34,52 @@
StatsPuller::StatsPuller(const int tagId)
: mTagId(tagId) {
- // Pullers can cause significant impact to system health and battery.
- // So that we don't pull too frequently.
- mCoolDownNs = StatsPullerManager::kAllPullAtomInfo.find(tagId)->second.coolDownNs;
- VLOG("Puller for tag %d created. Cooldown set to %lld", mTagId, (long long)mCoolDownNs);
}
-bool StatsPuller::Pull(const int64_t elapsedTimeNs, std::vector<std::shared_ptr<LogEvent>>* data) {
+bool StatsPuller::Pull(std::vector<std::shared_ptr<LogEvent>>* data) {
lock_guard<std::mutex> lock(mLock);
- int64_t wallClockTimeNs = getWallClockNs();
+ int64_t elapsedTimeNs = getElapsedRealtimeNs();
StatsdStats::getInstance().notePull(mTagId);
- if (elapsedTimeNs - mLastPullTimeNs < mCoolDownNs) {
- (*data) = mCachedData;
- StatsdStats::getInstance().notePullFromCache(mTagId);
- StatsdStats::getInstance().notePullDelay(mTagId, getElapsedRealtimeNs() - elapsedTimeNs);
- return true;
+ const bool shouldUseCache = elapsedTimeNs - mLastPullTimeNs <
+ StatsPullerManager::kAllPullAtomInfo.at(mTagId).coolDownNs;
+ if (shouldUseCache) {
+ if (mHasGoodData) {
+ (*data) = mCachedData;
+ StatsdStats::getInstance().notePullFromCache(mTagId);
+ }
+ return mHasGoodData;
}
- if (mMinPullIntervalNs > elapsedTimeNs - mLastPullTimeNs) {
- mMinPullIntervalNs = elapsedTimeNs - mLastPullTimeNs;
- StatsdStats::getInstance().updateMinPullIntervalSec(mTagId,
- mMinPullIntervalNs / NS_PER_SEC);
+
+ if (mLastPullTimeNs > 0) {
+ StatsdStats::getInstance().updateMinPullIntervalSec(
+ mTagId, (elapsedTimeNs - mLastPullTimeNs) / NS_PER_SEC);
}
mCachedData.clear();
mLastPullTimeNs = elapsedTimeNs;
- int64_t pullStartTimeNs = getElapsedRealtimeNs();
- bool ret = PullInternal(&mCachedData);
- if (!ret) {
- mCachedData.clear();
- return false;
+ mHasGoodData = PullInternal(&mCachedData);
+ if (!mHasGoodData) {
+ return mHasGoodData;
}
- StatsdStats::getInstance().notePullTime(mTagId, getElapsedRealtimeNs() - pullStartTimeNs);
- for (const shared_ptr<LogEvent>& data : mCachedData) {
- data->setElapsedTimestampNs(elapsedTimeNs);
- data->setLogdWallClockTimestampNs(wallClockTimeNs);
+ const int64_t pullDurationNs = getElapsedRealtimeNs() - elapsedTimeNs;
+ StatsdStats::getInstance().notePullTime(mTagId, pullDurationNs);
+ const bool pullTimeOut =
+ pullDurationNs > StatsPullerManager::kAllPullAtomInfo.at(mTagId).pullTimeoutNs;
+ if (pullTimeOut) {
+ // Something went wrong. Discard the data.
+ clearCacheLocked();
+ mHasGoodData = false;
+ StatsdStats::getInstance().notePullTimeout(mTagId);
+ ALOGW("Pull for atom %d exceeds timeout %lld nano seconds.", mTagId,
+ (long long)pullDurationNs);
+ return mHasGoodData;
}
if (mCachedData.size() > 0) {
mapAndMergeIsolatedUidsToHostUid(mCachedData, mUidMap, mTagId);
- (*data) = mCachedData;
}
- StatsdStats::getInstance().notePullDelay(mTagId, getElapsedRealtimeNs() - elapsedTimeNs);
- return ret;
+ (*data) = mCachedData;
+ return mHasGoodData;
}
int StatsPuller::ForceClearCache() {
@@ -84,6 +88,10 @@
int StatsPuller::clearCache() {
lock_guard<std::mutex> lock(mLock);
+ return clearCacheLocked();
+}
+
+int StatsPuller::clearCacheLocked() {
int ret = mCachedData.size();
mCachedData.clear();
mLastPullTimeNs = 0;
@@ -91,7 +99,8 @@
}
int StatsPuller::ClearCacheIfNecessary(int64_t timestampNs) {
- if (timestampNs - mLastPullTimeNs > mCoolDownNs) {
+ if (timestampNs - mLastPullTimeNs >
+ StatsPullerManager::kAllPullAtomInfo.at(mTagId).coolDownNs) {
return clearCache();
} else {
return 0;
diff --git a/cmds/statsd/src/external/StatsPuller.h b/cmds/statsd/src/external/StatsPuller.h
index cafd797..c83c4f8 100644
--- a/cmds/statsd/src/external/StatsPuller.h
+++ b/cmds/statsd/src/external/StatsPuller.h
@@ -18,7 +18,6 @@
#include <android/os/IStatsCompanionService.h>
#include <utils/RefBase.h>
-#include <utils/String16.h>
#include <mutex>
#include <vector>
#include "packages/UidMap.h"
@@ -33,14 +32,20 @@
class StatsPuller : public virtual RefBase {
public:
- StatsPuller(const int tagId);
+ explicit StatsPuller(const int tagId);
virtual ~StatsPuller() {}
- // Pulls the data. The returned data will have elapsedTimeNs set as timeNs
- // and will have wallClockTimeNs set as current wall clock time.
- // Return true if the pull is successful.
- bool Pull(const int64_t timeNs, std::vector<std::shared_ptr<LogEvent>>* data);
+ // Pulls the most recent data.
+ // The data may be served from cache if consecutive pulls come within
+ // predefined cooldown time.
+ // Returns true if the pull was successful.
+ // Returns false when
+ // 1) the pull fails
+ // 2) pull takes longer than mPullTimeoutNs (intrinsic to puller)
+ // If a metric wants to make any change to the data, like timestamps, it
+ // should make a copy as this data may be shared with multiple metrics.
+ bool Pull(std::vector<std::shared_ptr<LogEvent>>* data);
// Clear cache immediately
int ForceClearCache();
@@ -53,29 +58,30 @@
virtual void SetStatsCompanionService(sp<IStatsCompanionService> statsCompanionService){};
protected:
- // The atom tag id this puller pulls
const int mTagId;
private:
mutable std::mutex mLock;
- // Minimum time before this puller does actual pull again.
- // If a pull request comes before cooldown, a cached version from purevious pull
- // will be returned.
- // The actual value should be determined by individual pullers.
- int64_t mCoolDownNs;
- // For puller stats
- int64_t mMinPullIntervalNs = LONG_MAX;
+ // Real puller impl.
virtual bool PullInternal(std::vector<std::shared_ptr<LogEvent>>* data) = 0;
- // Cache of data from last pull. If next request comes before cool down finishes,
- // cached data will be returned.
- std::vector<std::shared_ptr<LogEvent>> mCachedData;
+ bool mHasGoodData = false;
int64_t mLastPullTimeNs;
+ // Cache of data from last pull. If next request comes before cool down finishes,
+ // cached data will be returned.
+ // Cached data is cleared when
+ // 1) A pull fails
+ // 2) A new pull request comes after cooldown time.
+ // 3) clearCache is called.
+ std::vector<std::shared_ptr<LogEvent>> mCachedData;
+
int clearCache();
+ int clearCacheLocked();
+
static sp<UidMap> mUidMap;
};
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index c070ca3..4a716cf 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -53,195 +53,172 @@
const std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = {
// wifi_bytes_transfer
{android::util::WIFI_BYTES_TRANSFER,
- {{2, 3, 4, 5},
- 1 * NS_PER_SEC,
- new StatsCompanionServicePuller(android::util::WIFI_BYTES_TRANSFER)}},
+ {.additiveFields = {2, 3, 4, 5},
+ .puller = new StatsCompanionServicePuller(android::util::WIFI_BYTES_TRANSFER)}},
// wifi_bytes_transfer_by_fg_bg
{android::util::WIFI_BYTES_TRANSFER_BY_FG_BG,
- {{3, 4, 5, 6},
- 1 * NS_PER_SEC,
- new StatsCompanionServicePuller(android::util::WIFI_BYTES_TRANSFER_BY_FG_BG)}},
+ {.additiveFields = {3, 4, 5, 6},
+ .puller = new StatsCompanionServicePuller(android::util::WIFI_BYTES_TRANSFER_BY_FG_BG)}},
// mobile_bytes_transfer
{android::util::MOBILE_BYTES_TRANSFER,
- {{2, 3, 4, 5},
- 1 * NS_PER_SEC,
- new StatsCompanionServicePuller(android::util::MOBILE_BYTES_TRANSFER)}},
+ {.additiveFields = {2, 3, 4, 5},
+ .puller = new StatsCompanionServicePuller(android::util::MOBILE_BYTES_TRANSFER)}},
// mobile_bytes_transfer_by_fg_bg
{android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG,
- {{3, 4, 5, 6},
- 1 * NS_PER_SEC,
- new StatsCompanionServicePuller(android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG)}},
+ {.additiveFields = {3, 4, 5, 6},
+ .puller =
+ new StatsCompanionServicePuller(android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG)}},
// bluetooth_bytes_transfer
{android::util::BLUETOOTH_BYTES_TRANSFER,
- {{2, 3},
- 1 * NS_PER_SEC,
- new StatsCompanionServicePuller(android::util::BLUETOOTH_BYTES_TRANSFER)}},
+ {.additiveFields = {2, 3},
+ .puller = new StatsCompanionServicePuller(android::util::BLUETOOTH_BYTES_TRANSFER)}},
// kernel_wakelock
{android::util::KERNEL_WAKELOCK,
- {{}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::KERNEL_WAKELOCK)}},
+ {.puller = new StatsCompanionServicePuller(android::util::KERNEL_WAKELOCK)}},
// subsystem_sleep_state
- {android::util::SUBSYSTEM_SLEEP_STATE,
- {{}, 1 * NS_PER_SEC, new SubsystemSleepStatePuller()}},
+ {android::util::SUBSYSTEM_SLEEP_STATE, {.puller = new SubsystemSleepStatePuller()}},
// on_device_power_measurement
- {android::util::ON_DEVICE_POWER_MEASUREMENT, {{}, 1 * NS_PER_SEC, new PowerStatsPuller()}},
+ {android::util::ON_DEVICE_POWER_MEASUREMENT, {.puller = new PowerStatsPuller()}},
// cpu_time_per_freq
{android::util::CPU_TIME_PER_FREQ,
- {{3}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::CPU_TIME_PER_FREQ)}},
+ {.additiveFields = {3},
+ .puller = new StatsCompanionServicePuller(android::util::CPU_TIME_PER_FREQ)}},
// cpu_time_per_uid
{android::util::CPU_TIME_PER_UID,
- {{2, 3},
- 1 * NS_PER_SEC,
- new StatsCompanionServicePuller(android::util::CPU_TIME_PER_UID)}},
+ {.additiveFields = {2, 3},
+ .puller = new StatsCompanionServicePuller(android::util::CPU_TIME_PER_UID)}},
// cpu_time_per_uid_freq
// the throttling is 3sec, handled in
// frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader
{android::util::CPU_TIME_PER_UID_FREQ,
- {{4},
- 1 * NS_PER_SEC,
- new StatsCompanionServicePuller(android::util::CPU_TIME_PER_UID_FREQ)}},
+ {.additiveFields = {4},
+ .puller = new StatsCompanionServicePuller(android::util::CPU_TIME_PER_UID_FREQ)}},
// cpu_active_time
// the throttling is 3sec, handled in
// frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader
{android::util::CPU_ACTIVE_TIME,
- {{2}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::CPU_ACTIVE_TIME)}},
+ {.additiveFields = {2},
+ .puller = new StatsCompanionServicePuller(android::util::CPU_ACTIVE_TIME)}},
// cpu_cluster_time
// the throttling is 3sec, handled in
// frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader
{android::util::CPU_CLUSTER_TIME,
- {{3}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::CPU_CLUSTER_TIME)}},
+ {.additiveFields = {3},
+ .puller = new StatsCompanionServicePuller(android::util::CPU_CLUSTER_TIME)}},
// wifi_activity_energy_info
{android::util::WIFI_ACTIVITY_INFO,
- {{}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::WIFI_ACTIVITY_INFO)}},
+ {.puller = new StatsCompanionServicePuller(android::util::WIFI_ACTIVITY_INFO)}},
// modem_activity_info
{android::util::MODEM_ACTIVITY_INFO,
- {{}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::MODEM_ACTIVITY_INFO)}},
+ {.puller = new StatsCompanionServicePuller(android::util::MODEM_ACTIVITY_INFO)}},
// bluetooth_activity_info
{android::util::BLUETOOTH_ACTIVITY_INFO,
- {{},
- 1 * NS_PER_SEC,
- new StatsCompanionServicePuller(android::util::BLUETOOTH_ACTIVITY_INFO)}},
+ {.puller = new StatsCompanionServicePuller(android::util::BLUETOOTH_ACTIVITY_INFO)}},
// system_elapsed_realtime
{android::util::SYSTEM_ELAPSED_REALTIME,
- {{},
- 1 * NS_PER_SEC,
- new StatsCompanionServicePuller(android::util::SYSTEM_ELAPSED_REALTIME)}},
+ {.pullTimeoutNs = NS_PER_SEC / 2,
+ .coolDownNs = NS_PER_SEC,
+ .puller = new StatsCompanionServicePuller(android::util::SYSTEM_ELAPSED_REALTIME)}},
// system_uptime
{android::util::SYSTEM_UPTIME,
- {{}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::SYSTEM_UPTIME)}},
+ {.puller = new StatsCompanionServicePuller(android::util::SYSTEM_UPTIME)}},
// remaining_battery_capacity
{android::util::REMAINING_BATTERY_CAPACITY,
- {{},
- 1 * NS_PER_SEC,
- new ResourceHealthManagerPuller(android::util::REMAINING_BATTERY_CAPACITY)}},
+ {.puller = new ResourceHealthManagerPuller(android::util::REMAINING_BATTERY_CAPACITY)}},
// full_battery_capacity
{android::util::FULL_BATTERY_CAPACITY,
- {{},
- 1 * NS_PER_SEC,
- new ResourceHealthManagerPuller(android::util::FULL_BATTERY_CAPACITY)}},
+ {.puller = new ResourceHealthManagerPuller(android::util::FULL_BATTERY_CAPACITY)}},
// battery_voltage
{android::util::BATTERY_VOLTAGE,
- {{}, 1 * NS_PER_SEC, new ResourceHealthManagerPuller(android::util::BATTERY_VOLTAGE)}},
- // battery_level
+ {.puller = new ResourceHealthManagerPuller(android::util::BATTERY_VOLTAGE)}},
+ // battery_voltage
{android::util::BATTERY_LEVEL,
- {{}, 1 * NS_PER_SEC, new ResourceHealthManagerPuller(android::util::BATTERY_LEVEL)}},
+ {.puller = new ResourceHealthManagerPuller(android::util::BATTERY_LEVEL)}},
// process_memory_state
{android::util::PROCESS_MEMORY_STATE,
- {{4, 5, 6, 7, 8, 9},
- 1 * NS_PER_SEC,
- new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_STATE)}},
+ {.additiveFields = {4, 5, 6, 7, 8, 9},
+ .puller = new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_STATE)}},
// native_process_memory_state
{android::util::NATIVE_PROCESS_MEMORY_STATE,
- {{3, 4, 5, 6},
- 1 * NS_PER_SEC,
- new StatsCompanionServicePuller(android::util::NATIVE_PROCESS_MEMORY_STATE)}},
+ {.additiveFields = {3, 4, 5, 6},
+ .puller = new StatsCompanionServicePuller(android::util::NATIVE_PROCESS_MEMORY_STATE)}},
{android::util::PROCESS_MEMORY_HIGH_WATER_MARK,
- {{3},
- 1 * NS_PER_SEC,
- new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_HIGH_WATER_MARK)}},
+ {.additiveFields = {3},
+ .puller =
+ new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_HIGH_WATER_MARK)}},
// temperature
- {android::util::TEMPERATURE, {{}, 1 * NS_PER_SEC, new ResourceThermalManagerPuller()}},
+ {android::util::TEMPERATURE, {.puller = new ResourceThermalManagerPuller()}},
// binder_calls
{android::util::BINDER_CALLS,
- {{4, 5, 6, 8, 12},
- 1 * NS_PER_SEC,
- new StatsCompanionServicePuller(android::util::BINDER_CALLS)}},
+ {.additiveFields = {4, 5, 6, 8, 12},
+ .puller = new StatsCompanionServicePuller(android::util::BINDER_CALLS)}},
// binder_calls_exceptions
{android::util::BINDER_CALLS_EXCEPTIONS,
- {{},
- 1 * NS_PER_SEC,
- new StatsCompanionServicePuller(android::util::BINDER_CALLS_EXCEPTIONS)}},
+ {.puller = new StatsCompanionServicePuller(android::util::BINDER_CALLS_EXCEPTIONS)}},
// looper_stats
{android::util::LOOPER_STATS,
- {{5, 6, 7, 8, 9},
- 1 * NS_PER_SEC,
- new StatsCompanionServicePuller(android::util::LOOPER_STATS)}},
+ {.additiveFields = {5, 6, 7, 8, 9},
+ .puller = new StatsCompanionServicePuller(android::util::LOOPER_STATS)}},
// Disk Stats
{android::util::DISK_STATS,
- {{}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::DISK_STATS)}},
+ {.puller = new StatsCompanionServicePuller(android::util::DISK_STATS)}},
// Directory usage
{android::util::DIRECTORY_USAGE,
- {{}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::DIRECTORY_USAGE)}},
+ {.puller = new StatsCompanionServicePuller(android::util::DIRECTORY_USAGE)}},
// Size of app's code, data, and cache
{android::util::APP_SIZE,
- {{}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::APP_SIZE)}},
+ {.puller = new StatsCompanionServicePuller(android::util::APP_SIZE)}},
// Size of specific categories of files. Eg. Music.
{android::util::CATEGORY_SIZE,
- {{}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::CATEGORY_SIZE)}},
+ {.puller = new StatsCompanionServicePuller(android::util::CATEGORY_SIZE)}},
// Number of fingerprints registered to each user.
{android::util::NUM_FINGERPRINTS,
- {{}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::NUM_FINGERPRINTS)}},
+ {.puller = new StatsCompanionServicePuller(android::util::NUM_FINGERPRINTS)}},
// ProcStats.
{android::util::PROC_STATS,
- {{}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::PROC_STATS)}},
+ {.puller = new StatsCompanionServicePuller(android::util::PROC_STATS)}},
// ProcStatsPkgProc.
{android::util::PROC_STATS_PKG_PROC,
- {{}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::PROC_STATS_PKG_PROC)}},
+ {.puller = new StatsCompanionServicePuller(android::util::PROC_STATS_PKG_PROC)}},
// Disk I/O stats per uid.
{android::util::DISK_IO,
- {{2, 3, 4, 5, 6, 7, 8, 9, 10, 11},
- 3 * NS_PER_SEC,
- new StatsCompanionServicePuller(android::util::DISK_IO)}},
+ {.additiveFields = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11},
+ .coolDownNs = 3 * NS_PER_SEC,
+ .puller = new StatsCompanionServicePuller(android::util::DISK_IO)}},
// PowerProfile constants for power model calculations.
{android::util::POWER_PROFILE,
- {{}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::POWER_PROFILE)}},
+ {.puller = new StatsCompanionServicePuller(android::util::POWER_PROFILE)}},
// Process cpu stats. Min cool-down is 5 sec, inline with what AcitivityManagerService uses.
{android::util::PROCESS_CPU_TIME,
- {{} /* additive fields */,
- 5 * NS_PER_SEC /* min cool-down in seconds*/,
- new StatsCompanionServicePuller(android::util::PROCESS_CPU_TIME)}},
+ {.coolDownNs = 5 * NS_PER_SEC /* min cool-down in seconds*/,
+ .puller = new StatsCompanionServicePuller(android::util::PROCESS_CPU_TIME)}},
{android::util::CPU_TIME_PER_THREAD_FREQ,
- {{7, 9, 11, 13, 15, 17, 19, 21},
- 1 * NS_PER_SEC,
- new StatsCompanionServicePuller(android::util::CPU_TIME_PER_THREAD_FREQ)}},
+ {.additiveFields = {7, 9, 11, 13, 15, 17, 19, 21},
+ .puller = new StatsCompanionServicePuller(android::util::CPU_TIME_PER_THREAD_FREQ)}},
// DeviceCalculatedPowerUse.
{android::util::DEVICE_CALCULATED_POWER_USE,
- {{},
- 1 * NS_PER_SEC,
- new StatsCompanionServicePuller(android::util::DEVICE_CALCULATED_POWER_USE)}},
+ {.puller = new StatsCompanionServicePuller(android::util::DEVICE_CALCULATED_POWER_USE)}},
// DeviceCalculatedPowerBlameUid.
{android::util::DEVICE_CALCULATED_POWER_BLAME_UID,
- {{}, // BatteryStats already merged isolated with host ids so it's unnecessary here.
- 1 * NS_PER_SEC,
- new StatsCompanionServicePuller(android::util::DEVICE_CALCULATED_POWER_BLAME_UID)}},
+ {.puller = new StatsCompanionServicePuller(
+ android::util::DEVICE_CALCULATED_POWER_BLAME_UID)}},
// DeviceCalculatedPowerBlameOther.
{android::util::DEVICE_CALCULATED_POWER_BLAME_OTHER,
- {{},
- 1 * NS_PER_SEC,
- new StatsCompanionServicePuller(android::util::DEVICE_CALCULATED_POWER_BLAME_OTHER)}},
+ {.puller = new StatsCompanionServicePuller(
+ android::util::DEVICE_CALCULATED_POWER_BLAME_OTHER)}},
// BuildInformation.
{android::util::BUILD_INFORMATION,
- {{}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::BUILD_INFORMATION)}},
+ {.puller = new StatsCompanionServicePuller(android::util::BUILD_INFORMATION)}},
};
StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) {
}
-bool StatsPullerManager::Pull(const int tagId, const int64_t timeNs,
- vector<shared_ptr<LogEvent>>* data) {
+bool StatsPullerManager::Pull(int tagId, vector<shared_ptr<LogEvent>>* data) {
VLOG("Initiating pulling %d", tagId);
if (kAllPullAtomInfo.find(tagId) != kAllPullAtomInfo.end()) {
- bool ret = kAllPullAtomInfo.find(tagId)->second.puller->Pull(timeNs, data);
+ bool ret = kAllPullAtomInfo.find(tagId)->second.puller->Pull(data);
VLOG("pulled %d items", (int)data->size());
return ret;
} else {
@@ -333,8 +310,9 @@
}
}
-void StatsPullerManager::OnAlarmFired(const int64_t currentTimeNs) {
+void StatsPullerManager::OnAlarmFired(int64_t elapsedTimeNs) {
AutoMutex _l(mLock);
+ int64_t wallClockNs = getWallClockNs();
int64_t minNextPullTimeNs = NO_ALARM_UPDATE;
@@ -344,7 +322,7 @@
vector<ReceiverInfo*> receivers = vector<ReceiverInfo*>();
if (pair.second.size() != 0) {
for (ReceiverInfo& receiverInfo : pair.second) {
- if (receiverInfo.nextPullTimeNs <= currentTimeNs) {
+ if (receiverInfo.nextPullTimeNs <= elapsedTimeNs) {
receivers.push_back(&receiverInfo);
} else {
if (receiverInfo.nextPullTimeNs < minNextPullTimeNs) {
@@ -360,22 +338,38 @@
for (const auto& pullInfo : needToPull) {
vector<shared_ptr<LogEvent>> data;
- if (Pull(pullInfo.first, currentTimeNs, &data)) {
- for (const auto& receiverInfo : pullInfo.second) {
- sp<PullDataReceiver> receiverPtr = receiverInfo->receiver.promote();
- if (receiverPtr != nullptr) {
- receiverPtr->onDataPulled(data);
- // we may have just come out of a coma, compute next pull time
- receiverInfo->nextPullTimeNs =
- (currentTimeNs - receiverInfo->nextPullTimeNs) /
- receiverInfo->intervalNs * receiverInfo->intervalNs +
- receiverInfo->intervalNs + receiverInfo->nextPullTimeNs;
- if (receiverInfo->nextPullTimeNs < minNextPullTimeNs) {
- minNextPullTimeNs = receiverInfo->nextPullTimeNs;
- }
- } else {
- VLOG("receiver already gone.");
+ if (!Pull(pullInfo.first, &data)) {
+ VLOG("pull failed at %lld, will try again later", (long long)elapsedTimeNs);
+ continue;
+ }
+ StatsdStats::getInstance().notePullDelay(pullInfo.first,
+ getElapsedRealtimeNs() - elapsedTimeNs);
+
+ // Convention is to mark pull atom timestamp at request time.
+ // If we pull at t0, puller starts at t1, finishes at t2, and send back
+ // at t3, we mark t0 as its timestamp, which should correspond to its
+ // triggering event, such as condition change at t0.
+ // Here the triggering event is alarm fired from AlarmManager.
+ // In ValueMetricProducer and GaugeMetricProducer we do same thing
+ // when pull on condition change, etc.
+ for (auto& event : data) {
+ event->setElapsedTimestampNs(elapsedTimeNs);
+ event->setLogdWallClockTimestampNs(wallClockNs);
+ }
+
+ for (const auto& receiverInfo : pullInfo.second) {
+ sp<PullDataReceiver> receiverPtr = receiverInfo->receiver.promote();
+ if (receiverPtr != nullptr) {
+ receiverPtr->onDataPulled(data);
+ // we may have just come out of a coma, compute next pull time
+ int numBucketsAhead =
+ (elapsedTimeNs - receiverInfo->nextPullTimeNs) / receiverInfo->intervalNs;
+ receiverInfo->nextPullTimeNs += (numBucketsAhead + 1) * receiverInfo->intervalNs;
+ if (receiverInfo->nextPullTimeNs < minNextPullTimeNs) {
+ minNextPullTimeNs = receiverInfo->nextPullTimeNs;
}
+ } else {
+ VLOG("receiver already gone.");
}
}
}
diff --git a/cmds/statsd/src/external/StatsPullerManager.h b/cmds/statsd/src/external/StatsPullerManager.h
index 3350736..807e4af 100644
--- a/cmds/statsd/src/external/StatsPullerManager.h
+++ b/cmds/statsd/src/external/StatsPullerManager.h
@@ -26,6 +26,7 @@
#include <vector>
#include "PullDataReceiver.h"
#include "StatsPuller.h"
+#include "guardrail/StatsdStats.h"
#include "logd/LogEvent.h"
namespace android {
@@ -36,11 +37,19 @@
// The field numbers of the fields that need to be summed when merging
// isolated uid with host uid.
std::vector<int> additiveFields;
- // How long should the puller wait before doing an actual pull again. Default
- // 1 sec. Set this to 0 if this is handled elsewhere.
+ // Minimum time before this puller does actual pull again.
+ // Pullers can cause significant impact to system health and battery.
+ // So that we don't pull too frequently.
+ // If a pull request comes before cooldown, a cached version from previous pull
+ // will be returned.
int64_t coolDownNs = 1 * NS_PER_SEC;
// The actual puller
sp<StatsPuller> puller;
+ // Max time allowed to pull this atom.
+ // We cannot reliably kill a pull thread. So we don't terminate the puller.
+ // The data is discarded if the pull takes longer than this and mHasGoodData
+ // marked as false.
+ int64_t pullTimeoutNs = StatsdStats::kPullMaxDelayNs;
} PullAtomInfo;
class StatsPullerManager : public virtual RefBase {
@@ -61,13 +70,18 @@
// Verify if we know how to pull for this matcher
bool PullerForMatcherExists(int tagId) const;
- void OnAlarmFired(const int64_t timeNs);
+ void OnAlarmFired(int64_t elapsedTimeNs);
- // Use respective puller to pull the data. The returned data will have
- // elapsedTimeNs set as timeNs and will have wallClockTimeNs set as current
- // wall clock time.
- virtual bool Pull(const int tagId, const int64_t timeNs,
- vector<std::shared_ptr<LogEvent>>* data);
+ // Pulls the most recent data.
+ // The data may be served from cache if consecutive pulls come within
+ // mCoolDownNs.
+ // Returns true if the pull was successful.
+ // Returns false when
+ // 1) the pull fails
+ // 2) pull takes longer than mPullTimeoutNs (intrinsic to puller)
+ // If the metric wants to make any change to the data, like timestamps, they
+ // should make a copy as this data may be shared with multiple metrics.
+ virtual bool Pull(int tagId, vector<std::shared_ptr<LogEvent>>* data);
// Clear pull data cache immediately.
int ForceClearPullerCache();
diff --git a/cmds/statsd/src/external/SubsystemSleepStatePuller.h b/cmds/statsd/src/external/SubsystemSleepStatePuller.h
index 17ce5b4cb..87f5f02 100644
--- a/cmds/statsd/src/external/SubsystemSleepStatePuller.h
+++ b/cmds/statsd/src/external/SubsystemSleepStatePuller.h
@@ -29,6 +29,8 @@
class SubsystemSleepStatePuller : public StatsPuller {
public:
SubsystemSleepStatePuller();
+
+private:
bool PullInternal(vector<std::shared_ptr<LogEvent>>* data) override;
};
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index 3e5e82f..f4d0144 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -373,6 +373,16 @@
mPulledAtomStats[pullAtomId].dataError++;
}
+void StatsdStats::notePullTimeout(int pullAtomId) {
+ lock_guard<std::mutex> lock(mLock);
+ mPulledAtomStats[pullAtomId].pullTimeout++;
+}
+
+void StatsdStats::notePullExceedMaxDelay(int pullAtomId) {
+ lock_guard<std::mutex> lock(mLock);
+ mPulledAtomStats[pullAtomId].pullExceedMaxDelay++;
+}
+
void StatsdStats::noteAtomLogged(int atomId, int32_t timeSec) {
lock_guard<std::mutex> lock(mLock);
@@ -429,6 +439,8 @@
pullStats.second.maxPullDelayNs = 0;
pullStats.second.numPullDelay = 0;
pullStats.second.dataError = 0;
+ pullStats.second.pullTimeout = 0;
+ pullStats.second.pullExceedMaxDelay = 0;
}
}
@@ -535,13 +547,16 @@
dprintf(out, "********Pulled Atom stats***********\n");
for (const auto& pair : mPulledAtomStats) {
dprintf(out,
- "Atom %d->(total pull)%ld, (pull from cache)%ld, (min pull interval)%ld, (average "
- "pull time nanos)%lld, (max pull time nanos)%lld, (average pull delay nanos)%lld, "
- "(max pull delay nanos)%lld, (data error)%ld\n",
+ "Atom %d->(total pull)%ld, (pull from cache)%ld, (min pull interval)%ld \n"
+ " (average pull time nanos)%lld, (max pull time nanos)%lld, (average pull delay "
+ "nanos)%lld, "
+ " (max pull delay nanos)%lld, (data error)%ld\n"
+ " (pull timeout)%ld, (pull exceed max delay)%ld\n",
(int)pair.first, (long)pair.second.totalPull, (long)pair.second.totalPullFromCache,
(long)pair.second.minPullIntervalSec, (long long)pair.second.avgPullTimeNs,
(long long)pair.second.maxPullTimeNs, (long long)pair.second.avgPullDelayNs,
- (long long)pair.second.maxPullDelayNs, pair.second.dataError);
+ (long long)pair.second.maxPullDelayNs, pair.second.dataError,
+ pair.second.pullTimeout, pair.second.pullExceedMaxDelay);
}
if (mAnomalyAlarmRegisteredStats > 0) {
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index 3157037..dc647f8 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -144,6 +144,8 @@
// How long to try to clear puller cache from last time
static const long kPullerCacheClearIntervalSec = 1;
+ // Max time to do a pull.
+ static const int64_t kPullMaxDelayNs = 10 * NS_PER_SEC;
/**
* Report a new config has been received and report the static stats about the config.
*
@@ -296,6 +298,16 @@
void notePullDelay(int pullAtomId, int64_t pullDelayNs);
/*
+ * Records pull exceeds timeout for the puller.
+ */
+ void notePullTimeout(int pullAtomId);
+
+ /*
+ * Records pull exceeds max delay for a metric.
+ */
+ void notePullExceedMaxDelay(int pullAtomId);
+
+ /*
* Records when system server restarts.
*/
void noteSystemServerRestart(int32_t timeSec);
@@ -335,6 +347,8 @@
int64_t maxPullDelayNs = 0;
long numPullDelay = 0;
long dataError = 0;
+ long pullTimeout = 0;
+ long pullExceedMaxDelay = 0;
} PulledAtomStats;
private:
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 8d61aba..2ff8aa1 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -41,6 +41,14 @@
}
}
+LogEvent::LogEvent(const LogEvent& event) {
+ mTagId = event.mTagId;
+ mLogUid = event.mLogUid;
+ mElapsedTimestampNs = event.mElapsedTimestampNs;
+ mLogdTimestampNs = event.mLogdTimestampNs;
+ mValues = event.mValues;
+}
+
LogEvent::LogEvent(const StatsLogEventWrapper& statsLogEventWrapper, int workChainIndex) {
mTagId = statsLogEventWrapper.getTagId();
mLogdTimestampNs = statsLogEventWrapper.getWallClockTimeNs();
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index 5408d17..43e6e4f 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -207,12 +207,15 @@
return &mValues;
}
+ inline LogEvent makeCopy() {
+ return LogEvent(*this);
+ }
+
private:
/**
- * Don't copy, it's slower. If we really need this we can add it but let's try to
- * avoid it.
+ * Only use this if copy is absolutely needed.
*/
- explicit LogEvent(const LogEvent&);
+ LogEvent(const LogEvent&);
/**
* Parses a log_msg into a LogEvent object.
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index ec60244..67a1a47 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -68,15 +68,12 @@
const int FIELD_ID_START_BUCKET_ELAPSED_MILLIS = 7;
const int FIELD_ID_END_BUCKET_ELAPSED_MILLIS = 8;
-GaugeMetricProducer::GaugeMetricProducer(const ConfigKey& key, const GaugeMetric& metric,
- const int conditionIndex,
- const sp<ConditionWizard>& wizard,
- const int whatMatcherIndex,
- const sp<EventMatcherWizard>& matcherWizard,
- const int pullTagId,
- const int triggerAtomId, const int atomId,
- const int64_t timeBaseNs, const int64_t startTimeNs,
- const sp<StatsPullerManager>& pullerManager)
+GaugeMetricProducer::GaugeMetricProducer(
+ const ConfigKey& key, const GaugeMetric& metric, const int conditionIndex,
+ const sp<ConditionWizard>& wizard, const int whatMatcherIndex,
+ const sp<EventMatcherWizard>& matcherWizard, const int pullTagId, const int triggerAtomId,
+ const int atomId, const int64_t timeBaseNs, const int64_t startTimeNs,
+ const sp<StatsPullerManager>& pullerManager)
: MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, wizard),
mWhatMatcherIndex(whatMatcherIndex),
mEventMatcherWizard(matcherWizard),
@@ -86,6 +83,8 @@
mAtomId(atomId),
mIsPulled(pullTagId != -1),
mMinBucketSizeNs(metric.min_bucket_size_nanos()),
+ mMaxPullDelayNs(metric.max_pull_delay_sec() > 0 ? metric.max_pull_delay_sec() * NS_PER_SEC
+ : StatsdStats::kPullMaxDelayNs),
mDimensionSoftLimit(StatsdStats::kAtomDimensionKeySizeLimitMap.find(pullTagId) !=
StatsdStats::kAtomDimensionKeySizeLimitMap.end()
? StatsdStats::kAtomDimensionKeySizeLimitMap.at(pullTagId).first
@@ -338,14 +337,24 @@
return;
}
vector<std::shared_ptr<LogEvent>> allData;
- if (!mPullerManager->Pull(mPullTagId, timestampNs, &allData)) {
+ if (!mPullerManager->Pull(mPullTagId, &allData)) {
ALOGE("Gauge Stats puller failed for tag: %d at %lld", mPullTagId, (long long)timestampNs);
return;
}
+ const int64_t pullDelayNs = getElapsedRealtimeNs() - timestampNs;
+ if (pullDelayNs > mMaxPullDelayNs) {
+ ALOGE("Pull finish too late for atom %d", mPullTagId);
+ StatsdStats::getInstance().notePullExceedMaxDelay(mPullTagId);
+ StatsdStats::getInstance().notePullDelay(mPullTagId, pullDelayNs);
+ return;
+ }
+ StatsdStats::getInstance().notePullDelay(mPullTagId, pullDelayNs);
for (const auto& data : allData) {
- if (mEventMatcherWizard->matchLogEvent(
- *data, mWhatMatcherIndex) == MatchingState::kMatched) {
- onMatchedLogEventLocked(mWhatMatcherIndex, *data);
+ LogEvent localCopy = data->makeCopy();
+ localCopy.setElapsedTimestampNs(timestampNs);
+ if (mEventMatcherWizard->matchLogEvent(localCopy, mWhatMatcherIndex) ==
+ MatchingState::kMatched) {
+ onMatchedLogEventLocked(mWhatMatcherIndex, localCopy);
}
}
}
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h
index 6e3530b..a1a5061 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.h
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h
@@ -160,6 +160,8 @@
GaugeMetric::SamplingType mSamplingType;
+ const int64_t mMaxPullDelayNs;
+
// apply a whitelist on the original input
std::shared_ptr<vector<FieldValue>> getGaugeFields(const LogEvent& event);
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index cf56e2d..9a8e3bd 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -103,7 +103,9 @@
mValueDirection(metric.value_direction()),
mSkipZeroDiffOutput(metric.skip_zero_diff_output()),
mUseZeroDefaultBase(metric.use_zero_default_base()),
- mHasGlobalBase(false) {
+ mHasGlobalBase(false),
+ mMaxPullDelayNs(metric.max_pull_delay_sec() > 0 ? metric.max_pull_delay_sec() * NS_PER_SEC
+ : StatsdStats::kPullMaxDelayNs) {
int64_t bucketSizeMills = 0;
if (metric.has_bucket()) {
bucketSizeMills = TimeUnitToBucketSizeInMillisGuardrailed(key.GetUid(), metric.bucket());
@@ -340,19 +342,32 @@
void ValueMetricProducer::pullAndMatchEventsLocked(const int64_t timestampNs) {
vector<std::shared_ptr<LogEvent>> allData;
- if (mPullerManager->Pull(mPullTagId, timestampNs, &allData)) {
- for (const auto& data : allData) {
- if (mEventMatcherWizard->matchLogEvent(
- *data, mWhatMatcherIndex) == MatchingState::kMatched) {
- onMatchedLogEventLocked(mWhatMatcherIndex, *data);
- }
- }
- mHasGlobalBase = true;
- } else {
- // for pulled data, every pull is needed. So we reset the base if any
- // pull fails.
+ if (!mPullerManager->Pull(mPullTagId, &allData)) {
+ ALOGE("Gauge Stats puller failed for tag: %d at %lld", mPullTagId, (long long)timestampNs);
resetBase();
+ return;
}
+ const int64_t pullDelayNs = getElapsedRealtimeNs() - timestampNs;
+ if (pullDelayNs > mMaxPullDelayNs) {
+ ALOGE("Pull finish too late for atom %d, longer than %lld", mPullTagId,
+ (long long)mMaxPullDelayNs);
+ StatsdStats::getInstance().notePullExceedMaxDelay(mPullTagId);
+ StatsdStats::getInstance().notePullDelay(mPullTagId, pullDelayNs);
+ resetBase();
+ return;
+ }
+ StatsdStats::getInstance().notePullDelay(mPullTagId, pullDelayNs);
+
+ for (const auto& data : allData) {
+ // make a copy before doing and changes
+ LogEvent localCopy = data->makeCopy();
+ localCopy.setElapsedTimestampNs(timestampNs);
+ if (mEventMatcherWizard->matchLogEvent(localCopy, mWhatMatcherIndex) ==
+ MatchingState::kMatched) {
+ onMatchedLogEventLocked(mWhatMatcherIndex, localCopy);
+ }
+ }
+ mHasGlobalBase = true;
}
int64_t ValueMetricProducer::calcPreviousBucketEndTime(const int64_t currentTimeNs) {
@@ -381,10 +396,11 @@
return;
}
for (const auto& data : allData) {
- if (mEventMatcherWizard->matchLogEvent(*data, mWhatMatcherIndex) ==
+ LogEvent localCopy = data->makeCopy();
+ if (mEventMatcherWizard->matchLogEvent(localCopy, mWhatMatcherIndex) ==
MatchingState::kMatched) {
- data->setElapsedTimestampNs(bucketEndTime);
- onMatchedLogEventLocked(mWhatMatcherIndex, *data);
+ localCopy.setElapsedTimestampNs(bucketEndTime);
+ onMatchedLogEventLocked(mWhatMatcherIndex, localCopy);
}
}
mHasGlobalBase = true;
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index 4991af4..4865aee 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -183,6 +183,8 @@
// diff against.
bool mHasGlobalBase;
+ const int64_t mMaxPullDelayNs;
+
FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsNoCondition);
FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsWithFiltering);
FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset);
@@ -207,6 +209,8 @@
FRIEND_TEST(ValueMetricProducerTest, TestUseZeroDefaultBase);
FRIEND_TEST(ValueMetricProducerTest, TestUseZeroDefaultBaseWithPullFailures);
FRIEND_TEST(ValueMetricProducerTest, TestTrimUnusedDimensionKey);
+ FRIEND_TEST(ValueMetricProducerTest, TestResetBaseOnPullFail);
+ FRIEND_TEST(ValueMetricProducerTest, TestResetBaseOnPullTooLate);
};
} // namespace statsd
diff --git a/cmds/statsd/src/shell/ShellSubscriber.cpp b/cmds/statsd/src/shell/ShellSubscriber.cpp
index dffff7a..22883f3 100644
--- a/cmds/statsd/src/shell/ShellSubscriber.cpp
+++ b/cmds/statsd/src/shell/ShellSubscriber.cpp
@@ -131,8 +131,7 @@
VLOG("pull atom %d now", pullInfo.mPullerMatcher.atom_id());
vector<std::shared_ptr<LogEvent>> data;
- mPullerMgr->Pull(pullInfo.mPullerMatcher.atom_id(), nowMillis * 1000000L,
- &data);
+ mPullerMgr->Pull(pullInfo.mPullerMatcher.atom_id(), &data);
VLOG("pulled %zu atoms", data.size());
if (data.size() > 0) {
writeToOutputLocked(data, pullInfo.mPullerMatcher);
diff --git a/cmds/statsd/src/socket/StatsSocketListener.h b/cmds/statsd/src/socket/StatsSocketListener.h
index 73e4d33..b8185d2 100644
--- a/cmds/statsd/src/socket/StatsSocketListener.h
+++ b/cmds/statsd/src/socket/StatsSocketListener.h
@@ -35,7 +35,7 @@
class StatsSocketListener : public SocketListener, public virtual android::RefBase {
public:
- StatsSocketListener(const sp<LogListener>& listener);
+ explicit StatsSocketListener(const sp<LogListener>& listener);
virtual ~StatsSocketListener();
@@ -51,4 +51,4 @@
};
} // namespace statsd
} // namespace os
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index 5a87e46..e8de875 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -401,6 +401,8 @@
optional int64 average_pull_delay_nanos = 7;
optional int64 max_pull_delay_nanos = 8;
optional int64 data_error = 9;
+ optional int64 pull_timeout = 10;
+ optional int64 pull_exceed_max_delay = 11;
}
repeated PulledAtomStats pulled_atom_stats = 10;
diff --git a/cmds/statsd/src/stats_log_util.cpp b/cmds/statsd/src/stats_log_util.cpp
index f1310db..7de0bb3 100644
--- a/cmds/statsd/src/stats_log_util.cpp
+++ b/cmds/statsd/src/stats_log_util.cpp
@@ -64,6 +64,8 @@
const int FIELD_ID_AVERAGE_PULL_DELAY_NANOS = 7;
const int FIELD_ID_MAX_PULL_DELAY_NANOS = 8;
const int FIELD_ID_DATA_ERROR = 9;
+const int FIELD_ID_PULL_TIMEOUT = 10;
+const int FIELD_ID_PULL_EXCEED_MAX_DELAY = 11;
namespace {
@@ -450,6 +452,10 @@
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_MAX_PULL_DELAY_NANOS,
(long long)pair.second.maxPullDelayNs);
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_DATA_ERROR, (long long)pair.second.dataError);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULL_TIMEOUT,
+ (long long)pair.second.pullTimeout);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULL_EXCEED_MAX_DELAY,
+ (long long)pair.second.pullExceedMaxDelay);
protoOutput->end(token);
}
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index f485185..381ac32 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -240,7 +240,10 @@
optional SamplingType sampling_type = 9 [default = RANDOM_ONE_SAMPLE] ;
optional int64 min_bucket_size_nanos = 10;
+
optional int64 max_num_gauge_atoms_per_bucket = 11 [default = 10];
+
+ optional int32 max_pull_delay_sec = 13 [default = 10];
}
message ValueMetric {
@@ -285,6 +288,8 @@
optional ValueDirection value_direction = 13 [default = INCREASING];
optional bool skip_zero_diff_output = 14 [default = true];
+
+ optional int32 max_pull_delay_sec = 16 [default = 10];
}
message Alert {
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
index 2d090e0..d5c358d 100644
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
@@ -48,6 +48,7 @@
*gaugeMetric->mutable_dimensions_in_what() =
CreateDimensions(android::util::TEMPERATURE, {2/* sensor name field */ });
gaugeMetric->set_bucket(FIVE_MINUTES);
+ gaugeMetric->set_max_pull_delay_sec(INT_MAX);
config.set_hash_strings_in_metric_report(false);
return config;
@@ -57,7 +58,7 @@
TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents) {
auto config = CreateStatsdConfig(GaugeMetric::RANDOM_ONE_SAMPLE);
- int64_t baseTimeNs = 10 * NS_PER_SEC;
+ int64_t baseTimeNs = getElapsedRealtimeNs();
int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
int64_t bucketSizeNs =
TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
@@ -202,7 +203,7 @@
TEST(GaugeMetricE2eTest, TestConditionChangeToTrueSamplePulledEvents) {
auto config = CreateStatsdConfig(GaugeMetric::CONDITION_CHANGE_TO_TRUE);
- int64_t baseTimeNs = 10 * NS_PER_SEC;
+ int64_t baseTimeNs = getElapsedRealtimeNs();
int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
int64_t bucketSizeNs =
TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
@@ -303,7 +304,7 @@
TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvent_LateAlarm) {
auto config = CreateStatsdConfig(GaugeMetric::RANDOM_ONE_SAMPLE);
- int64_t baseTimeNs = 10 * NS_PER_SEC;
+ int64_t baseTimeNs = getElapsedRealtimeNs();
int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
int64_t bucketSizeNs =
TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
diff --git a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
index abf1ab1..cab6eac 100644
--- a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
@@ -50,6 +50,7 @@
valueMetric->set_bucket(FIVE_MINUTES);
valueMetric->set_use_absolute_value_on_reset(true);
valueMetric->set_skip_zero_diff_output(false);
+ valueMetric->set_max_pull_delay_sec(INT_MAX);
return config;
}
@@ -57,7 +58,7 @@
TEST(ValueMetricE2eTest, TestPulledEvents) {
auto config = CreateStatsdConfig();
- int64_t baseTimeNs = 10 * NS_PER_SEC;
+ int64_t baseTimeNs = getElapsedRealtimeNs();
int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
int64_t bucketSizeNs =
TimeUnitToBucketSizeInMillis(config.value_metric(0).bucket()) * 1000000;
@@ -163,7 +164,7 @@
TEST(ValueMetricE2eTest, TestPulledEvents_LateAlarm) {
auto config = CreateStatsdConfig();
- int64_t baseTimeNs = 10 * NS_PER_SEC;
+ int64_t baseTimeNs = getElapsedRealtimeNs();
int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
int64_t bucketSizeNs =
TimeUnitToBucketSizeInMillis(config.value_metric(0).bucket()) * 1000000;
diff --git a/cmds/statsd/tests/external/StatsPuller_test.cpp b/cmds/statsd/tests/external/StatsPuller_test.cpp
new file mode 100644
index 0000000..76e2097
--- /dev/null
+++ b/cmds/statsd/tests/external/StatsPuller_test.cpp
@@ -0,0 +1,227 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <stdio.h>
+#include <chrono>
+#include <thread>
+#include <vector>
+#include "../metrics/metrics_test_helper.h"
+#include "src/stats_log_util.h"
+#include "tests/statsd_test_util.h"
+
+#ifdef __ANDROID__
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using namespace testing;
+using std::make_shared;
+using std::shared_ptr;
+using std::vector;
+using std::this_thread::sleep_for;
+using testing::Contains;
+
+// cooldown time 1sec.
+int pullTagId = 10014;
+
+bool pullSuccess;
+vector<std::shared_ptr<LogEvent>> pullData;
+long pullDelayNs;
+
+class FakePuller : public StatsPuller {
+public:
+ FakePuller() : StatsPuller(pullTagId){};
+
+private:
+ bool PullInternal(vector<std::shared_ptr<LogEvent>>* data) override {
+ (*data) = pullData;
+ sleep_for(std::chrono::nanoseconds(pullDelayNs));
+ return pullSuccess;
+ }
+};
+
+FakePuller puller;
+
+shared_ptr<LogEvent> createSimpleEvent(int64_t eventTimeNs, int64_t value) {
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(pullTagId, eventTimeNs);
+ event->write(value);
+ event->init();
+ return event;
+}
+
+class StatsPullerTest : public ::testing::Test {
+public:
+ StatsPullerTest() {
+ }
+
+ void SetUp() override {
+ puller.ForceClearCache();
+ pullSuccess = false;
+ pullDelayNs = 0;
+ pullData.clear();
+ }
+};
+
+TEST_F(StatsPullerTest, PullSucces) {
+ pullData.push_back(createSimpleEvent(1111L, 33));
+
+ pullSuccess = true;
+
+ vector<std::shared_ptr<LogEvent>> dataHolder;
+ EXPECT_TRUE(puller.Pull(&dataHolder));
+ EXPECT_EQ(1, dataHolder.size());
+ EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
+ EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs());
+ EXPECT_EQ(1, dataHolder[0]->size());
+ EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value);
+
+ sleep_for(std::chrono::seconds(1));
+
+ pullData.clear();
+ pullData.push_back(createSimpleEvent(2222L, 44));
+
+ pullSuccess = true;
+
+ EXPECT_TRUE(puller.Pull(&dataHolder));
+ EXPECT_EQ(1, dataHolder.size());
+ EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
+ EXPECT_EQ(2222L, dataHolder[0]->GetElapsedTimestampNs());
+ EXPECT_EQ(1, dataHolder[0]->size());
+ EXPECT_EQ(44, dataHolder[0]->getValues()[0].mValue.int_value);
+}
+
+TEST_F(StatsPullerTest, PullFailAfterSuccess) {
+ pullData.push_back(createSimpleEvent(1111L, 33));
+
+ pullSuccess = true;
+
+ vector<std::shared_ptr<LogEvent>> dataHolder;
+ EXPECT_TRUE(puller.Pull(&dataHolder));
+ EXPECT_EQ(1, dataHolder.size());
+ EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
+ EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs());
+ EXPECT_EQ(1, dataHolder[0]->size());
+ EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value);
+
+ sleep_for(std::chrono::seconds(1));
+
+ pullData.clear();
+ pullData.push_back(createSimpleEvent(2222L, 44));
+
+ pullSuccess = false;
+ dataHolder.clear();
+ EXPECT_FALSE(puller.Pull(&dataHolder));
+ EXPECT_EQ(0, dataHolder.size());
+
+ pullSuccess = true;
+ dataHolder.clear();
+ EXPECT_FALSE(puller.Pull(&dataHolder));
+ EXPECT_EQ(0, dataHolder.size());
+}
+
+// Test pull takes longer than timeout, 2nd pull happens shorter than cooldown
+TEST_F(StatsPullerTest, PullTakeTooLongAndPullFast) {
+ pullData.push_back(createSimpleEvent(1111L, 33));
+ pullSuccess = true;
+ // timeout is 0.5
+ pullDelayNs = (long)(0.8 * NS_PER_SEC);
+
+ vector<std::shared_ptr<LogEvent>> dataHolder;
+ EXPECT_FALSE(puller.Pull(&dataHolder));
+ EXPECT_EQ(0, dataHolder.size());
+
+ pullData.clear();
+ pullData.push_back(createSimpleEvent(2222L, 44));
+
+ pullSuccess = true;
+ dataHolder.clear();
+ EXPECT_FALSE(puller.Pull(&dataHolder));
+ EXPECT_EQ(0, dataHolder.size());
+}
+
+TEST_F(StatsPullerTest, PullFail) {
+ pullData.push_back(createSimpleEvent(1111L, 33));
+
+ pullSuccess = false;
+
+ vector<std::shared_ptr<LogEvent>> dataHolder;
+ EXPECT_FALSE(puller.Pull(&dataHolder));
+ EXPECT_EQ(0, dataHolder.size());
+}
+
+TEST_F(StatsPullerTest, PullTakeTooLong) {
+ pullData.push_back(createSimpleEvent(1111L, 33));
+
+ pullSuccess = true;
+ pullDelayNs = NS_PER_SEC;
+
+ vector<std::shared_ptr<LogEvent>> dataHolder;
+ EXPECT_FALSE(puller.Pull(&dataHolder));
+ EXPECT_EQ(0, dataHolder.size());
+}
+
+TEST_F(StatsPullerTest, PullTooFast) {
+ pullData.push_back(createSimpleEvent(1111L, 33));
+
+ pullSuccess = true;
+
+ vector<std::shared_ptr<LogEvent>> dataHolder;
+ EXPECT_TRUE(puller.Pull(&dataHolder));
+ EXPECT_EQ(1, dataHolder.size());
+ EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
+ EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs());
+ EXPECT_EQ(1, dataHolder[0]->size());
+ EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value);
+
+ pullData.clear();
+ pullData.push_back(createSimpleEvent(2222L, 44));
+
+ pullSuccess = true;
+
+ dataHolder.clear();
+ EXPECT_TRUE(puller.Pull(&dataHolder));
+ EXPECT_EQ(1, dataHolder.size());
+ EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
+ EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs());
+ EXPECT_EQ(1, dataHolder[0]->size());
+ EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value);
+}
+
+TEST_F(StatsPullerTest, PullFailsAndTooFast) {
+ pullData.push_back(createSimpleEvent(1111L, 33));
+
+ pullSuccess = false;
+
+ vector<std::shared_ptr<LogEvent>> dataHolder;
+ EXPECT_FALSE(puller.Pull(&dataHolder));
+ EXPECT_EQ(0, dataHolder.size());
+
+ pullData.clear();
+ pullData.push_back(createSimpleEvent(2222L, 44));
+
+ pullSuccess = true;
+
+ EXPECT_FALSE(puller.Pull(&dataHolder));
+ EXPECT_EQ(0, dataHolder.size());
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
index 67a9f7f..2799107 100644
--- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
@@ -90,6 +90,7 @@
metric.set_id(metricId);
metric.set_bucket(ONE_MINUTE);
metric.mutable_gauge_fields_filter()->set_include_all(false);
+ metric.set_max_pull_delay_sec(INT_MAX);
auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
gaugeFieldMatcher->set_field(tagId);
gaugeFieldMatcher->add_child()->set_field(1);
@@ -106,9 +107,8 @@
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
- EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
- .WillOnce(Invoke([](int tagId, int64_t timeNs,
- vector<std::shared_ptr<LogEvent>>* data) {
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event->write(3);
@@ -266,6 +266,7 @@
GaugeMetric metric;
metric.set_id(metricId);
metric.set_bucket(ONE_MINUTE);
+ metric.set_max_pull_delay_sec(INT_MAX);
auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
gaugeFieldMatcher->set_field(tagId);
gaugeFieldMatcher->add_child()->set_field(2);
@@ -281,10 +282,9 @@
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
- EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
.WillOnce(Return(false))
- .WillOnce(Invoke([](int tagId, int64_t timeNs,
- vector<std::shared_ptr<LogEvent>>* data) {
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, eventUpgradeTimeNs);
event->write("some value");
@@ -341,6 +341,7 @@
GaugeMetric metric;
metric.set_id(metricId);
metric.set_bucket(ONE_MINUTE);
+ metric.set_max_pull_delay_sec(INT_MAX);
auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
gaugeFieldMatcher->set_field(tagId);
gaugeFieldMatcher->add_child()->set_field(2);
@@ -357,9 +358,8 @@
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
- EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
- .WillOnce(Invoke([](int tagId, int64_t timeNs,
- vector<std::shared_ptr<LogEvent>>* data) {
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event->write("some value");
@@ -420,6 +420,7 @@
metric.set_bucket(ONE_MINUTE);
metric.mutable_gauge_fields_filter()->set_include_all(true);
metric.set_condition(StringToId("APP_DIED"));
+ metric.set_max_pull_delay_sec(INT_MAX);
auto dim = metric.mutable_dimensions_in_what();
dim->set_field(tagId);
dim->add_child()->set_field(1);
@@ -454,9 +455,8 @@
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
- EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
- .WillOnce(Invoke([](int tagId, int64_t timeNs,
- vector<std::shared_ptr<LogEvent>>* data) {
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event->write(1000);
@@ -502,11 +502,12 @@
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
- EXPECT_CALL(*pullerManager, Pull(tagId, _, _)).WillOnce(Return(false));
+ EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(false));
GaugeMetric metric;
metric.set_id(metricId);
metric.set_bucket(ONE_MINUTE);
+ metric.set_max_pull_delay_sec(INT_MAX);
auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
gaugeFieldMatcher->set_field(tagId);
gaugeFieldMatcher->add_child()->set_field(2);
@@ -591,6 +592,7 @@
metric.set_bucket(ONE_MINUTE);
metric.set_sampling_type(GaugeMetric::FIRST_N_SAMPLES);
metric.mutable_gauge_fields_filter()->set_include_all(false);
+ metric.set_max_pull_delay_sec(INT_MAX);
auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
gaugeFieldMatcher->set_field(tagId);
gaugeFieldMatcher->add_child()->set_field(1);
@@ -604,9 +606,8 @@
new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
- .WillOnce(Invoke([](int tagId, int64_t timeNs,
- vector<std::shared_ptr<LogEvent>>* data) {
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event->write(4);
@@ -614,8 +615,7 @@
data->push_back(event);
return true;
}))
- .WillOnce(Invoke([](int tagId, int64_t timeNs,
- vector<std::shared_ptr<LogEvent>>* data) {
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 20);
event->write(5);
@@ -664,6 +664,7 @@
metric.set_bucket(ONE_MINUTE);
metric.set_sampling_type(GaugeMetric::FIRST_N_SAMPLES);
metric.mutable_gauge_fields_filter()->set_include_all(true);
+ metric.set_max_pull_delay_sec(INT_MAX);
auto dimensionMatcher = metric.mutable_dimensions_in_what();
// use field 1 as dimension.
dimensionMatcher->set_field(tagId);
@@ -678,9 +679,8 @@
new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
- .WillOnce(Invoke([](int tagId, int64_t timeNs,
- vector<std::shared_ptr<LogEvent>>* data) {
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 3);
event->write(3);
@@ -689,8 +689,7 @@
data->push_back(event);
return true;
}))
- .WillOnce(Invoke([](int tagId, int64_t timeNs,
- vector<std::shared_ptr<LogEvent>>* data) {
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event->write(4);
@@ -699,8 +698,7 @@
data->push_back(event);
return true;
}))
- .WillOnce(Invoke([](int tagId, int64_t timeNs,
- vector<std::shared_ptr<LogEvent>>* data) {
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 20);
event->write(4);
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 5524503..67570fc 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -125,6 +125,7 @@
metric.set_bucket(ONE_MINUTE);
metric.mutable_value_field()->set_field(tagId);
metric.mutable_value_field()->add_child()->set_field(2);
+ metric.set_max_pull_delay_sec(INT_MAX);
UidMap uidMap;
SimpleAtomMatcher atomMatcher;
@@ -136,9 +137,8 @@
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
- EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
- .WillOnce(Invoke([](int tagId, int64_t timeNs,
- vector<std::shared_ptr<LogEvent>>* data) {
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs);
event->write(tagId);
@@ -218,6 +218,7 @@
metric.set_bucket(ONE_MINUTE);
metric.mutable_value_field()->set_field(tagId);
metric.mutable_value_field()->add_child()->set_field(2);
+ metric.set_max_pull_delay_sec(INT_MAX);
UidMap uidMap;
SimpleAtomMatcher atomMatcher;
@@ -232,9 +233,8 @@
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
- EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
- .WillOnce(Invoke([](int tagId, int64_t timeNs,
- vector<std::shared_ptr<LogEvent>>* data) {
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs);
event->write(3);
@@ -315,6 +315,7 @@
metric.mutable_value_field()->set_field(tagId);
metric.mutable_value_field()->add_child()->set_field(2);
metric.set_use_absolute_value_on_reset(true);
+ metric.set_max_pull_delay_sec(INT_MAX);
UidMap uidMap;
SimpleAtomMatcher atomMatcher;
@@ -326,7 +327,7 @@
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
- EXPECT_CALL(*pullerManager, Pull(tagId, _, _)).WillOnce(Return(true));
+ EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(true));
ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
logEventMatcherIndex, eventMatcherWizard, tagId,
@@ -393,6 +394,7 @@
metric.set_bucket(ONE_MINUTE);
metric.mutable_value_field()->set_field(tagId);
metric.mutable_value_field()->add_child()->set_field(2);
+ metric.set_max_pull_delay_sec(INT_MAX);
UidMap uidMap;
SimpleAtomMatcher atomMatcher;
@@ -404,7 +406,7 @@
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
- EXPECT_CALL(*pullerManager, Pull(tagId, _, _)).WillOnce(Return(false));
+ EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(false));
ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
logEventMatcherIndex, eventMatcherWizard, tagId,
@@ -469,6 +471,7 @@
metric.mutable_value_field()->set_field(tagId);
metric.mutable_value_field()->add_child()->set_field(2);
metric.set_condition(StringToId("SCREEN_ON"));
+ metric.set_max_pull_delay_sec(INT_MAX);
UidMap uidMap;
SimpleAtomMatcher atomMatcher;
@@ -481,9 +484,8 @@
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
- EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
- .WillOnce(Invoke([](int tagId, int64_t timeNs,
- vector<std::shared_ptr<LogEvent>>* data) {
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 8);
event->write(tagId);
@@ -492,8 +494,7 @@
data->push_back(event);
return true;
}))
- .WillOnce(Invoke([](int tagId, int64_t timeNs,
- vector<std::shared_ptr<LogEvent>>* data) {
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
event->write(tagId);
@@ -599,6 +600,7 @@
metric.set_bucket(ONE_MINUTE);
metric.mutable_value_field()->set_field(tagId);
metric.mutable_value_field()->add_child()->set_field(2);
+ metric.set_max_pull_delay_sec(INT_MAX);
UidMap uidMap;
SimpleAtomMatcher atomMatcher;
@@ -610,10 +612,9 @@
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
- EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
.WillOnce(Return(true))
- .WillOnce(Invoke([](int tagId, int64_t timeNs,
- vector<std::shared_ptr<LogEvent>>* data) {
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 149);
event->write(tagId);
@@ -661,6 +662,7 @@
metric.mutable_value_field()->set_field(tagId);
metric.mutable_value_field()->add_child()->set_field(2);
metric.set_condition(StringToId("SCREEN_ON"));
+ metric.set_max_pull_delay_sec(INT_MAX);
UidMap uidMap;
SimpleAtomMatcher atomMatcher;
@@ -672,9 +674,8 @@
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
- EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
- .WillOnce(Invoke([](int tagId, int64_t timeNs,
- vector<std::shared_ptr<LogEvent>>* data) {
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
event->write(tagId);
@@ -683,8 +684,7 @@
data->push_back(event);
return true;
}))
- .WillOnce(Invoke([](int tagId, int64_t timeNs,
- vector<std::shared_ptr<LogEvent>>* data) {
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs - 100);
event->write(tagId);
@@ -924,6 +924,7 @@
metric.set_bucket(ONE_MINUTE);
metric.mutable_value_field()->set_field(tagId);
metric.mutable_value_field()->add_child()->set_field(2);
+ metric.set_max_pull_delay_sec(INT_MAX);
UidMap uidMap;
SimpleAtomMatcher atomMatcher;
@@ -935,7 +936,7 @@
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
- EXPECT_CALL(*pullerManager, Pull(tagId, _, _)).WillOnce(Return(true));
+ EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(true));
ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
logEventMatcherIndex, eventMatcherWizard, tagId,
@@ -1012,6 +1013,7 @@
metric.mutable_value_field()->set_field(tagId);
metric.mutable_value_field()->add_child()->set_field(2);
metric.set_condition(StringToId("SCREEN_ON"));
+ metric.set_max_pull_delay_sec(INT_MAX);
UidMap uidMap;
SimpleAtomMatcher atomMatcher;
@@ -1024,10 +1026,9 @@
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
- EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
// condition becomes true
- .WillOnce(Invoke([](int tagId, int64_t timeNs,
- vector<std::shared_ptr<LogEvent>>* data) {
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 8);
event->write(tagId);
@@ -1037,8 +1038,7 @@
return true;
}))
// condition becomes false
- .WillOnce(Invoke([](int tagId, int64_t timeNs,
- vector<std::shared_ptr<LogEvent>>* data) {
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
event->write(tagId);
@@ -1098,6 +1098,7 @@
metric.mutable_value_field()->set_field(tagId);
metric.mutable_value_field()->add_child()->set_field(2);
metric.set_condition(StringToId("SCREEN_ON"));
+ metric.set_max_pull_delay_sec(INT_MAX);
UidMap uidMap;
SimpleAtomMatcher atomMatcher;
@@ -1110,10 +1111,9 @@
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillRepeatedly(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
- EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
// condition becomes true
- .WillOnce(Invoke([](int tagId, int64_t timeNs,
- vector<std::shared_ptr<LogEvent>>* data) {
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 8);
event->write(tagId);
@@ -1123,8 +1123,7 @@
return true;
}))
// condition becomes false
- .WillOnce(Invoke([](int tagId, int64_t timeNs,
- vector<std::shared_ptr<LogEvent>>* data) {
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
event->write(tagId);
@@ -1134,8 +1133,7 @@
return true;
}))
// condition becomes true again
- .WillOnce(Invoke([](int tagId, int64_t timeNs,
- vector<std::shared_ptr<LogEvent>>* data) {
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 25);
event->write(tagId);
@@ -1480,6 +1478,7 @@
metric.mutable_dimensions_in_what()->set_field(tagId);
metric.mutable_dimensions_in_what()->add_child()->set_field(1);
metric.set_use_zero_default_base(true);
+ metric.set_max_pull_delay_sec(INT_MAX);
UidMap uidMap;
SimpleAtomMatcher atomMatcher;
@@ -1491,9 +1490,8 @@
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
- EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
- .WillOnce(Invoke([](int tagId, int64_t timeNs,
- vector<std::shared_ptr<LogEvent>>* data) {
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs);
event->write(1);
@@ -1565,6 +1563,7 @@
metric.mutable_dimensions_in_what()->set_field(tagId);
metric.mutable_dimensions_in_what()->add_child()->set_field(1);
metric.set_use_zero_default_base(true);
+ metric.set_max_pull_delay_sec(INT_MAX);
UidMap uidMap;
SimpleAtomMatcher atomMatcher;
@@ -1576,9 +1575,8 @@
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
- EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
- .WillOnce(Invoke([](int tagId, int64_t timeNs,
- vector<std::shared_ptr<LogEvent>>* data) {
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs);
event->write(1);
@@ -1692,6 +1690,7 @@
metric.mutable_value_field()->add_child()->set_field(2);
metric.mutable_dimensions_in_what()->set_field(tagId);
metric.mutable_dimensions_in_what()->add_child()->set_field(1);
+ metric.set_max_pull_delay_sec(INT_MAX);
UidMap uidMap;
SimpleAtomMatcher atomMatcher;
@@ -1703,9 +1702,8 @@
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
- EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
- .WillOnce(Invoke([](int tagId, int64_t timeNs,
- vector<std::shared_ptr<LogEvent>>* data) {
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs);
event->write(1);
@@ -1804,6 +1802,128 @@
EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
}
+TEST(ValueMetricProducerTest, TestResetBaseOnPullFail) {
+ ValueMetric metric;
+ metric.set_id(metricId);
+ metric.set_bucket(ONE_MINUTE);
+ metric.mutable_value_field()->set_field(tagId);
+ metric.mutable_value_field()->add_child()->set_field(2);
+ metric.set_condition(StringToId("SCREEN_ON"));
+ metric.set_max_pull_delay_sec(INT_MAX);
+
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard =
+ new EventMatcherWizard({new SimpleLogMatchingTracker(
+ atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+ EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
+
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 8);
+ event->write(tagId);
+ event->write(100);
+ event->init();
+ data->push_back(event);
+ return true;
+ }))
+ .WillOnce(Return(false));
+
+ ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
+ eventMatcherWizard, tagId, bucketStartTimeNs,
+ bucketStartTimeNs, pullerManager);
+
+ valueProducer.onConditionChanged(true, bucketStartTimeNs + 8);
+
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ValueMetricProducer::Interval& curInterval =
+ valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ EXPECT_EQ(true, curInterval.hasBase);
+ EXPECT_EQ(100, curInterval.base.long_value);
+ EXPECT_EQ(false, curInterval.hasValue);
+ EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+
+ valueProducer.onConditionChanged(false, bucketStartTimeNs + 20);
+
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ EXPECT_EQ(false, curInterval.hasValue);
+ EXPECT_EQ(false, curInterval.hasBase);
+ EXPECT_EQ(false, valueProducer.mHasGlobalBase);
+}
+
+TEST(ValueMetricProducerTest, TestResetBaseOnPullTooLate) {
+ ValueMetric metric;
+ metric.set_id(metricId);
+ metric.set_bucket(ONE_MINUTE);
+ metric.mutable_value_field()->set_field(tagId);
+ metric.mutable_value_field()->add_child()->set_field(2);
+ metric.set_condition(StringToId("SCREEN_ON"));
+ metric.set_max_pull_delay_sec(0);
+
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard =
+ new EventMatcherWizard({new SimpleLogMatchingTracker(
+ atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+ EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
+
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
+ event->write(tagId);
+ event->write(120);
+ event->init();
+ data->push_back(event);
+ return true;
+ }));
+
+ ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
+ eventMatcherWizard, tagId, bucketStartTimeNs,
+ bucketStartTimeNs, pullerManager);
+
+ valueProducer.mCondition = true;
+ valueProducer.mHasGlobalBase = true;
+
+ vector<shared_ptr<LogEvent>> allData;
+ allData.clear();
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
+ event->write(1);
+ event->write(110);
+ event->init();
+ allData.push_back(event);
+ valueProducer.onDataPulled(allData);
+
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ValueMetricProducer::Interval& curInterval =
+ valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ EXPECT_EQ(true, curInterval.hasBase);
+ EXPECT_EQ(110, curInterval.base.long_value);
+ EXPECT_EQ(false, curInterval.hasValue);
+ EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+ EXPECT_EQ(true, valueProducer.mHasGlobalBase);
+
+ valueProducer.onConditionChanged(false, bucket2StartTimeNs + 1);
+
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ EXPECT_EQ(false, curInterval.hasValue);
+ EXPECT_EQ(false, curInterval.hasBase);
+ EXPECT_EQ(false, valueProducer.mHasGlobalBase);
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/tests/metrics/metrics_test_helper.h b/cmds/statsd/tests/metrics/metrics_test_helper.h
index 5afaba6..97c1072 100644
--- a/cmds/statsd/tests/metrics/metrics_test_helper.h
+++ b/cmds/statsd/tests/metrics/metrics_test_helper.h
@@ -38,8 +38,7 @@
MOCK_METHOD4(RegisterReceiver, void(int tagId, wp<PullDataReceiver> receiver,
int64_t nextPulltimeNs, int64_t intervalNs));
MOCK_METHOD2(UnRegisterReceiver, void(int tagId, wp<PullDataReceiver> receiver));
- MOCK_METHOD3(Pull, bool(const int pullCode, const int64_t timeNs,
- vector<std::shared_ptr<LogEvent>>* data));
+ MOCK_METHOD2(Pull, bool(const int pullCode, vector<std::shared_ptr<LogEvent>>* data));
};
class MockUidMap : public UidMap {
diff --git a/cmds/statsd/tests/shell/ShellSubscriber_test.cpp b/cmds/statsd/tests/shell/ShellSubscriber_test.cpp
index dd00561..a184f56 100644
--- a/cmds/statsd/tests/shell/ShellSubscriber_test.cpp
+++ b/cmds/statsd/tests/shell/ShellSubscriber_test.cpp
@@ -189,23 +189,22 @@
sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, Pull(10016, _, _))
- .WillRepeatedly(
- Invoke([](int tagId, int64_t timeNs, vector<std::shared_ptr<LogEvent>>* data) {
- data->clear();
- shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, timeNs);
- event->write(kUid1);
- event->write(kCpuTime1);
- event->init();
- data->push_back(event);
- // another event
- event = make_shared<LogEvent>(tagId, timeNs);
- event->write(kUid2);
- event->write(kCpuTime2);
- event->init();
- data->push_back(event);
- return true;
- }));
+ EXPECT_CALL(*pullerManager, Pull(10016, _))
+ .WillRepeatedly(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, 1111L);
+ event->write(kUid1);
+ event->write(kCpuTime1);
+ event->init();
+ data->push_back(event);
+ // another event
+ event = make_shared<LogEvent>(tagId, 1111L);
+ event->write(kUid2);
+ event->write(kCpuTime2);
+ event->init();
+ data->push_back(event);
+ return true;
+ }));
runShellTest(getPulledConfig(), uidMap, pullerManager, vector<std::shared_ptr<LogEvent>>(),
getExpectedShellData());
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index a782ced..aad3253 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -1638,46 +1638,6 @@
return true;
}
- /**
- * @hide
- */
- public static boolean areAnyScreenOffEffectsSuppressed(int effects) {
- for (int i = 0; i < SCREEN_OFF_SUPPRESSED_EFFECTS.length; i++) {
- final int effect = SCREEN_OFF_SUPPRESSED_EFFECTS[i];
- if ((effects & effect) != 0) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * @hide
- */
- public static boolean areAnyScreenOnEffectsSuppressed(int effects) {
- for (int i = 0; i < SCREEN_ON_SUPPRESSED_EFFECTS.length; i++) {
- final int effect = SCREEN_ON_SUPPRESSED_EFFECTS[i];
- if ((effects & effect) != 0) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * @hide
- */
- public static int toggleScreenOffEffectsSuppressed(int currentEffects, boolean suppress) {
- return toggleEffects(currentEffects, SCREEN_OFF_SUPPRESSED_EFFECTS, suppress);
- }
-
- /**
- * @hide
- */
- public static int toggleScreenOnEffectsSuppressed(int currentEffects, boolean suppress) {
- return toggleEffects(currentEffects, SCREEN_ON_SUPPRESSED_EFFECTS, suppress);
- }
-
private static int toggleEffects(int currentEffects, int[] effects, boolean suppress) {
for (int i = 0; i < effects.length; i++) {
final int effect = effects[i];
@@ -1837,6 +1797,41 @@
return priorityMessageSenders;
}
+ /** @hide **/
+ public boolean showFullScreenIntents() {
+ return (suppressedVisualEffects & SUPPRESSED_EFFECT_FULL_SCREEN_INTENT) == 0;
+ }
+
+ /** @hide **/
+ public boolean showLights() {
+ return (suppressedVisualEffects & SUPPRESSED_EFFECT_LIGHTS) == 0;
+ }
+
+ /** @hide **/
+ public boolean showPeeking() {
+ return (suppressedVisualEffects & SUPPRESSED_EFFECT_PEEK) == 0;
+ }
+
+ /** @hide **/
+ public boolean showStatusBarIcons() {
+ return (suppressedVisualEffects & SUPPRESSED_EFFECT_STATUS_BAR) == 0;
+ }
+
+ /** @hide **/
+ public boolean showAmbient() {
+ return (suppressedVisualEffects & SUPPRESSED_EFFECT_AMBIENT) == 0;
+ }
+
+ /** @hide **/
+ public boolean showBadges() {
+ return (suppressedVisualEffects & SUPPRESSED_EFFECT_BADGE) == 0;
+ }
+
+ /** @hide **/
+ public boolean showInNotificationList() {
+ return (suppressedVisualEffects & SUPPRESSED_EFFECT_NOTIFICATION_LIST) == 0;
+ }
+
/**
* returns a deep copy of this policy
* @hide
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 001e328..6f12cad 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -691,7 +691,8 @@
*
* @see android.content.res.Resources.Theme#obtainStyledAttributes(int[])
*/
- public final TypedArray obtainStyledAttributes(@StyleableRes int[] attrs) {
+ @NonNull
+ public final TypedArray obtainStyledAttributes(@NonNull @StyleableRes int[] attrs) {
return getTheme().obtainStyledAttributes(attrs);
}
@@ -702,8 +703,9 @@
*
* @see android.content.res.Resources.Theme#obtainStyledAttributes(int, int[])
*/
- public final TypedArray obtainStyledAttributes(
- @StyleRes int resid, @StyleableRes int[] attrs) throws Resources.NotFoundException {
+ @NonNull
+ public final TypedArray obtainStyledAttributes(@StyleRes int resid,
+ @NonNull @StyleableRes int[] attrs) throws Resources.NotFoundException {
return getTheme().obtainStyledAttributes(resid, attrs);
}
@@ -714,8 +716,9 @@
*
* @see android.content.res.Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)
*/
+ @NonNull
public final TypedArray obtainStyledAttributes(
- AttributeSet set, @StyleableRes int[] attrs) {
+ @Nullable AttributeSet set, @NonNull @StyleableRes int[] attrs) {
return getTheme().obtainStyledAttributes(set, attrs, 0, 0);
}
@@ -726,8 +729,9 @@
*
* @see android.content.res.Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)
*/
- public final TypedArray obtainStyledAttributes(
- AttributeSet set, @StyleableRes int[] attrs, @AttrRes int defStyleAttr,
+ @NonNull
+ public final TypedArray obtainStyledAttributes(@Nullable AttributeSet set,
+ @NonNull @StyleableRes int[] attrs, @AttrRes int defStyleAttr,
@StyleRes int defStyleRes) {
return getTheme().obtainStyledAttributes(
set, attrs, defStyleAttr, defStyleRes);
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 623bdda..f06df3d 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -145,6 +145,15 @@
public static final String ACTION_SESSION_COMMITTED =
"android.content.pm.action.SESSION_COMMITTED";
+ /**
+ * Broadcast Action: Send information about a staged install session when its state is updated.
+ * <p>
+ * The associated session information is defined in {@link #EXTRA_SESSION}.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_SESSION_UPDATED =
+ "android.content.pm.action.SESSION_UPDATED";
+
/** {@hide} */
public static final String ACTION_CONFIRM_INSTALL = "android.content.pm.action.CONFIRM_INSTALL";
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 88b1c88..365ceac 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -1468,7 +1468,8 @@
* @see #obtainStyledAttributes(int, int[])
* @see #obtainStyledAttributes(AttributeSet, int[], int, int)
*/
- public TypedArray obtainStyledAttributes(@StyleableRes int[] attrs) {
+ @NonNull
+ public TypedArray obtainStyledAttributes(@NonNull @StyleableRes int[] attrs) {
return mThemeImpl.obtainStyledAttributes(this, null, attrs, 0, 0);
}
@@ -1493,7 +1494,9 @@
* @see #obtainStyledAttributes(int[])
* @see #obtainStyledAttributes(AttributeSet, int[], int, int)
*/
- public TypedArray obtainStyledAttributes(@StyleRes int resId, @StyleableRes int[] attrs)
+ @NonNull
+ public TypedArray obtainStyledAttributes(@StyleRes int resId,
+ @NonNull @StyleableRes int[] attrs)
throws NotFoundException {
return mThemeImpl.obtainStyledAttributes(this, null, attrs, 0, resId);
}
@@ -1547,8 +1550,10 @@
* @see #obtainStyledAttributes(int[])
* @see #obtainStyledAttributes(int, int[])
*/
- public TypedArray obtainStyledAttributes(AttributeSet set,
- @StyleableRes int[] attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
+ @NonNull
+ public TypedArray obtainStyledAttributes(@Nullable AttributeSet set,
+ @NonNull @StyleableRes int[] attrs, @AttrRes int defStyleAttr,
+ @StyleRes int defStyleRes) {
return mThemeImpl.obtainStyledAttributes(this, set, attrs, defStyleAttr, defStyleRes);
}
diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java
index f01d5b1..015146466 100644
--- a/core/java/android/preference/SeekBarVolumizer.java
+++ b/core/java/android/preference/SeekBarVolumizer.java
@@ -123,7 +123,7 @@
mContext = context;
mAudioManager = context.getSystemService(AudioManager.class);
mNotificationManager = context.getSystemService(NotificationManager.class);
- mNotificationPolicy = mNotificationManager.getNotificationPolicy();
+ mNotificationPolicy = mNotificationManager.getConsolidatedNotificationPolicy();
mAllowAlarms = (mNotificationPolicy.priorityCategories & NotificationManager.Policy
.PRIORITY_CATEGORY_ALARMS) != 0;
mAllowMedia = (mNotificationPolicy.priorityCategories & NotificationManager.Policy
@@ -485,7 +485,7 @@
mZenMode = mNotificationManager.getZenMode();
updateSlider();
} else if (NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED.equals(action)) {
- mNotificationPolicy = mNotificationManager.getNotificationPolicy();
+ mNotificationPolicy = mNotificationManager.getConsolidatedNotificationPolicy();
mAllowAlarms = (mNotificationPolicy.priorityCategories & NotificationManager.Policy
.PRIORITY_CATEGORY_ALARMS) != 0;
mAllowMedia = (mNotificationPolicy.priorityCategories
diff --git a/core/java/android/service/autofill/augmented/FillWindow.java b/core/java/android/service/autofill/augmented/FillWindow.java
index 27df845..bad7ddd 100644
--- a/core/java/android/service/autofill/augmented/FillWindow.java
+++ b/core/java/android/service/autofill/augmented/FillWindow.java
@@ -163,14 +163,15 @@
final int height = rect.bottom - rect.top;
final int width = rect.right - rect.left;
final WindowManager.LayoutParams windowParams = window.getAttributes();
- windowParams.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
- windowParams.y = rect.top - height;
+ windowParams.gravity = Gravity.TOP | Gravity.LEFT;
+ windowParams.y = rect.top + height;
windowParams.height = height;
windowParams.x = rect.left;
windowParams.width = width;
window.setAttributes(windowParams);
window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
+ window.setBackgroundDrawableResource(android.R.color.transparent);
mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
final ViewGroup.LayoutParams diagParams = new ViewGroup.LayoutParams(width, height);
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 6792c69..bec654a 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -16,7 +16,6 @@
package android.service.notification;
-import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_REMINDERS;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
@@ -126,6 +125,15 @@
private static final String STATE_TAG = "state";
private static final String STATE_ATT_CHANNELS_BYPASSING_DND = "areChannelsBypassingDnd";
+ // zen policy visual effects attributes
+ private static final String SHOW_ATT_FULL_SCREEN_INTENT = "showFullScreenIntent";
+ private static final String SHOW_ATT_LIGHTS = "showLights";
+ private static final String SHOW_ATT_PEEK = "shoePeek";
+ private static final String SHOW_ATT_STATUS_BAR_ICONS = "showStatusBarIcons";
+ private static final String SHOW_ATT_BADGES = "showBadges";
+ private static final String SHOW_ATT_AMBIENT = "showAmbient";
+ private static final String SHOW_ATT_NOTIFICATION_LIST = "showNotificationList";
+
private static final String CONDITION_ATT_ID = "id";
private static final String CONDITION_ATT_SUMMARY = "summary";
private static final String CONDITION_ATT_LINE1 = "line1";
@@ -134,6 +142,8 @@
private static final String CONDITION_ATT_STATE = "state";
private static final String CONDITION_ATT_FLAGS = "flags";
+ private static final String ZEN_POLICY_TAG = "zen_policy";
+
private static final String MANUAL_TAG = "manual";
private static final String AUTOMATIC_TAG = "automatic";
@@ -650,6 +660,7 @@
rt.zenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
}
rt.modified = safeBoolean(parser, RULE_ATT_MODIFIED, false);
+ rt.zenPolicy = readZenPolicyXml(parser);
return rt;
}
@@ -676,6 +687,9 @@
if (rule.condition != null) {
writeConditionXml(rule.condition, out);
}
+ if (rule.zenPolicy != null) {
+ writeZenPolicyXml(rule.zenPolicy, out);
+ }
out.attribute(null, RULE_ATT_MODIFIED, Boolean.toString(rule.modified));
}
@@ -706,6 +720,141 @@
out.attribute(null, CONDITION_ATT_FLAGS, Integer.toString(c.flags));
}
+ /**
+ * Read the zen policy from xml
+ * Returns null if no zen policy exists
+ */
+ public static ZenPolicy readZenPolicyXml(XmlPullParser parser) {
+ boolean policySet = false;
+
+ ZenPolicy.Builder builder = new ZenPolicy.Builder();
+ final int calls = safeInt(parser, ALLOW_ATT_CALLS_FROM, ZenPolicy.PEOPLE_TYPE_UNSET);
+ final int messages = safeInt(parser, ALLOW_ATT_MESSAGES_FROM, ZenPolicy.PEOPLE_TYPE_UNSET);
+ final int repeatCallers = safeInt(parser, ALLOW_ATT_REPEAT_CALLERS, ZenPolicy.STATE_UNSET);
+ final int alarms = safeInt(parser, ALLOW_ATT_ALARMS, ZenPolicy.STATE_UNSET);
+ final int media = safeInt(parser, ALLOW_ATT_MEDIA, ZenPolicy.STATE_UNSET);
+ final int system = safeInt(parser, ALLOW_ATT_SYSTEM, ZenPolicy.STATE_UNSET);
+ final int events = safeInt(parser, ALLOW_ATT_EVENTS, ZenPolicy.STATE_UNSET);
+ final int reminders = safeInt(parser, ALLOW_ATT_REMINDERS, ZenPolicy.STATE_UNSET);
+
+ if (calls != ZenPolicy.PEOPLE_TYPE_UNSET) {
+ builder.allowCalls(calls);
+ policySet = true;
+ }
+ if (messages != ZenPolicy.PEOPLE_TYPE_UNSET) {
+ builder.allowMessages(messages);
+ policySet = true;
+ }
+ if (repeatCallers != ZenPolicy.STATE_UNSET) {
+ builder.allowRepeatCallers(repeatCallers == ZenPolicy.STATE_ALLOW);
+ policySet = true;
+ }
+ if (alarms != ZenPolicy.STATE_UNSET) {
+ builder.allowAlarms(alarms == ZenPolicy.STATE_ALLOW);
+ policySet = true;
+ }
+ if (media != ZenPolicy.STATE_UNSET) {
+ builder.allowMedia(media == ZenPolicy.STATE_ALLOW);
+ policySet = true;
+ }
+ if (system != ZenPolicy.STATE_UNSET) {
+ builder.allowSystem(system == ZenPolicy.STATE_ALLOW);
+ policySet = true;
+ }
+ if (events != ZenPolicy.STATE_UNSET) {
+ builder.allowEvents(events == ZenPolicy.STATE_ALLOW);
+ policySet = true;
+ }
+ if (reminders != ZenPolicy.STATE_UNSET) {
+ builder.allowReminders(reminders == ZenPolicy.STATE_ALLOW);
+ policySet = true;
+ }
+
+ final int fullScreenIntent = safeInt(parser, SHOW_ATT_FULL_SCREEN_INTENT,
+ ZenPolicy.STATE_UNSET);
+ final int lights = safeInt(parser, SHOW_ATT_LIGHTS, ZenPolicy.STATE_UNSET);
+ final int peek = safeInt(parser, SHOW_ATT_PEEK, ZenPolicy.STATE_UNSET);
+ final int statusBar = safeInt(parser, SHOW_ATT_STATUS_BAR_ICONS, ZenPolicy.STATE_UNSET);
+ final int badges = safeInt(parser, SHOW_ATT_BADGES, ZenPolicy.STATE_UNSET);
+ final int ambient = safeInt(parser, SHOW_ATT_AMBIENT, ZenPolicy.STATE_UNSET);
+ final int notificationList = safeInt(parser, SHOW_ATT_NOTIFICATION_LIST,
+ ZenPolicy.STATE_UNSET);
+
+ if (fullScreenIntent != ZenPolicy.STATE_UNSET) {
+ builder.showFullScreenIntent(fullScreenIntent == ZenPolicy.STATE_ALLOW);
+ policySet = true;
+ }
+ if (lights != ZenPolicy.STATE_UNSET) {
+ builder.showLights(lights == ZenPolicy.STATE_ALLOW);
+ policySet = true;
+ }
+ if (peek != ZenPolicy.STATE_UNSET) {
+ builder.showPeeking(peek == ZenPolicy.STATE_ALLOW);
+ policySet = true;
+ }
+ if (statusBar != ZenPolicy.STATE_UNSET) {
+ builder.showStatusBarIcons(statusBar == ZenPolicy.STATE_ALLOW);
+ policySet = true;
+ }
+ if (badges != ZenPolicy.STATE_UNSET) {
+ builder.showBadges(badges == ZenPolicy.STATE_ALLOW);
+ policySet = true;
+ }
+ if (ambient != ZenPolicy.STATE_UNSET) {
+ builder.showInAmbientDisplay(ambient == ZenPolicy.STATE_ALLOW);
+ policySet = true;
+ }
+ if (notificationList != ZenPolicy.STATE_UNSET) {
+ builder.showInNotificationList(notificationList == ZenPolicy.STATE_ALLOW);
+ policySet = true;
+ }
+
+ if (policySet) {
+ return builder.build();
+ }
+ return null;
+ }
+
+ /**
+ * Writes zen policy to xml
+ */
+ public static void writeZenPolicyXml(ZenPolicy policy, XmlSerializer out)
+ throws IOException {
+ writeZenPolicyState(ALLOW_ATT_CALLS_FROM, policy.getPriorityCallSenders(), out);
+ writeZenPolicyState(ALLOW_ATT_MESSAGES_FROM, policy.getPriorityMessageSenders(), out);
+ writeZenPolicyState(ALLOW_ATT_REPEAT_CALLERS, policy.getPriorityCategoryRepeatCallers(),
+ out);
+ writeZenPolicyState(ALLOW_ATT_ALARMS, policy.getPriorityCategoryAlarms(), out);
+ writeZenPolicyState(ALLOW_ATT_MEDIA, policy.getPriorityCategoryMedia(), out);
+ writeZenPolicyState(ALLOW_ATT_SYSTEM, policy.getPriorityCategorySystem(), out);
+ writeZenPolicyState(ALLOW_ATT_REMINDERS, policy.getPriorityCategoryReminders(), out);
+ writeZenPolicyState(ALLOW_ATT_EVENTS, policy.getPriorityCategoryEvents(), out);
+
+ writeZenPolicyState(SHOW_ATT_FULL_SCREEN_INTENT, policy.getVisualEffectFullScreenIntent(),
+ out);
+ writeZenPolicyState(SHOW_ATT_LIGHTS, policy.getVisualEffectLights(), out);
+ writeZenPolicyState(SHOW_ATT_PEEK, policy.getVisualEffectPeek(), out);
+ writeZenPolicyState(SHOW_ATT_STATUS_BAR_ICONS, policy.getVisualEffectStatusBar(), out);
+ writeZenPolicyState(SHOW_ATT_BADGES, policy.getVisualEffectBadge(), out);
+ writeZenPolicyState(SHOW_ATT_AMBIENT, policy.getVisualEffectAmbient(), out);
+ writeZenPolicyState(SHOW_ATT_NOTIFICATION_LIST, policy.getVisualEffectNotificationList(),
+ out);
+ }
+
+ private static void writeZenPolicyState(String attr, int val, XmlSerializer out)
+ throws IOException {
+ if (Objects.equals(attr, ALLOW_ATT_CALLS_FROM)
+ || Objects.equals(attr, ALLOW_ATT_MESSAGES_FROM)) {
+ if (val != ZenPolicy.PEOPLE_TYPE_UNSET) {
+ out.attribute(null, attr, Integer.toString(val));
+ }
+ } else {
+ if (val != ZenPolicy.STATE_UNSET) {
+ out.attribute(null, attr, Integer.toString(val));
+ }
+ }
+ }
+
public static boolean isValidHour(int val) {
return val >= 0 && val < 24;
}
@@ -798,7 +947,7 @@
if (zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_REMINDERS,
isPriorityCategoryEnabled(Policy.PRIORITY_CATEGORY_REMINDERS, defaultPolicy))) {
- priorityCategories |= PRIORITY_CATEGORY_REMINDERS;
+ priorityCategories |= Policy.PRIORITY_CATEGORY_REMINDERS;
}
if (zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_EVENTS,
@@ -839,15 +988,30 @@
priorityCategories |= Policy.PRIORITY_CATEGORY_SYSTEM;
}
- if (!zenPolicy.isVisualEffectAllowed(ZenPolicy.VISUAL_EFFECT_FULL_SCREEN_INTENT,
+ boolean suppressFullScreenIntent = !zenPolicy.isVisualEffectAllowed(
+ ZenPolicy.VISUAL_EFFECT_FULL_SCREEN_INTENT,
isVisualEffectAllowed(Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT,
- defaultPolicy))) {
+ defaultPolicy));
+
+ boolean suppressLights = !zenPolicy.isVisualEffectAllowed(
+ ZenPolicy.VISUAL_EFFECT_LIGHTS,
+ isVisualEffectAllowed(Policy.SUPPRESSED_EFFECT_LIGHTS,
+ defaultPolicy));
+
+ boolean suppressAmbient = !zenPolicy.isVisualEffectAllowed(
+ ZenPolicy.VISUAL_EFFECT_AMBIENT,
+ isVisualEffectAllowed(Policy.SUPPRESSED_EFFECT_AMBIENT,
+ defaultPolicy));
+
+ if (suppressFullScreenIntent && suppressLights && suppressAmbient) {
+ suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
+ }
+
+ if (suppressFullScreenIntent) {
suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
}
- if (!zenPolicy.isVisualEffectAllowed(ZenPolicy.VISUAL_EFFECT_LIGHTS,
- isVisualEffectAllowed(Policy.SUPPRESSED_EFFECT_LIGHTS,
- defaultPolicy))) {
+ if (suppressLights) {
suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_LIGHTS;
}
@@ -855,6 +1019,7 @@
isVisualEffectAllowed(Policy.SUPPRESSED_EFFECT_PEEK,
defaultPolicy))) {
suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_PEEK;
+ suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_SCREEN_ON;
}
if (!zenPolicy.isVisualEffectAllowed(ZenPolicy.VISUAL_EFFECT_STATUS_BAR,
@@ -869,9 +1034,7 @@
suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_BADGE;
}
- if (!zenPolicy.isVisualEffectAllowed(ZenPolicy.VISUAL_EFFECT_AMBIENT,
- isVisualEffectAllowed(Policy.SUPPRESSED_EFFECT_AMBIENT,
- defaultPolicy))) {
+ if (suppressAmbient) {
suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_AMBIENT;
}
@@ -898,14 +1061,31 @@
case ZenPolicy.PEOPLE_TYPE_ANYONE:
return Policy.PRIORITY_SENDERS_ANY;
case ZenPolicy.PEOPLE_TYPE_CONTACTS:
+
return Policy.PRIORITY_SENDERS_CONTACTS;
case ZenPolicy.PEOPLE_TYPE_STARRED:
default:
return Policy.PRIORITY_SENDERS_STARRED;
}
-
}
+
+ /**
+ * Maps NotificationManager.Policy senders type to ZenPolicy.PeopleType
+ */
+ public static @ZenPolicy.PeopleType int getZenPolicySenders(int senders) {
+ switch (senders) {
+ case Policy.PRIORITY_SENDERS_ANY:
+ return ZenPolicy.PEOPLE_TYPE_ANYONE;
+ case Policy.PRIORITY_SENDERS_CONTACTS:
+ return ZenPolicy.PEOPLE_TYPE_CONTACTS;
+ case Policy.PRIORITY_SENDERS_STARRED:
+ default:
+ return ZenPolicy.PEOPLE_TYPE_STARRED;
+ }
+ }
+
+
public Policy toNotificationPolicy() {
int priorityCategories = 0;
int priorityCallSenders = Policy.PRIORITY_SENDERS_CONTACTS;
diff --git a/core/java/android/service/notification/ZenPolicy.java b/core/java/android/service/notification/ZenPolicy.java
index 194147c..6392704 100644
--- a/core/java/android/service/notification/ZenPolicy.java
+++ b/core/java/android/service/notification/ZenPolicy.java
@@ -327,6 +327,32 @@
}
/**
+ * Whether this policy hides all visual effects
+ * @hide
+ */
+ public boolean shouldHideAllVisualEffects() {
+ for (int i = 0; i < mVisualEffects.size(); i++) {
+ if (mVisualEffects.get(i) != STATE_DISALLOW) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Whether this policy shows all visual effects
+ * @hide
+ */
+ public boolean shouldShowAllVisualEffects() {
+ for (int i = 0; i < mVisualEffects.size(); i++) {
+ if (mVisualEffects.get(i) != STATE_ALLOW) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
* Builder class for {@link ZenPolicy} objects.
* Provides a convenient way to set the various fields of a {@link ZenPolicy}. If a field
* is not set, it is (@link STATE_UNSET} and will not change the current set policy.
@@ -339,6 +365,17 @@
}
/**
+ * @hide
+ */
+ public Builder(ZenPolicy policy) {
+ if (policy != null) {
+ mZenPolicy = policy.copy();
+ } else {
+ mZenPolicy = new ZenPolicy();
+ }
+ }
+
+ /**
* Builds the current ZenPolicy.
*/
public ZenPolicy build() {
@@ -533,6 +570,34 @@
}
/**
+ * Whether to allow {@link PriorityCategory} sounds to play when DND is active.
+ * @hide
+ */
+ public Builder allowCategory(@PriorityCategory int category, boolean allow) {
+ switch (category) {
+ case PRIORITY_CATEGORY_ALARMS:
+ allowAlarms(allow);
+ break;
+ case PRIORITY_CATEGORY_MEDIA:
+ allowMedia(allow);
+ break;
+ case PRIORITY_CATEGORY_SYSTEM:
+ allowSystem(allow);
+ break;
+ case PRIORITY_CATEGORY_REMINDERS:
+ allowReminders(allow);
+ break;
+ case PRIORITY_CATEGORY_EVENTS:
+ allowEvents(allow);
+ break;
+ case PRIORITY_CATEGORY_REPEAT_CALLERS:
+ allowRepeatCallers(allow);
+ break;
+ }
+ return this;
+ }
+
+ /**
* Whether {@link Notification#fullScreenIntent full screen intents} that are intercepted
* by DND are shown.
*/
@@ -601,6 +666,38 @@
show ? STATE_ALLOW : STATE_DISALLOW);
return this;
}
+
+ /**
+ * Whether notifications intercepted by DND are prevented from appearing for
+ * {@link VisualEffect}
+ * @hide
+ */
+ public Builder showVisualEffect(@VisualEffect int effect, boolean show) {
+ switch (effect) {
+ case VISUAL_EFFECT_FULL_SCREEN_INTENT:
+ showFullScreenIntent(show);
+ break;
+ case VISUAL_EFFECT_LIGHTS:
+ showLights(show);
+ break;
+ case VISUAL_EFFECT_PEEK:
+ showPeeking(show);
+ break;
+ case VISUAL_EFFECT_STATUS_BAR:
+ showStatusBarIcons(show);
+ break;
+ case VISUAL_EFFECT_BADGE:
+ showBadges(show);
+ break;
+ case VISUAL_EFFECT_AMBIENT:
+ showInAmbientDisplay(show);
+ break;
+ case VISUAL_EFFECT_NOTIFICATION_LIST:
+ showInNotificationList(show);
+ break;
+ }
+ return this;
+ }
}
@Override
@@ -640,8 +737,8 @@
.append('{')
.append("priorityCategories=[").append(priorityCategoriesToString())
.append("], visualEffects=[").append(visualEffectsToString())
- .append(", priorityCalls=").append(stateToString(mPriorityCalls))
- .append("], priorityMessages=").append(stateToString(mPriorityMessages))
+ .append("], priorityCalls=").append(peopleTypeToString(mPriorityCalls))
+ .append(", priorityMessages=").append(peopleTypeToString(mPriorityMessages))
.append('}')
.toString();
}
@@ -726,7 +823,23 @@
case STATE_ALLOW:
return "allow";
}
- return null;
+ return "invalidState{" + state + "}";
+ }
+
+ private String peopleTypeToString(@PeopleType int peopleType) {
+ switch (peopleType) {
+ case PEOPLE_TYPE_ANYONE:
+ return "anyone";
+ case PEOPLE_TYPE_CONTACTS:
+ return "contacts";
+ case PEOPLE_TYPE_NONE:
+ return "none";
+ case PEOPLE_TYPE_STARRED:
+ return "starred_contacts";
+ case STATE_UNSET:
+ return "unset";
+ }
+ return "invalidPeopleType{" + peopleType + "}";
}
@Override
@@ -859,27 +972,6 @@
/**
* @hide
*/
- public boolean areValuesSet() {
- return getPriorityCategoryReminders() != STATE_UNSET
- || getPriorityCategoryEvents() != STATE_UNSET
- || getPriorityCategoryMessages() != STATE_UNSET
- || getPriorityCategoryCalls() != STATE_UNSET
- || getPriorityCategoryRepeatCallers() != STATE_UNSET
- || getPriorityCategoryAlarms() != STATE_UNSET
- || getPriorityCategoryMedia() != STATE_UNSET
- || getPriorityCategorySystem() != STATE_UNSET
- || getVisualEffectFullScreenIntent() != STATE_UNSET
- || getVisualEffectLights() != STATE_UNSET
- || getVisualEffectPeek() != STATE_UNSET
- || getVisualEffectStatusBar() != STATE_UNSET
- || getVisualEffectBadge() != STATE_UNSET
- || getVisualEffectAmbient() != STATE_UNSET
- || getVisualEffectNotificationList() != STATE_UNSET;
- }
-
- /**
- * @hide
- */
public void writeToProto(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 9dfd43c..330d72f 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -107,12 +107,6 @@
*/
void endProlongedAnimations();
- // Re-evaluate the current orientation from the caller's state.
- // If there is a change, the new Configuration is returned and the
- // caller must call setNewConfiguration() sometime later.
- Configuration updateOrientationFromAppTokens(in Configuration currentConfig,
- IBinder freezeThisOneIfNeeded, int displayId);
-
void startFreezingScreen(int exitAnim, int enterAnim);
void stopFreezingScreen();
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 699b34a..56f973e 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -77,7 +77,6 @@
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-
//TODO: use java.lang.ref.Cleaner once Android supports Java 9
import sun.misc.Cleaner;
@@ -2966,12 +2965,13 @@
if (afm == null) return null;
final View view = afm.getClient().autofillClientFindViewByAutofillIdTraversal(id);
- // TODO(b/111330312): optimize (for example, use temp rect from attach info) and
- // fix (for example, take system status bar height into account) logic below
+ final Rect windowVisibleDisplayFrame = new Rect();
+ view.getWindowVisibleDisplayFrame(windowVisibleDisplayFrame);
final int[] location = new int[2];
view.getLocationOnScreen(location);
- final Rect rect = new Rect(location[0], location[1], location[0] + view.getWidth(),
- location[1] + view.getHeight());
+ final Rect rect = new Rect(location[0], location[1] - windowVisibleDisplayFrame.top,
+ location[0] + view.getWidth(),
+ location[1] - windowVisibleDisplayFrame.top + view.getHeight());
if (sVerbose) {
Log.v(TAG, "Coordinates for " + id + ": " + rect);
}
diff --git a/core/java/android/webkit/UserPackage.java b/core/java/android/webkit/UserPackage.java
index 03ff0ca..8a1a0b5 100644
--- a/core/java/android/webkit/UserPackage.java
+++ b/core/java/android/webkit/UserPackage.java
@@ -34,7 +34,7 @@
private final UserInfo mUserInfo;
private final PackageInfo mPackageInfo;
- public static final int MINIMUM_SUPPORTED_SDK = Build.VERSION_CODES.P;
+ public static final int MINIMUM_SUPPORTED_SDK = Build.VERSION_CODES.Q;
public UserPackage(UserInfo user, PackageInfo packageInfo) {
this.mUserInfo = user;
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 46b1f6e..6d88530 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -47,7 +47,7 @@
// visible for WebViewZygoteInit to look up the class by reflection and call preloadInZygote.
/** @hide */
private static final String CHROMIUM_WEBVIEW_FACTORY =
- "com.android.webview.chromium.WebViewChromiumFactoryProviderForP";
+ "com.android.webview.chromium.WebViewChromiumFactoryProviderForQ";
private static final String CHROMIUM_WEBVIEW_FACTORY_METHOD = "create";
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 299798b..c6343a8 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -611,6 +611,7 @@
<protected-broadcast android:name="android.intent.action.DOCK_ACTIVE" />
<!-- Added in Q -->
+ <protected-broadcast android:name="android.content.pm.action.SESSION_UPDATED" />
<!-- For CarIdlenessTracker -->
<protected-broadcast android:name="com.android.server.jobscheduler.GARAGE_MODE_ON" />
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index fc813d2..4de25f9 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -932,10 +932,6 @@
fDL->drawAnnotation(rect, key, val);
}
-void RecordingCanvas::onDrawTextRSXform(const void* text, size_t bytes, const SkRSXform xform[],
- const SkRect* cull, const SkPaint& paint) {
- fDL->drawTextRSXform(text, bytes, xform, cull, paint);
-}
void RecordingCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
const SkPaint& paint) {
fDL->drawTextBlob(blob, x, y, paint);
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index 22b3a63..ae3c4f05 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -173,8 +173,6 @@
void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override;
void onDrawAnnotation(const SkRect&, const char[], SkData*) override;
- void onDrawTextRSXform(const void*, size_t, const SkRSXform[], const SkRect*,
- const SkPaint&) override;
void onDrawTextBlob(const SkTextBlob*, SkScalar, SkScalar, const SkPaint&) override;
void onDrawBitmap(const SkBitmap&, SkScalar, SkScalar, const SkPaint*) override;
diff --git a/libs/hwui/pipeline/skia/DumpOpsCanvas.h b/libs/hwui/pipeline/skia/DumpOpsCanvas.h
index 2b5d580..0eb526a 100644
--- a/libs/hwui/pipeline/skia/DumpOpsCanvas.h
+++ b/libs/hwui/pipeline/skia/DumpOpsCanvas.h
@@ -82,11 +82,6 @@
mOutput << mIdent << "drawDRRect" << std::endl;
}
- void onDrawTextRSXform(const void*, size_t, const SkRSXform[], const SkRect*,
- const SkPaint&) override {
- mOutput << mIdent << "drawTextRSXform" << std::endl;
- }
-
void onDrawTextBlob(const SkTextBlob*, SkScalar, SkScalar, const SkPaint&) override {
mOutput << mIdent << "drawTextBlob" << std::endl;
}
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
index f2906de..ff87313 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -30,7 +30,7 @@
class SkiaPipeline : public renderthread::IRenderPipeline {
public:
- SkiaPipeline(renderthread::RenderThread& thread);
+ explicit SkiaPipeline(renderthread::RenderThread& thread);
virtual ~SkiaPipeline();
TaskManager* getTaskManager() override;
diff --git a/libs/hwui/pipeline/skia/SkiaProfileRenderer.h b/libs/hwui/pipeline/skia/SkiaProfileRenderer.h
index daa4c18..dc8420f 100644
--- a/libs/hwui/pipeline/skia/SkiaProfileRenderer.h
+++ b/libs/hwui/pipeline/skia/SkiaProfileRenderer.h
@@ -23,7 +23,7 @@
class SkiaProfileRenderer : public IProfileRenderer {
public:
- SkiaProfileRenderer(SkCanvas* canvas) : mCanvas(canvas) {}
+ explicit SkiaProfileRenderer(SkCanvas* canvas) : mCanvas(canvas) {}
void drawRect(float left, float top, float right, float bottom, const SkPaint& paint) override;
void drawRects(const float* rects, int count, const SkPaint& paint) override;
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
index 02874c7..53ffc44 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
@@ -25,7 +25,7 @@
class SkiaVulkanPipeline : public SkiaPipeline {
public:
- SkiaVulkanPipeline(renderthread::RenderThread& thread);
+ explicit SkiaVulkanPipeline(renderthread::RenderThread& thread);
virtual ~SkiaVulkanPipeline() {}
renderthread::MakeCurrentResult makeCurrent() override;
diff --git a/libs/hwui/pipeline/skia/VectorDrawableAtlas.h b/libs/hwui/pipeline/skia/VectorDrawableAtlas.h
index 74e48ce..5e892aa 100644
--- a/libs/hwui/pipeline/skia/VectorDrawableAtlas.h
+++ b/libs/hwui/pipeline/skia/VectorDrawableAtlas.h
@@ -62,8 +62,8 @@
public:
enum class StorageMode { allowSharedSurface, disallowSharedSurface };
- VectorDrawableAtlas(size_t surfaceArea,
- StorageMode storageMode = StorageMode::allowSharedSurface);
+ explicit VectorDrawableAtlas(size_t surfaceArea,
+ StorageMode storageMode = StorageMode::allowSharedSurface);
/**
* "prepareForDraw" may allocate a new surface if needed. It may schedule to repack the
diff --git a/libs/hwui/tests/unit/FatalTestCanvas.h b/libs/hwui/tests/unit/FatalTestCanvas.h
index 146662b..1723c2e 100644
--- a/libs/hwui/tests/unit/FatalTestCanvas.h
+++ b/libs/hwui/tests/unit/FatalTestCanvas.h
@@ -30,10 +30,6 @@
void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) {
ADD_FAILURE() << "onDrawDRRect not expected in this test";
}
- void onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform[],
- const SkRect* cullRect, const SkPaint& paint) {
- ADD_FAILURE() << "onDrawTextRSXform not expected in this test";
- }
void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint) {
ADD_FAILURE() << "onDrawTextBlob not expected in this test";
}
@@ -116,4 +112,4 @@
int mDrawCounter = 0; // counts how may draw calls of any kind were made to this canvas
};
-}
\ No newline at end of file
+}
diff --git a/libs/incident/include/android/os/IncidentReportArgs.h b/libs/incident/include/android/os/IncidentReportArgs.h
index c56f689..ee1e33c 100644
--- a/libs/incident/include/android/os/IncidentReportArgs.h
+++ b/libs/incident/include/android/os/IncidentReportArgs.h
@@ -40,7 +40,7 @@
class IncidentReportArgs : public Parcelable {
public:
IncidentReportArgs();
- explicit IncidentReportArgs(const IncidentReportArgs& that);
+ IncidentReportArgs(const IncidentReportArgs& that);
virtual ~IncidentReportArgs();
virtual status_t writeToParcel(Parcel* out) const;
diff --git a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java
index d400159..305862a 100644
--- a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java
+++ b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java
@@ -165,8 +165,12 @@
private void bindChartDetailsView(PreferenceViewHolder holder) {
final Button detailsView = (Button) holder.findViewById(R.id.bar_chart_details);
- detailsView.setText(mDetailsId);
- detailsView.setOnClickListener(mDetailsOnClickListener);
+ if (mDetailsId == 0) {
+ detailsView.setVisibility(View.GONE);
+ } else {
+ detailsView.setText(mDetailsId);
+ detailsView.setOnClickListener(mDetailsOnClickListener);
+ }
}
private void updateBarChart(PreferenceViewHolder holder) {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java
index d4e7481..375b45c 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java
@@ -41,6 +41,7 @@
private BarView mBarView2;
private BarView mBarView3;
private BarView mBarView4;
+ private TextView mDetailsView;
private PreferenceViewHolder mHolder;
private BarChartPreference mPreference;
@@ -51,14 +52,13 @@
mHolder = PreferenceViewHolder.createInstanceForTests(mBarChartView);
mPreference = new BarChartPreference(mContext, null /* attrs */);
mPreference.setBarChartTitle(R.string.debug_app);
- mPreference.setBarChartDetails(R.string.debug_app);
-
mIcon = mContext.getDrawable(R.drawable.ic_menu);
mBarView1 = (BarView) mBarChartView.findViewById(R.id.bar_view1);
mBarView2 = (BarView) mBarChartView.findViewById(R.id.bar_view2);
mBarView3 = (BarView) mBarChartView.findViewById(R.id.bar_view3);
mBarView4 = (BarView) mBarChartView.findViewById(R.id.bar_view4);
+ mDetailsView = (TextView) mBarChartView.findViewById(R.id.bar_chart_details);
}
@Test
@@ -73,26 +73,31 @@
}
@Test
- public void setBarChartDetailsRes_setDetailsRes_showInBarChartDetails() {
- final TextView detailsView = (TextView) mBarChartView.findViewById(R.id.bar_chart_details);
+ public void onBindViewHolder_notSetDetailsRes_barChartDetailsViewIsGone() {
+ // We don't call BarChartPreference#setBarChartDetails
+ mPreference.onBindViewHolder(mHolder);
+ assertThat(mDetailsView.getVisibility()).isEqualTo(View.GONE);
+ }
+
+ @Test
+ public void setBarChartDetailsRes_setDetailsRes_showInBarChartDetails() {
mPreference.setBarChartDetails(R.string.debug_app);
mPreference.onBindViewHolder(mHolder);
- assertThat(detailsView.getVisibility()).isEqualTo(View.VISIBLE);
- assertThat(detailsView.getText()).isEqualTo(mContext.getText(R.string.debug_app));
+ assertThat(mDetailsView.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mDetailsView.getText()).isEqualTo(mContext.getText(R.string.debug_app));
}
@Test
public void setBarChartDetailsClickListener_setClickListener_detailsViewAttachClickListener() {
- final TextView detailsView = (TextView) mBarChartView.findViewById(R.id.bar_chart_details);
-
+ mPreference.setBarChartDetails(R.string.debug_app);
mPreference.setBarChartDetailsClickListener(v -> {
});
mPreference.onBindViewHolder(mHolder);
- assertThat(detailsView.getVisibility()).isEqualTo(View.VISIBLE);
- assertThat(detailsView.hasOnClickListeners()).isTrue();
+ assertThat(mDetailsView.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mDetailsView.hasOnClickListeners()).isTrue();
}
@Test
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 443e389..f51004a 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -531,10 +531,18 @@
sDependency.destroyDependency(cls, destroy);
}
+ /**
+ * @deprecated see docs/dagger.md
+ */
+ @Deprecated
public static <T> T get(Class<T> cls) {
return sDependency.getDependency(cls);
}
+ /**
+ * @deprecated see docs/dagger.md
+ */
+ @Deprecated
public static <T> T get(DependencyKey<T> cls) {
return sDependency.getDependency(cls);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 93130d4..bedba9a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -18,7 +18,7 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.app.Fragment;
+import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Bundle;
@@ -46,10 +46,11 @@
import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
import com.android.systemui.util.InjectionInflationController;
+import com.android.systemui.util.LifecycleFragment;
import javax.inject.Inject;
-public class QSFragment extends Fragment implements QS, CommandQueue.Callbacks {
+public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Callbacks {
private static final String TAG = "QS";
private static final boolean DEBUG = false;
private static final String EXTRA_EXPANDED = "expanded";
@@ -81,9 +82,12 @@
@Inject
public QSFragment(RemoteInputQuickSettingsDisabler remoteInputQsDisabler,
- InjectionInflationController injectionInflater) {
+ InjectionInflationController injectionInflater,
+ Context context) {
mRemoteInputQuickSettingsDisabler = remoteInputQsDisabler;
mInjectionInflater = injectionInflater;
+ SysUiServiceProvider.getComponent(context, CommandQueue.class)
+ .observe(getLifecycle(), this);
}
@Override
@@ -118,13 +122,6 @@
mQSPanel.getTileLayout().restoreInstanceState(savedInstanceState);
}
}
- SysUiServiceProvider.getComponent(getContext(), CommandQueue.class).addCallback(this);
- }
-
- @Override
- public void onDestroyView() {
- SysUiServiceProvider.getComponent(getContext(), CommandQueue.class).removeCallback(this);
- super.onDestroyView();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index 017cda7..017a9c3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -25,7 +25,6 @@
import android.view.View;
import android.view.ViewGroup;
-import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.statusbar.notification.NotificationData;
@@ -44,6 +43,8 @@
import javax.inject.Inject;
import javax.inject.Singleton;
+import dagger.Lazy;
+
/**
* NotificationViewHierarchyManager manages updating the view hierarchy of notification views based
* on their group structure. For example, if a notification becomes bundled with another,
@@ -60,20 +61,15 @@
mTmpChildOrderMap = new HashMap<>();
// Dependencies:
- protected final NotificationLockscreenUserManager mLockscreenUserManager =
- Dependency.get(NotificationLockscreenUserManager.class);
- protected final NotificationGroupManager mGroupManager =
- Dependency.get(NotificationGroupManager.class);
- protected final VisualStabilityManager mVisualStabilityManager =
- Dependency.get(VisualStabilityManager.class);
- private final StatusBarStateController mStatusBarStateController =
- Dependency.get(StatusBarStateController.class);
- private final NotificationEntryManager mEntryManager =
- Dependency.get(NotificationEntryManager.class);
- private final BubbleController mBubbleController = Dependency.get(BubbleController.class);
+ protected final NotificationLockscreenUserManager mLockscreenUserManager;
+ protected final NotificationGroupManager mGroupManager;
+ protected final VisualStabilityManager mVisualStabilityManager;
+ private final StatusBarStateController mStatusBarStateController;
+ private final NotificationEntryManager mEntryManager;
+ private final BubbleController mBubbleController;
// Lazy
- private ShadeController mShadeController;
+ private final Lazy<ShadeController> mShadeController;
/**
* {@code true} if notifications not part of a group should by default be rendered in their
@@ -120,20 +116,27 @@
}
}
- private ShadeController getShadeController() {
- if (mShadeController == null) {
- mShadeController = Dependency.get(ShadeController.class);
- }
- return mShadeController;
- }
-
@Inject
- public NotificationViewHierarchyManager(Context context) {
+ public NotificationViewHierarchyManager(Context context,
+ NotificationLockscreenUserManager notificationLockscreenUserManager,
+ NotificationGroupManager groupManager,
+ VisualStabilityManager visualStabilityManager,
+ StatusBarStateController statusBarStateController,
+ NotificationEntryManager notificationEntryManager,
+ BubbleController bubbleController,
+ Lazy<ShadeController> shadeController) {
+ mLockscreenUserManager = notificationLockscreenUserManager;
+ mGroupManager = groupManager;
+ mVisualStabilityManager = visualStabilityManager;
+ mStatusBarStateController = statusBarStateController;
+ mEntryManager = notificationEntryManager;
+ mBubbleController = bubbleController;
+ mShadeController = shadeController;
Resources res = context.getResources();
mAlwaysExpandNonGroupedNotification =
res.getBoolean(R.bool.config_alwaysExpandNonGroupedNotifications);
mStatusBarStateListener = new StatusBarStateListener(mBubbleController);
- Dependency.get(StatusBarStateController.class).addCallback(mStatusBarStateListener);
+ mStatusBarStateController.addCallback(mStatusBarStateListener);
}
public void setUpWithPresenter(NotificationPresenter presenter,
@@ -396,7 +399,7 @@
&& !row.isLowPriority()));
}
- entry.getRow().setOnAmbient(getShadeController().isDozing());
+ entry.getRow().setOnAmbient(mShadeController.get().isDozing());
int userId = entry.notification.getUserId();
boolean suppressedSummary = mGroupManager.isSummaryOfSuppressedGroup(
entry.notification) && !entry.isRowRemoved();
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 6a7983a..8c17922 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -276,7 +276,9 @@
@Override
public void onBackButtonVisibilityChanged(boolean visible) {
- getBackButton().setVisibility(visible ? VISIBLE : GONE);
+ if (!inScreenPinning()) {
+ getBackButton().setVisibility(visible ? VISIBLE : GONE);
+ }
}
@Override
@@ -940,6 +942,9 @@
public void showPinningEnterExitToast(boolean entering) {
if (entering) {
mScreenPinningNotify.showPinningStartToast();
+
+ // TODO(b/112934365): remove after prototype finished, only needed to escape from pin
+ getBackButton().setVisibility(VISIBLE);
} else {
mScreenPinningNotify.showPinningExitToast();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java
index 2305db0..fd030d1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java
@@ -19,7 +19,6 @@
import android.os.Handler;
import android.util.ArrayMap;
-import com.android.systemui.Dependency;
import com.android.systemui.plugins.Plugin;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.shared.plugins.PluginManager;
@@ -49,12 +48,24 @@
public static final int SORT_ORDER_DEFAULT = 4;
private final Context mDefaultContext;
+ private final LeakDetector mLeakDetector;
+ private final PluginManager mPluginManager;
+ private final TunerService mTunerService;
+ private final ConfigurationController mConfigurationController;
/**
*/
@Inject
- public ExtensionControllerImpl(Context context) {
+ public ExtensionControllerImpl(Context context,
+ LeakDetector leakDetector,
+ PluginManager pluginManager,
+ TunerService tunerService,
+ ConfigurationController configurationController) {
mDefaultContext = context;
+ mLeakDetector = leakDetector;
+ mPluginManager = pluginManager;
+ mTunerService = tunerService;
+ mConfigurationController = configurationController;
}
@Override
@@ -168,14 +179,14 @@
@Override
public void clearItem(boolean isDestroyed) {
if (isDestroyed && mItem != null) {
- Dependency.get(LeakDetector.class).trackGarbage(mItem);
+ mLeakDetector.trackGarbage(mItem);
}
mItem = null;
}
private void notifyChanged() {
if (mItem != null) {
- Dependency.get(LeakDetector.class).trackGarbage(mItem);
+ mLeakDetector.trackGarbage(mItem);
}
mItem = null;
for (int i = 0; i < mProducers.size(); i++) {
@@ -216,7 +227,7 @@
public PluginItem(String action, Class<P> cls, PluginConverter<T, P> converter) {
mConverter = converter;
- Dependency.get(PluginManager.class).addPluginListener(action, this, cls);
+ mPluginManager.addPluginListener(action, this, cls);
}
@Override
@@ -244,7 +255,7 @@
@Override
public void destroy() {
- Dependency.get(PluginManager.class).removePluginListener(this);
+ mPluginManager.removePluginListener(this);
}
@Override
@@ -260,7 +271,7 @@
public TunerItem(TunerFactory<T> factory, String... setting) {
mFactory = factory;
- Dependency.get(TunerService.class).addTunable(this, setting);
+ mTunerService.addTunable(this, setting);
}
@Override
@@ -270,7 +281,7 @@
@Override
public void destroy() {
- Dependency.get(TunerService.class).removeTunable(this);
+ mTunerService.removeTunable(this);
}
@Override
@@ -298,7 +309,7 @@
mSupplier = supplier;
mUiMode = mDefaultContext.getResources().getConfiguration().uiMode
& Configuration.UI_MODE_TYPE_MASK;
- Dependency.get(ConfigurationController.class).addCallback(this);
+ mConfigurationController.addCallback(this);
}
@Override
@@ -318,7 +329,7 @@
@Override
public void destroy() {
- Dependency.get(ConfigurationController.class).removeCallback(this);
+ mConfigurationController.removeCallback(this);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
index 7198165..29c42d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
@@ -117,8 +117,8 @@
@Override
public boolean areNotificationsHiddenInShade() {
if (mZenMode != Global.ZEN_MODE_OFF) {
- return (mConfig.suppressedVisualEffects & NotificationManager.Policy
- .SUPPRESSED_EFFECT_NOTIFICATION_LIST) != 0;
+ return (mConsolidatedNotificationPolicy.suppressedVisualEffects
+ & NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST) != 0;
}
return false;
}
@@ -260,7 +260,6 @@
}
}
-
@VisibleForTesting
protected void updateZenModeConfig() {
final ZenModeConfig config = mNoMan.getZenModeConfig();
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index a86970b..32bc01c 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -550,7 +550,8 @@
}
private boolean updateZenConfig() {
- final NotificationManager.Policy policy = mNotificationManager.getNotificationPolicy();
+ final NotificationManager.Policy policy =
+ mNotificationManager.getConsolidatedNotificationPolicy();
boolean disallowAlarms = (policy.priorityCategories & NotificationManager.Policy
.PRIORITY_CATEGORY_ALARMS) == 0;
boolean disallowMedia = (policy.priorityCategories & NotificationManager.Policy
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index ab508a2..45e49df 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -125,6 +125,7 @@
@Override
protected Fragment instantiate(Context context, String className, Bundle arguments) {
return new QSFragment(new RemoteInputQuickSettingsDisabler(context),
- new InjectionInflationController(SystemUIFactory.getInstance().getRootComponent()));
+ new InjectionInflationController(SystemUIFactory.getInstance().getRootComponent()),
+ context);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
index 520a927..8cf4b05 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
@@ -20,6 +20,7 @@
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -35,6 +36,7 @@
import com.android.systemui.Dependency;
import com.android.systemui.InitController;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationData.Entry;
@@ -90,7 +92,10 @@
when(mEntryManager.getNotificationData()).thenReturn(mNotificationData);
- mViewHierarchyManager = new NotificationViewHierarchyManager(mContext);
+ mViewHierarchyManager = new NotificationViewHierarchyManager(mContext,
+ mLockscreenUserManager, mGroupManager, mVisualStabilityManager,
+ mock(StatusBarStateController.class), mEntryManager, mock(BubbleController.class),
+ () -> mShadeController);
Dependency.get(InitController.class).executePostInitTasks();
mViewHierarchyManager.setUpWithPresenter(mPresenter, mListContainer);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ExtensionControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ExtensionControllerImplTest.java
index 1cceefa..2553ac1e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ExtensionControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ExtensionControllerImplTest.java
@@ -28,7 +28,6 @@
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
-import com.android.systemui.Dependency;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.OverlayPlugin;
import com.android.systemui.plugins.Plugin;
@@ -39,6 +38,7 @@
import com.android.systemui.statusbar.policy.ExtensionController.TunerFactory;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
+import com.android.systemui.util.leak.LeakDetector;
import org.junit.Before;
import org.junit.Test;
@@ -62,7 +62,8 @@
mPluginManager = mDependency.injectMockDependency(PluginManager.class);
mTunerService = mDependency.injectMockDependency(TunerService.class);
mConfigurationController = mDependency.injectMockDependency(ConfigurationController.class);
- mExtensionController = Dependency.get(ExtensionController.class);
+ mExtensionController = new ExtensionControllerImpl(mContext,
+ mock(LeakDetector.class), mPluginManager, mTunerService, mConfigurationController);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java
index 7437e834..8f5f072 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java
@@ -89,20 +89,22 @@
@Test
public void testAreNotificationsHiddenInShade_zenOnShadeNotSuppressed() {
- mConfig.suppressedVisualEffects =
- NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
+ NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0,
+ NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR);
+ when(mNm.getConsolidatedNotificationPolicy()).thenReturn(policy);
+ mController.updateConsolidatedNotificationPolicy();
mController.updateZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
- mController.updateZenModeConfig();
assertFalse(mController.areNotificationsHiddenInShade());
}
@Test
public void testAreNotificationsHiddenInShade_zenOnShadeSuppressed() {
- mConfig.suppressedVisualEffects =
- NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
+ NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0,
+ NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST);
+ when(mNm.getConsolidatedNotificationPolicy()).thenReturn(policy);
+ mController.updateConsolidatedNotificationPolicy();
mController.updateZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
- mController.updateZenModeConfig();
assertTrue(mController.areNotificationsHiddenInShade());
}
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index 529d78f..3180b47 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -6664,6 +6664,72 @@
// OS: Q
NOTIFICATION_ACTION_IS_SMART = 1601;
+ // FIELD: true if the associated ACTION_ZEN_ALLOW_* or ACTION_ZEN_BLOCK_* allows/blocks
+ // the effect/sound when DND is on. false if set to disallow/show.
+ // OS: Q
+ FIELD_ZEN_TOGGLE_EXCEPTION = 1602;
+
+ // FIELD: rule id an ACTION_ZEN_ALLOW_* or ACTION_ZEN_BLOCK_* is associated with
+ // OS: Q
+ FIELD_ZEN_RULE_ID = 1603;
+
+ // OPEN: Settings > Sound > Do Not Disturb > Schedules > (Click on system rule)
+ // > Do Not Disturb behavior
+ // CATEGORY: SETTINGS
+ // OS: Q
+ ZEN_CUSTOM_RULE_SETTINGS = 1604;
+
+ // OPEN: Settings > Sound > Do Not Disturb > Schedules > (Click on system rule)
+ // > Do Not Disturb behavior > Custom
+ // CATEGORY: SETTINGS
+ // OS: Q
+ ZEN_CUSTOM_RULE_SOUND_SETTINGS = 1605;
+
+ // OPEN: Settings > Sound > Do Not Disturb > Schedules > (Click on system rule)
+ // > Do Not Disturb behavior > Use default Do Not Disturb behavior
+ // CATEGORY: SETTINGS
+ // OS: Q
+ ZEN_CUSTOM_RULE_DEFAULT_SETTINGS = 1606;
+
+ // OPEN: Settings > Sound > Do Not Disturb > Schedules > (Click on system rule)
+ // > Do Not Disturb behavior > Custom
+ // CATEGORY: SETTINGS
+ // OS: Q
+ ZEN_CUSTOM_RULE_CUSTOM_SETTINGS = 1607;
+
+ // OPEN: Settings > Sound > Do Not Disturb > Schedules > (Click on system rule)
+ // > Do Not Disturb behavior > Use default Do Not Disturb behavior
+ // > Notification restriction
+ // CATEGORY: SETTINGS
+ // OS: Q
+ ZEN_CUSTOM_RULE_NOTIFICATION_RESTRICTIONS = 1608;
+
+ // OPEN: Settings > Sound > Do Not Disturb > Schedules > (Click on system rule)
+ // > Do Not Disturb behavior > Use default Do Not Disturb behavior
+ // > Notification restriction > Custom
+ // CATEGORY: SETTINGS
+ // OS: Q
+ ZEN_CUSTOM_RULE_VIS_EFFECTS = 1609;
+
+ // OPEN: Settings > Sound > Do Not Disturb > Schedules > (Click on system rule)
+ // > Do Not Disturb behavior > Use default Do Not Disturb behavior
+ // > Notification restriction > Custom > Allow messages
+ // CATEGORY: SETTINGS
+ // OS: Q
+ ZEN_CUSTOM_RULE_MESSAGES = 1610;
+
+ // OPEN: Settings > Sound > Do Not Disturb > Schedules > (Click on system rule)
+ // > Do Not Disturb behavior > Use default Do Not Disturb behavior
+ // > Notification restriction > Custom > Allow calls
+ // CATEGORY: SETTINGS
+ // OS: Q
+ ZEN_CUSTOM_RULE_CALLS = 1611;
+
+ // OPEN: Settings > Sound > Do Not Disturb > Click footer link if custom settings applied
+ // CATEGORY: SETTINGS
+ // OS: Q
+ ZEN_CUSTOM_SETTINGS_DIALOG = 1612;
+
// ---- End Q Constants, all Q constants go above this line ----
// Add new aosp constants above this line.
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index ac17d87..121a830 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -87,6 +87,10 @@
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;
import com.android.server.am.BatteryStatsService;
+import com.android.server.deviceidle.ConstraintController;
+import com.android.server.deviceidle.DeviceIdleConstraintTracker;
+import com.android.server.deviceidle.IDeviceIdleConstraint;
+import com.android.server.deviceidle.TvConstraintController;
import com.android.server.net.NetworkPolicyManagerInternal;
import com.android.server.wm.ActivityTaskManagerInternal;
@@ -104,6 +108,7 @@
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
+import java.util.stream.Collectors;
/**
* Keeps track of device idleness and drives low power mode based on that.
@@ -296,6 +301,17 @@
private Location mLastGpsLocation;
// Current locked state of the screen
private boolean mScreenLocked;
+ private int mNumBlockingConstraints = 0;
+
+ /**
+ * Constraints are the "handbrakes" that stop the device from moving into a lower state until
+ * every one is released at the same time.
+ *
+ * @see #registerDeviceIdleConstraintInternal(IDeviceIdleConstraint, String, int)
+ */
+ private final ArrayMap<IDeviceIdleConstraint, DeviceIdleConstraintTracker>
+ mConstraints = new ArrayMap<>();
+ private ConstraintController mConstraintController;
/** Device is currently active. */
@VisibleForTesting
@@ -703,8 +719,7 @@
* global Settings. Any access to this class or its fields should be done while
* holding the DeviceIdleController lock.
*/
- @VisibleForTesting
- final class Constants extends ContentObserver {
+ public final class Constants extends ContentObserver {
// Key names stored in the settings value.
private static final String KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT
= "light_after_inactive_to";
@@ -1228,6 +1243,7 @@
private static final int MSG_REPORT_MAINTENANCE_ACTIVITY = 7;
private static final int MSG_FINISH_IDLE_OP = 8;
private static final int MSG_REPORT_TEMP_APP_WHITELIST_CHANGED = 9;
+ private static final int MSG_SEND_CONSTRAINT_MONITORING = 10;
final class MyHandler extends Handler {
MyHandler(Looper looper) {
@@ -1348,6 +1364,15 @@
final boolean added = (msg.arg2 == 1);
mNetworkPolicyManagerInternal.onTempPowerSaveWhitelistChange(appId, added);
} break;
+ case MSG_SEND_CONSTRAINT_MONITORING: {
+ final IDeviceIdleConstraint constraint = (IDeviceIdleConstraint) msg.obj;
+ final boolean monitoring = (msg.arg1 == 1);
+ if (monitoring) {
+ constraint.startMonitoring();
+ } else {
+ constraint.stopMonitoring();
+ }
+ } break;
}
}
}
@@ -1512,6 +1537,25 @@
}
public class LocalService {
+ public void onConstraintStateChanged(IDeviceIdleConstraint constraint, boolean active) {
+ synchronized (DeviceIdleController.this) {
+ onConstraintStateChangedLocked(constraint, active);
+ }
+ }
+
+ public void registerDeviceIdleConstraint(IDeviceIdleConstraint constraint, String name,
+ @IDeviceIdleConstraint.MinimumState int minState) {
+ registerDeviceIdleConstraintInternal(constraint, name, minState);
+ }
+
+ public void unregisterDeviceIdleConstraint(IDeviceIdleConstraint constraint) {
+ unregisterDeviceIdleConstraintInternal(constraint);
+ }
+
+ public void exitIdle(String reason) {
+ exitIdleInternal(reason);
+ }
+
// duration in milliseconds
public void addPowerSaveTempWhitelistApp(int callingUid, String packageName,
long duration, int userId, boolean sync, String reason) {
@@ -1612,6 +1656,23 @@
PowerManager getPowerManager() {
return mContext.getSystemService(PowerManager.class);
}
+
+ SensorManager getSensorManager() {
+ return mContext.getSystemService(SensorManager.class);
+ }
+
+ ConstraintController getConstraintController(Handler handler, LocalService localService) {
+ if (mContext.getPackageManager()
+ .hasSystemFeature(PackageManager.FEATURE_LEANBACK_ONLY)) {
+ return new TvConstraintController(mContext, handler);
+ }
+ return null;
+ }
+
+ boolean useMotionSensor() {
+ return mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_autoPowerModeUseMotionSensor);
+ }
}
private final Injector mInjector;
@@ -1636,9 +1697,7 @@
mHandler = mInjector.getHandler(this);
mAppStateTracker = mInjector.getAppStateTracker(context, FgThread.get().getLooper());
LocalServices.addService(AppStateTracker.class, mAppStateTracker);
-
- mUseMotionSensor = context.getResources().getBoolean(
- com.android.internal.R.bool.config_autoPowerModeUseMotionSensor);
+ mUseMotionSensor = mInjector.useMotionSensor();
}
public DeviceIdleController(Context context) {
@@ -1738,7 +1797,7 @@
mNetworkPolicyManager = INetworkPolicyManager.Stub.asInterface(
ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
mNetworkPolicyManagerInternal = getLocalService(NetworkPolicyManagerInternal.class);
- mSensorManager = (SensorManager) getContext().getSystemService(Context.SENSOR_SERVICE);
+ mSensorManager = mInjector.getSensorManager();
if (mUseMotionSensor) {
int sigMotionSensorId = getContext().getResources().getInteger(
@@ -1767,6 +1826,12 @@
.setNumUpdates(1);
}
+ mConstraintController = mInjector.getConstraintController(
+ mHandler, getLocalService(LocalService.class));
+ if (mConstraintController != null) {
+ mConstraintController.start();
+ }
+
float angleThreshold = getContext().getResources().getInteger(
com.android.internal.R.integer.config_autoPowerModeThresholdAngle) / 100f;
mAnyMotionDetector = mInjector.getAnyMotionDetector(mHandler, mSensorManager, this,
@@ -1822,6 +1887,99 @@
}
}
+ @VisibleForTesting
+ boolean hasMotionSensor() {
+ return mUseMotionSensor && mMotionSensor != null;
+ }
+
+ private void registerDeviceIdleConstraintInternal(IDeviceIdleConstraint constraint,
+ final String name, final int type) {
+ final int minState;
+ switch (type) {
+ case IDeviceIdleConstraint.ACTIVE:
+ minState = STATE_ACTIVE;
+ break;
+ case IDeviceIdleConstraint.SENSING_OR_ABOVE:
+ minState = STATE_SENSING;
+ break;
+ default:
+ Slog.wtf(TAG, "Registering device-idle constraint with invalid type: " + type);
+ return;
+ }
+ synchronized (this) {
+ if (mConstraints.containsKey(constraint)) {
+ Slog.e(TAG, "Re-registering device-idle constraint: " + constraint + ".");
+ return;
+ }
+ DeviceIdleConstraintTracker tracker = new DeviceIdleConstraintTracker(name, minState);
+ mConstraints.put(constraint, tracker);
+ updateActiveConstraintsLocked();
+ }
+ }
+
+ private void unregisterDeviceIdleConstraintInternal(IDeviceIdleConstraint constraint) {
+ synchronized (this) {
+ // Artifically force the constraint to inactive to unblock anything waiting for it.
+ onConstraintStateChangedLocked(constraint, /* active= */ false);
+
+ // Let the constraint know that we are not listening to it any more.
+ setConstraintMonitoringLocked(constraint, /* monitoring= */ false);
+ mConstraints.remove(constraint);
+ }
+ }
+
+ @GuardedBy("this")
+ private void onConstraintStateChangedLocked(IDeviceIdleConstraint constraint, boolean active) {
+ DeviceIdleConstraintTracker tracker = mConstraints.get(constraint);
+ if (tracker == null) {
+ Slog.e(TAG, "device-idle constraint " + constraint + " has not been registered.");
+ return;
+ }
+ if (active != tracker.active && tracker.monitoring) {
+ tracker.active = active;
+ mNumBlockingConstraints += (tracker.active ? +1 : -1);
+ if (mNumBlockingConstraints == 0) {
+ if (mState == STATE_ACTIVE) {
+ becomeInactiveIfAppropriateLocked();
+ } else if (mNextAlarmTime == 0 || mNextAlarmTime < SystemClock.elapsedRealtime()) {
+ stepIdleStateLocked("s:" + tracker.name);
+ }
+ }
+ }
+ }
+
+ @GuardedBy("this")
+ private void setConstraintMonitoringLocked(IDeviceIdleConstraint constraint, boolean monitor) {
+ DeviceIdleConstraintTracker tracker = mConstraints.get(constraint);
+ if (tracker.monitoring != monitor) {
+ tracker.monitoring = monitor;
+ updateActiveConstraintsLocked();
+ // We send the callback on a separate thread instead of just relying on oneway as
+ // the client could be in the system server with us and cause re-entry problems.
+ mHandler.obtainMessage(MSG_SEND_CONSTRAINT_MONITORING,
+ /* monitoring= */ monitor ? 1 : 0,
+ /* <not used>= */ -1,
+ /* constraint= */ constraint).sendToTarget();
+ }
+ }
+
+ @GuardedBy("this")
+ private void updateActiveConstraintsLocked() {
+ mNumBlockingConstraints = 0;
+ for (int i = 0; i < mConstraints.size(); i++) {
+ final IDeviceIdleConstraint constraint = mConstraints.keyAt(i);
+ final DeviceIdleConstraintTracker tracker = mConstraints.valueAt(i);
+ final boolean monitoring = (tracker.minState == mState);
+ if (monitoring != tracker.monitoring) {
+ setConstraintMonitoringLocked(constraint, monitoring);
+ tracker.active = monitoring;
+ }
+ if (tracker.monitoring && tracker.active) {
+ mNumBlockingConstraints++;
+ }
+ }
+ }
+
public boolean addPowerSaveWhitelistAppInternal(String name) {
synchronized (this) {
try {
@@ -2452,6 +2610,7 @@
cancelLocatingLocked();
stopMonitoringMotionLocked();
mAnyMotionDetector.stop();
+ updateActiveConstraintsLocked();
}
private void resetLightIdleManagementLocked() {
@@ -2587,40 +2746,50 @@
return;
}
+ if (mNumBlockingConstraints != 0 && !mForceIdle) {
+ // We have some constraints from other parts of the system server preventing
+ // us from moving to the next state.
+ if (DEBUG) {
+ Slog.i(TAG, "Cannot step idle state. Blocked by: " + mConstraints.values().stream()
+ .filter(x -> x.active)
+ .map(x -> x.name)
+ .collect(Collectors.joining(",")));
+ }
+ return;
+ }
+
switch (mState) {
case STATE_INACTIVE:
// We have now been inactive long enough, it is time to start looking
// for motion and sleep some more while doing so.
startMonitoringMotionLocked();
scheduleAlarmLocked(mConstants.IDLE_AFTER_INACTIVE_TIMEOUT, false);
- mState = STATE_IDLE_PENDING;
- if (DEBUG) Slog.d(TAG, "Moved from STATE_INACTIVE to STATE_IDLE_PENDING.");
- EventLogTags.writeDeviceIdle(mState, reason);
+ moveToStateLocked(STATE_IDLE_PENDING, reason);
break;
case STATE_IDLE_PENDING:
- mState = STATE_SENSING;
- if (DEBUG) Slog.d(TAG, "Moved from STATE_IDLE_PENDING to STATE_SENSING.");
- EventLogTags.writeDeviceIdle(mState, reason);
+ moveToStateLocked(STATE_SENSING, reason);
cancelLocatingLocked();
mLocated = false;
mLastGenericLocation = null;
mLastGpsLocation = null;
+ updateActiveConstraintsLocked();
- // If we have an accelerometer, wait to find out whether we are moving.
+ // Wait for open constraints and an accelerometer reading before moving on.
if (mUseMotionSensor && mAnyMotionDetector.hasSensor()) {
scheduleSensingTimeoutAlarmLocked(mConstants.SENSING_TIMEOUT);
mNotMoving = false;
mAnyMotionDetector.checkForAnyMotion();
break;
+ } else if (mNumBlockingConstraints != 0) {
+ cancelAlarmLocked();
+ break;
}
mNotMoving = true;
// Otherwise, fall through and check this off the list of requirements.
case STATE_SENSING:
cancelSensingTimeoutAlarmLocked();
- mState = STATE_LOCATING;
- if (DEBUG) Slog.d(TAG, "Moved from STATE_SENSING to STATE_LOCATING.");
- EventLogTags.writeDeviceIdle(mState, reason);
+ moveToStateLocked(STATE_LOCATING, reason);
scheduleAlarmLocked(mConstants.LOCATING_TIMEOUT, false);
LocationManager locationManager = mInjector.getLocationManager();
if (locationManager != null
@@ -2669,12 +2838,11 @@
if (mNextIdleDelay < mConstants.IDLE_TIMEOUT) {
mNextIdleDelay = mConstants.IDLE_TIMEOUT;
}
- mState = STATE_IDLE;
+ moveToStateLocked(STATE_IDLE, reason);
if (mLightState != LIGHT_STATE_OVERRIDE) {
mLightState = LIGHT_STATE_OVERRIDE;
cancelLightAlarmLocked();
}
- EventLogTags.writeDeviceIdle(mState, reason);
addEvent(EVENT_DEEP_IDLE, null);
mGoingIdleWakeLock.acquire();
mHandler.sendEmptyMessage(MSG_REPORT_IDLE_ON);
@@ -2692,14 +2860,24 @@
if (mNextIdlePendingDelay < mConstants.IDLE_PENDING_TIMEOUT) {
mNextIdlePendingDelay = mConstants.IDLE_PENDING_TIMEOUT;
}
- mState = STATE_IDLE_MAINTENANCE;
- EventLogTags.writeDeviceIdle(mState, reason);
+ moveToStateLocked(STATE_IDLE_MAINTENANCE, reason);
addEvent(EVENT_DEEP_MAINTENANCE, null);
mHandler.sendEmptyMessage(MSG_REPORT_IDLE_OFF);
break;
}
}
+ private void moveToStateLocked(int state, String reason) {
+ final int oldState = mState;
+ mState = state;
+ if (DEBUG) {
+ Slog.d(TAG, String.format("Moved from STATE_%s to STATE_%s.",
+ stateToString(oldState), stateToString(mState)));
+ }
+ EventLogTags.writeDeviceIdle(mState, reason);
+ updateActiveConstraintsLocked();
+ }
+
void incActiveIdleOps() {
synchronized (this) {
mActiveIdleOpCount++;
@@ -2822,6 +3000,7 @@
mMaintenanceStartTime = 0;
EventLogTags.writeDeviceIdle(mState, type);
becomeInactive = true;
+ updateActiveConstraintsLocked();
}
if (mLightState == LIGHT_STATE_OVERRIDE) {
// We went out of light idle mode because we had started deep idle mode... let's
@@ -3798,8 +3977,22 @@
pw.print(" mScreenLocked="); pw.println(mScreenLocked);
pw.print(" mNetworkConnected="); pw.println(mNetworkConnected);
pw.print(" mCharging="); pw.println(mCharging);
- pw.print(" mMotionActive="); pw.println(mMotionListener.active);
+ if (mConstraints.size() != 0) {
+ pw.println(" mConstraints={");
+ for (int i = 0; i < mConstraints.size(); i++) {
+ final DeviceIdleConstraintTracker tracker = mConstraints.valueAt(i);
+ pw.print(" \""); pw.print(tracker.name); pw.print("\"=");
+ if (tracker.minState == mState) {
+ pw.println(tracker.active);
+ } else {
+ pw.print("ignored <mMinState="); pw.print(stateToString(tracker.minState));
+ pw.println(">");
+ }
+ }
+ pw.println(" }");
+ }
if (mUseMotionSensor) {
+ pw.print(" mMotionActive="); pw.println(mMotionListener.active);
pw.print(" mNotMoving="); pw.println(mNotMoving);
}
pw.print(" mLocating="); pw.print(mLocating); pw.print(" mHasGps=");
diff --git a/services/core/java/com/android/server/deviceidle/BluetoothConstraint.java b/services/core/java/com/android/server/deviceidle/BluetoothConstraint.java
new file mode 100644
index 0000000..cc319bf
--- /dev/null
+++ b/services/core/java/com/android/server/deviceidle/BluetoothConstraint.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.deviceidle;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.BluetoothProfile;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Handler;
+import android.os.Message;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.DeviceIdleController;
+
+/**
+ * Track whether there are any active Bluetooth devices connected.
+ */
+public class BluetoothConstraint implements IDeviceIdleConstraint {
+ private static final String TAG = BluetoothConstraint.class.getSimpleName();
+ private static final long INACTIVITY_TIMEOUT_MS = 20 * 60 * 1000L;
+
+ private final Context mContext;
+ private final Handler mHandler;
+ private final DeviceIdleController.LocalService mLocalService;
+ private final BluetoothManager mBluetoothManager;
+
+ private volatile boolean mConnected = true;
+ private volatile boolean mMonitoring = false;
+
+ public BluetoothConstraint(
+ Context context, Handler handler, DeviceIdleController.LocalService localService) {
+ mContext = context;
+ mHandler = handler;
+ mLocalService = localService;
+ mBluetoothManager = mContext.getSystemService(BluetoothManager.class);
+ }
+
+ @Override
+ public synchronized void startMonitoring() {
+ // Start by assuming we have a connected bluetooth device.
+ mConnected = true;
+ mMonitoring = true;
+
+ // Register a receiver to get updates on bluetooth devices disconnecting or the
+ // adapter state changing.
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
+ filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
+ filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
+ mContext.registerReceiver(mReceiver, filter);
+
+ // Some devices will try to stay connected indefinitely. Set a timeout to ignore them.
+ mHandler.sendMessageDelayed(
+ Message.obtain(mHandler, mTimeoutCallback), INACTIVITY_TIMEOUT_MS);
+
+ // Now we have the receiver registered, make a direct check for connected devices.
+ updateAndReportActiveLocked();
+ }
+
+ @Override
+ public synchronized void stopMonitoring() {
+ mContext.unregisterReceiver(mReceiver);
+ mHandler.removeCallbacks(mTimeoutCallback);
+ mMonitoring = false;
+ }
+
+ private synchronized void cancelMonitoringDueToTimeout() {
+ if (mMonitoring) {
+ mMonitoring = false;
+ mLocalService.onConstraintStateChanged(this, /* active= */ false);
+ }
+ }
+
+ /**
+ * Check the latest data from BluetoothManager and let DeviceIdleController know whether we
+ * have connected devices (for example TV remotes / gamepads) and thus want to stay awake.
+ */
+ @GuardedBy("this")
+ private void updateAndReportActiveLocked() {
+ final boolean connected = isBluetoothConnected(mBluetoothManager);
+ if (connected != mConnected) {
+ mConnected = connected;
+ // If we lost all of our connections, we are on track to going into idle state.
+ mLocalService.onConstraintStateChanged(this, /* active= */ mConnected);
+ }
+ }
+
+ /**
+ * True if the bluetooth adapter exists, is enabled, and has at least one GATT device connected.
+ */
+ @VisibleForTesting
+ static boolean isBluetoothConnected(BluetoothManager bluetoothManager) {
+ BluetoothAdapter adapter = bluetoothManager.getAdapter();
+ if (adapter != null && adapter.isEnabled()) {
+ return bluetoothManager.getConnectedDevices(BluetoothProfile.GATT).size() > 0;
+ }
+ return false;
+ }
+
+ /**
+ * Registered in {@link #startMonitoring()}, unregistered in {@link #stopMonitoring()}.
+ */
+ @VisibleForTesting
+ final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (BluetoothDevice.ACTION_ACL_CONNECTED.equals(intent.getAction())) {
+ mLocalService.exitIdle("bluetooth");
+ } else {
+ updateAndReportActiveLocked();
+ }
+ }
+ };
+
+ private final Runnable mTimeoutCallback = () -> cancelMonitoringDueToTimeout();
+}
diff --git a/services/core/java/com/android/server/deviceidle/ConstraintController.java b/services/core/java/com/android/server/deviceidle/ConstraintController.java
new file mode 100644
index 0000000..6d52f71
--- /dev/null
+++ b/services/core/java/com/android/server/deviceidle/ConstraintController.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.deviceidle;
+
+/**
+ * Device idle constraints for a specific form factor or use-case.
+ */
+public interface ConstraintController {
+ /**
+ * Begin any general continuing work and register all constraints.
+ */
+ void start();
+
+ /**
+ * Unregister all constraints and stop any general work.
+ */
+ void stop();
+}
diff --git a/services/core/java/com/android/server/deviceidle/DeviceIdleConstraintTracker.java b/services/core/java/com/android/server/deviceidle/DeviceIdleConstraintTracker.java
new file mode 100644
index 0000000..4d5760e
--- /dev/null
+++ b/services/core/java/com/android/server/deviceidle/DeviceIdleConstraintTracker.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.deviceidle;
+
+/**
+ * Current state of an {@link IDeviceIdleConstraint}.
+ *
+ * If the current doze state is between leastActive and mostActive, then startMonitoring() will
+ * be the most recent call. Otherwise, stopMonitoring() is the most recent call.
+ */
+public class DeviceIdleConstraintTracker {
+
+ /**
+ * Appears in "dumpsys deviceidle".
+ */
+ public final String name;
+
+ /**
+ * Whenever a constraint is active, it will keep the device at or above
+ * minState (provided the rule is currently in effect).
+ *
+ */
+ public final int minState;
+
+ /**
+ * Whether this constraint currently prevents going below {@link #minState}.
+ *
+ * When the state is set to exactly minState, active is automatically
+ * overwritten with {@code true}.
+ */
+ public boolean active = false;
+
+ /**
+ * Internal tracking for whether the {@link IDeviceIdleConstraint} on the other
+ * side has been told it needs to send updates.
+ */
+ public boolean monitoring = false;
+
+ public DeviceIdleConstraintTracker(final String name, int minState) {
+ this.name = name;
+ this.minState = minState;
+ }
+}
diff --git a/services/core/java/com/android/server/deviceidle/IDeviceIdleConstraint.java b/services/core/java/com/android/server/deviceidle/IDeviceIdleConstraint.java
new file mode 100644
index 0000000..f1f95730
--- /dev/null
+++ b/services/core/java/com/android/server/deviceidle/IDeviceIdleConstraint.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.deviceidle;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Implemented by OEM and/or Form Factor. System ones are built into the
+ * image regardless of build flavour but may still be switched off at run time.
+ * Individual feature flags at build time control which are used. We may
+ * also explore a local override for quick testing.
+ */
+public interface IDeviceIdleConstraint {
+
+ /**
+ * A state for this constraint to block descent from.
+ *
+ * <p>These states are a subset of the states in DeviceIdleController that make sense for
+ * constraints to be able to block on. For example, {@link #SENSING_OR_ABOVE} clearly has
+ * defined "above" and "below" states. However, a hypothetical {@code QUICK_DOZE_OR_ABOVE}
+ * state would not have clear semantics as to what transitions should be blocked and which
+ * should be allowed.
+ */
+ @IntDef(flag = false, value = {
+ ACTIVE,
+ SENSING_OR_ABOVE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface MinimumState {}
+
+ int ACTIVE = 0;
+ int SENSING_OR_ABOVE = 1;
+
+ /**
+ * Begin tracking events for this constraint.
+ *
+ * <p>The device idle controller has reached a point where it is waiting for the all-clear
+ * from this tracker (possibly among others) in order to continue with progression into
+ * idle state. It will not proceed until one of the following happens:
+ * <ul>
+ * <li>The constraint reports inactive with {@code .setActive(false)}.</li>
+ * <li>The constraint is unregistered with {@code .unregisterDeviceIdleConstraint(this)}.</li>
+ * <li>A transition timeout in DeviceIdleController fires.
+ * </ul>
+ */
+ void startMonitoring();
+
+ /** Stop checking for new events and do not call into LocalService with updates any more. */
+ void stopMonitoring();
+}
diff --git a/services/core/java/com/android/server/deviceidle/TvConstraintController.java b/services/core/java/com/android/server/deviceidle/TvConstraintController.java
new file mode 100644
index 0000000..2d472de6
--- /dev/null
+++ b/services/core/java/com/android/server/deviceidle/TvConstraintController.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.deviceidle;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Handler;
+
+import com.android.server.DeviceIdleController;
+import com.android.server.LocalServices;
+
+/**
+ * Device idle constraints for television devices.
+ *
+ * <p>Televisions are devices with {@code FEATURE_LEANBACK_ONLY}. Other devices might support
+ * some kind of leanback mode but they should not follow the same rules for idle state.
+ */
+public class TvConstraintController implements ConstraintController {
+ private final Context mContext;
+ private final Handler mHandler;
+ private final DeviceIdleController.LocalService mDeviceIdleService;
+
+ @Nullable
+ private final BluetoothConstraint mBluetoothConstraint;
+
+ public TvConstraintController(Context context, Handler handler) {
+ mContext = context;
+ mHandler = handler;
+ mDeviceIdleService = LocalServices.getService(DeviceIdleController.LocalService.class);
+
+ final PackageManager pm = context.getPackageManager();
+ mBluetoothConstraint = pm.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)
+ ? new BluetoothConstraint(mContext, mHandler, mDeviceIdleService)
+ : null;
+ }
+
+ @Override
+ public void start() {
+ if (mBluetoothConstraint != null) {
+ mDeviceIdleService.registerDeviceIdleConstraint(
+ mBluetoothConstraint, "bluetooth", IDeviceIdleConstraint.SENSING_OR_ABOVE);
+ }
+ }
+
+ @Override
+ public void stop() {
+ if (mBluetoothConstraint != null) {
+ mDeviceIdleService.unregisterDeviceIdleConstraint(mBluetoothConstraint);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
index 8e3f351..918dc07 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
@@ -38,11 +38,11 @@
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodSubtype;
import android.view.textservice.SpellCheckerInfo;
-import android.view.textservice.TextServicesManager;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.inputmethod.StartInputFlags;
+import com.android.server.textservices.TextServicesManagerInternal;
import java.util.ArrayList;
import java.util.Arrays;
@@ -641,7 +641,7 @@
}
// Only the current spell checker should be treated as an enabled one.
final SpellCheckerInfo currentSpellChecker =
- TextServicesManager.getInstance().getCurrentSpellChecker();
+ TextServicesManagerInternal.get().getCurrentSpellCheckerForUser(userId);
for (final String packageName : systemImesDisabledUntilUsed) {
if (DEBUG) {
Slog.d(TAG, "check " + packageName);
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index f01d343..e5b1878 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -558,9 +558,7 @@
rule.conditionId = automaticZenRule.getConditionId();
rule.enabled = automaticZenRule.isEnabled();
rule.modified = automaticZenRule.isModified();
- if (automaticZenRule.getZenPolicy() != null) {
- rule.zenPolicy = automaticZenRule.getZenPolicy();
- }
+ rule.zenPolicy = automaticZenRule.getZenPolicy();
rule.zenMode = NotificationManager.zenModeFromInterruptionFilter(
automaticZenRule.getInterruptionFilter(), Global.ZEN_MODE_OFF);
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 0d0db94..35ffe8d 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -1065,6 +1065,7 @@
if (isStaged()) {
// STOPSHIP: implement staged sessions
mStagedSessionReady = true;
+ mPm.sendSessionUpdatedBroadcast(generateInfo(), userId);
dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "Session staged", null);
return;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 9f1b922..af12633 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -19629,6 +19629,17 @@
return getHomeActivitiesAsUser(allHomeCandidates, UserHandle.getCallingUserId());
}
+ /**
+ * Send a {@code PackageInstaller.ACTION_SESSION_UPDATED} broadcast intent, containing
+ * the {@code sessionInfo} in the extra field {@code PackageInstaller.EXTRA_SESSION}.
+ */
+ public void sendSessionUpdatedBroadcast(PackageInstaller.SessionInfo sessionInfo,
+ int userId) {
+ Intent sessionUpdatedIntent = new Intent(PackageInstaller.ACTION_SESSION_UPDATED)
+ .putExtra(PackageInstaller.EXTRA_SESSION, sessionInfo);
+ mContext.sendBroadcastAsUser(sessionUpdatedIntent, UserHandle.of(userId));
+ }
+
public void sendSessionCommitBroadcast(PackageInstaller.SessionInfo sessionInfo, int userId) {
UserManagerService ums = UserManagerService.getInstance();
if (ums != null) {
diff --git a/services/core/java/com/android/server/textservices/TextServicesManagerInternal.java b/services/core/java/com/android/server/textservices/TextServicesManagerInternal.java
new file mode 100644
index 0000000..56bcdd9
--- /dev/null
+++ b/services/core/java/com/android/server/textservices/TextServicesManagerInternal.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.textservices;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.view.textservice.SpellCheckerInfo;
+
+import com.android.server.LocalServices;
+
+/**
+ * Local interface of {@link TextServicesManagerService} inside system server process.
+ */
+public abstract class TextServicesManagerInternal {
+ /**
+ * Returns the list of installed input methods for the specified user.
+ *
+ * <p>CAVEAT: This method is not fully implemented yet. This may return an empty list if
+ * {@code userId} for a background user is specified. Check the implementation before starting
+ * this method.</p>
+ *
+ * @param userId The user ID to be queried.
+ * @return {@link SpellCheckerInfo} that is currently selected {@code userId}.
+ */
+ @Nullable
+ public abstract SpellCheckerInfo getCurrentSpellCheckerForUser(@UserIdInt int userId);
+
+ /**
+ * Fake implementation of {@link TextServicesManagerInternal}. All the methods do nothing.
+ */
+ private static final TextServicesManagerInternal NOP =
+ new TextServicesManagerInternal() {
+ @Override
+ public SpellCheckerInfo getCurrentSpellCheckerForUser(@UserIdInt int userId) {
+ return null;
+ }
+ };
+
+ /**
+ * @return Global instance if exists. Otherwise, a dummy no-op instance.
+ */
+ @NonNull
+ public static TextServicesManagerInternal get() {
+ final TextServicesManagerInternal instance =
+ LocalServices.getService(TextServicesManagerInternal.class);
+ return instance != null ? instance : NOP;
+ }
+}
diff --git a/services/core/java/com/android/server/textservices/TextServicesManagerService.java b/services/core/java/com/android/server/textservices/TextServicesManagerService.java
index 97f238a..65d5b10 100644
--- a/services/core/java/com/android/server/textservices/TextServicesManagerService.java
+++ b/services/core/java/com/android/server/textservices/TextServicesManagerService.java
@@ -56,6 +56,7 @@
import com.android.internal.textservice.ITextServicesManager;
import com.android.internal.textservice.ITextServicesSessionListener;
import com.android.internal.util.DumpUtils;
+import com.android.server.LocalServices;
import com.android.server.SystemService;
import org.xmlpull.v1.XmlPullParserException;
@@ -278,6 +279,14 @@
@Override
public void onStart() {
+ LocalServices.addService(TextServicesManagerInternal.class,
+ new TextServicesManagerInternal() {
+ @Override
+ public SpellCheckerInfo getCurrentSpellCheckerForUser(
+ @UserIdInt int userId) {
+ return mService.getCurrentSpellCheckerForUser(userId);
+ }
+ });
publishBinderService(Context.TEXT_SERVICES_MANAGER_SERVICE, mService);
}
@@ -493,6 +502,15 @@
return spellCheckerList.get(0);
}
+ @Nullable
+ private SpellCheckerInfo getCurrentSpellCheckerForUser(@UserIdInt int userId) {
+ synchronized (mLock) {
+ final int spellCheckerOwnerUserId = mSpellCheckerOwnerUserIdMap.get(userId);
+ final TextServicesData data = mUserData.get(spellCheckerOwnerUserId);
+ return data != null ? data.getCurrentSpellChecker() : null;
+ }
+ }
+
// TODO: Save SpellCheckerService by supported languages. Currently only one spell
// checker is saved.
@Override
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 4d8440a8..2cd0168 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2486,36 +2486,20 @@
}
void setRequestedOrientation(int requestedOrientation) {
- final int displayId = getDisplayId();
- final Configuration displayConfig =
- mRootActivityContainer.getDisplayOverrideConfiguration(displayId);
-
- final Configuration config = setOrientation(requestedOrientation,
- displayId, displayConfig, mayFreezeScreenLocked(app));
- if (config != null) {
- frozenBeforeDestroy = true;
- if (!mAtmService.updateDisplayOverrideConfigurationLocked(config, this,
- false /* deferResume */, displayId)) {
- mRootActivityContainer.resumeFocusedStacksTopActivities();
- }
- }
+ setOrientation(requestedOrientation, mayFreezeScreenLocked(app));
mAtmService.getTaskChangeNotificationController().notifyActivityRequestedOrientationChanged(
task.taskId, requestedOrientation);
}
- Configuration setOrientation(int requestedOrientation, int displayId,
- Configuration displayConfig, boolean freezeScreenIfNeeded) {
+ private void setOrientation(int requestedOrientation, boolean freezeScreenIfNeeded) {
if (mAppWindowToken == null) {
Slog.w(TAG_WM,
"Attempted to set orientation of non-existing app token: " + appToken);
- return null;
+ return;
}
- mAppWindowToken.setOrientation(requestedOrientation);
-
final IBinder binder = freezeScreenIfNeeded ? appToken.asBinder() : null;
- return mAtmService.mWindowManager.updateOrientationFromAppTokens(displayConfig, binder,
- displayId);
+ mAppWindowToken.setOrientation(requestedOrientation, binder, this);
}
int getOrientation() {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 1943efc..a5ceee2 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -397,10 +397,11 @@
private final Matrix mTmpMatrix = new Matrix();
private final Region mTmpRegion = new Region();
-
/** Used for handing back size of display */
private final Rect mTmpBounds = new Rect();
+ private final Configuration mTmpConfiguration = new Configuration();
+
/** Remove this display when animation on it has completed. */
private boolean mDeferredRemoval;
@@ -1156,6 +1157,36 @@
mWmService.mH.obtainMessage(SEND_NEW_CONFIGURATION, this).sendToTarget();
}
+ @Override
+ boolean onDescendantOrientationChanged(IBinder freezeDisplayToken,
+ ConfigurationContainer requestingContainer) {
+ final Configuration config = updateOrientationFromAppTokens(
+ getRequestedOverrideConfiguration(), freezeDisplayToken, false);
+ // If display rotation class tells us that it doesn't consider app requested orientation,
+ // this display won't rotate just because of an app changes its requested orientation. Thus
+ // it indicates that this display chooses not to handle this request.
+ final boolean handled = getDisplayRotation().respectAppRequestedOrientation();
+ if (config == null) {
+ return handled;
+ }
+
+ if (handled && requestingContainer instanceof ActivityRecord) {
+ final ActivityRecord activityRecord = (ActivityRecord) requestingContainer;
+ final boolean kept = mWmService.mAtmService.updateDisplayOverrideConfigurationLocked(
+ config, activityRecord, false /* deferResume */, getDisplayId());
+ activityRecord.frozenBeforeDestroy = true;
+ if (!kept) {
+ mWmService.mAtmService.mRootActivityContainer.resumeFocusedStacksTopActivities();
+ }
+ } else {
+ // We have a new configuration to push so we need to update ATMS for now.
+ // TODO: Clean up display configuration push between ATMS and WMS after unification.
+ mWmService.mAtmService.updateDisplayOverrideConfigurationLocked(
+ config, null /* starting */, false /* deferResume */, getDisplayId());
+ }
+ return handled;
+ }
+
/**
* Determine the new desired orientation of this display.
*
@@ -1169,7 +1200,56 @@
return updateOrientationFromAppTokens(false /* forceUpdate */);
}
- boolean updateOrientationFromAppTokens(boolean forceUpdate) {
+ /**
+ * Update orientation of the target display, returning a non-null new Configuration if it has
+ * changed from the current orientation. If a non-null configuration is returned, someone must
+ * call {@link WindowManagerService#setNewDisplayOverrideConfiguration(Configuration,
+ * DisplayContent)} to tell the window manager it can unfreeze the screen. This will typically
+ * be done by calling {@link WindowManagerService#sendNewConfiguration(int)}.
+ */
+ Configuration updateOrientationFromAppTokens(Configuration currentConfig,
+ IBinder freezeDisplayToken, boolean forceUpdate) {
+ if (!mDisplayReady) {
+ return null;
+ }
+
+ Configuration config = null;
+ if (updateOrientationFromAppTokens(forceUpdate)) {
+ // If we changed the orientation but mOrientationChangeComplete is already true,
+ // we used seamless rotation, and we don't need to freeze the screen.
+ if (freezeDisplayToken != null && !mWmService.mRoot.mOrientationChangeComplete) {
+ final AppWindowToken atoken = getAppWindowToken(freezeDisplayToken);
+ if (atoken != null) {
+ atoken.startFreezingScreen();
+ }
+ }
+ config = new Configuration();
+ computeScreenConfiguration(config);
+ } else if (currentConfig != null) {
+ // No obvious action we need to take, but if our current state mismatches the
+ // activity manager's, update it, disregarding font scale, which should remain set
+ // to the value of the previous configuration.
+ // Here we're calling Configuration#unset() instead of setToDefaults() because we
+ // need to keep override configs clear of non-empty values (e.g. fontSize).
+ mTmpConfiguration.unset();
+ mTmpConfiguration.updateFrom(currentConfig);
+ computeScreenConfiguration(mTmpConfiguration);
+ if (currentConfig.diff(mTmpConfiguration) != 0) {
+ mWaitingForConfig = true;
+ setLayoutNeeded();
+ int[] anim = new int[2];
+ getDisplayPolicy().selectRotationAnimationLw(anim);
+
+ mWmService.startFreezingDisplayLocked(anim[0], anim[1], this);
+ config = new Configuration(mTmpConfiguration);
+ }
+ }
+
+ return config;
+ }
+
+
+ private boolean updateOrientationFromAppTokens(boolean forceUpdate) {
final int req = getOrientation();
if (req != mLastOrientation || forceUpdate) {
mLastOrientation = req;
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 7aabc15..bcc7be4 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -329,6 +329,15 @@
return mFixedToUserRotation;
}
+ /**
+ * Returns {@code true} if this display rotation takes app requested orientation into
+ * consideration; {@code false} otherwise. For the time being the only case where this is {@code
+ * false} is when {@link #isFixedToUserRotation()} is {@code true}.
+ */
+ boolean respectAppRequestedOrientation() {
+ return !mFixedToUserRotation;
+ }
+
public int getLandscapeRotation() {
return mLandscapeRotation;
}
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index d0937e9..6f92e64 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -597,11 +597,15 @@
// Force-update the orientation from the WindowManager, since we need the true configuration
// to send to the client now.
- final Configuration config = mWindowManager.updateOrientationFromAppTokens(
- getDisplayOverrideConfiguration(displayId),
- starting != null && starting.mayFreezeScreenLocked(starting.app)
- ? starting.appToken : null,
- displayId, true /* forceUpdate */);
+ final DisplayContent displayContent = mRootWindowContainer.getDisplayContent(displayId);
+ Configuration config = null;
+ if (displayContent != null) {
+ config = displayContent.updateOrientationFromAppTokens(
+ getDisplayOverrideConfiguration(displayId),
+ starting != null && starting.mayFreezeScreenLocked(starting.app)
+ ? starting.appToken : null,
+ true /* forceUpdate */);
+ }
if (starting != null && markFrozenIfConfigChanged && config != null) {
starting.frozenBeforeDestroy = true;
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index b10fd31..d334bd2 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -44,6 +44,7 @@
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
+import android.os.IBinder;
import android.util.EventLog;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
@@ -328,6 +329,23 @@
return boundsChange;
}
+ @Override
+ public boolean onDescendantOrientationChanged(IBinder freezeDisplayToken,
+ ConfigurationContainer requestingContainer) {
+ if (super.onDescendantOrientationChanged(freezeDisplayToken, requestingContainer)) {
+ return true;
+ }
+
+ // No one in higher hierarchy handles this request, let's adjust our bounds to fulfill
+ // it if possible.
+ // TODO: Move to TaskRecord after unification is done.
+ if (mTaskRecord != null) {
+ mTaskRecord.onConfigurationChanged(mTaskRecord.getParent().getConfiguration());
+ return true;
+ }
+ return false;
+ }
+
void resize(boolean relayout, boolean forced) {
if (setBounds(getRequestedOverrideBounds(), forced) != BOUNDS_CHANGE_NONE && relayout) {
getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 651089d..32c5a3b 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -31,10 +31,12 @@
import android.annotation.CallSuper;
import android.annotation.IntDef;
+import android.annotation.Nullable;
import android.app.WindowConfiguration;
import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.Rect;
+import android.os.IBinder;
import android.util.Pools;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
@@ -698,8 +700,58 @@
}
}
+ /**
+ * Called when this container or one of its descendants changed its requested orientation, and
+ * wants this container to handle it or pass it to its parent.
+ *
+ * @param freezeDisplayToken freeze this app window token if display needs to freeze
+ * @param requestingContainer the container which orientation request has changed
+ * @return {@code true} if handled; {@code false} otherwise.
+ */
+ boolean onDescendantOrientationChanged(@Nullable IBinder freezeDisplayToken,
+ @Nullable ConfigurationContainer requestingContainer) {
+ final WindowContainer parent = getParent();
+ if (parent == null) {
+ return false;
+ }
+ return parent.onDescendantOrientationChanged(freezeDisplayToken,
+ requestingContainer);
+ }
+
+ /**
+ * Calls {@link #setOrientation(int, IBinder, ActivityRecord)} with {@code null} to the last 2
+ * parameters.
+ *
+ * @param orientation the specified orientation.
+ */
void setOrientation(int orientation) {
+ setOrientation(orientation, null /* freezeDisplayToken */,
+ null /* ActivityRecord */);
+ }
+
+ /**
+ * Sets the specified orientation of this container. It percolates this change upward along the
+ * hierarchy to let each level of the hierarchy a chance to respond to it.
+ *
+ * @param orientation the specified orientation. Needs to be one of {@link
+ * android.content.pm.ActivityInfo.ScreenOrientation}.
+ * @param freezeDisplayToken uses this token to freeze display if orientation change is not
+ * done. Display will not be frozen if this is {@code null}, which
+ * should only happen in tests.
+ * @param requestingContainer the container which orientation request has changed. Mostly used
+ * to ensure it gets correct configuration.
+ */
+ void setOrientation(int orientation, @Nullable IBinder freezeDisplayToken,
+ @Nullable ConfigurationContainer requestingContainer) {
+ final boolean changed = mOrientation != orientation;
mOrientation = orientation;
+ if (!changed) {
+ return;
+ }
+ final WindowContainer parent = getParent();
+ if (parent != null) {
+ onDescendantOrientationChanged(freezeDisplayToken, requestingContainer);
+ }
}
int getOrientation() {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index e3ced83..b6a4a51 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2383,85 +2383,6 @@
}
}
- @Override
- public Configuration updateOrientationFromAppTokens(Configuration currentConfig,
- IBinder freezeThisOneIfNeeded, int displayId) {
- return updateOrientationFromAppTokens(currentConfig, freezeThisOneIfNeeded, displayId,
- false /* forceUpdate */);
- }
-
- public Configuration updateOrientationFromAppTokens(Configuration currentConfig,
- IBinder freezeThisOneIfNeeded, int displayId, boolean forceUpdate) {
- if (!checkCallingPermission(MANAGE_APP_TOKENS, "updateOrientationFromAppTokens()")) {
- throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
- }
-
- final Configuration config;
- final long ident = Binder.clearCallingIdentity();
- try {
- synchronized (mGlobalLock) {
- config = updateOrientationFromAppTokensLocked(currentConfig, freezeThisOneIfNeeded,
- displayId, forceUpdate);
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
-
- return config;
- }
-
- /**
- * Update orientation of the target display, returning a non-null new Configuration if it has
- * changed from the current orientation. If a non-null configuration is returned, someone must
- * call {@link #setNewDisplayOverrideConfiguration(Configuration, int)} to tell the window
- * manager it can unfreeze the screen. This will typically be done by calling
- * {@link #sendNewConfiguration(int)}.
- *
- * @see android.view.IWindowManager#updateOrientationFromAppTokens(Configuration, IBinder, int)
- */
- private Configuration updateOrientationFromAppTokensLocked(Configuration currentConfig,
- IBinder freezeThisOneIfNeeded, int displayId, boolean forceUpdate) {
- if (!mDisplayReady) {
- return null;
- }
- Configuration config = null;
-
- final DisplayContent dc = mRoot.getDisplayContent(displayId);
- if (dc != null && dc.updateOrientationFromAppTokens(forceUpdate)) {
- // If we changed the orientation but mOrientationChangeComplete is already true,
- // we used seamless rotation, and we don't need to freeze the screen.
- if (freezeThisOneIfNeeded != null && !mRoot.mOrientationChangeComplete) {
- final AppWindowToken atoken = mRoot.getAppWindowToken(freezeThisOneIfNeeded);
- if (atoken != null) {
- atoken.startFreezingScreen();
- }
- }
- config = computeNewConfigurationLocked(displayId);
-
- } else if (currentConfig != null) {
- // No obvious action we need to take, but if our current state mismatches the activity
- // manager's, update it, disregarding font scale, which should remain set to the value
- // of the previous configuration.
- // Here we're calling Configuration#unset() instead of setToDefaults() because we need
- // to keep override configs clear of non-empty values (e.g. fontSize).
- mTempConfiguration.unset();
- mTempConfiguration.updateFrom(currentConfig);
- final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
- displayContent.computeScreenConfiguration(mTempConfiguration);
- if (currentConfig.diff(mTempConfiguration) != 0) {
- displayContent.mWaitingForConfig = true;
- displayContent.setLayoutNeeded();
- int anim[] = new int[2];
- displayContent.getDisplayPolicy().selectRotationAnimationLw(anim);
-
- startFreezingDisplayLocked(anim[0], anim[1], displayContent);
- config = new Configuration(mTempConfiguration);
- }
- }
-
- return config;
- }
-
void setNewDisplayOverrideConfiguration(Configuration overrideConfig,
@NonNull DisplayContent dc) {
if (dc.mWaitingForConfig) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
index 7ff10bf..1a16e56 100644
--- a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
@@ -50,6 +50,7 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
import android.app.ActivityManagerInternal;
import android.app.AlarmManager;
@@ -57,6 +58,7 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.location.LocationManager;
import android.location.LocationProvider;
@@ -71,6 +73,7 @@
import androidx.test.runner.AndroidJUnit4;
+import com.android.server.deviceidle.ConstraintController;
import com.android.server.net.NetworkPolicyManagerInternal;
import com.android.server.wm.ActivityTaskManagerInternal;
@@ -78,6 +81,7 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoSession;
import org.mockito.quality.Strictness;
@@ -110,10 +114,13 @@
private PowerManager.WakeLock mWakeLock;
@Mock
private PowerManagerInternal mPowerManagerInternal;
+ @Mock
+ private SensorManager mSensorManager;
class InjectorForTest extends DeviceIdleController.Injector {
ConnectivityService connectivityService;
LocationManager locationManager;
+ ConstraintController constraintController;
InjectorForTest(Context ctx) {
super(ctx);
@@ -147,20 +154,36 @@
@Override
DeviceIdleController.MyHandler getHandler(DeviceIdleController controller) {
- return mock(DeviceIdleController.MyHandler.class);
+ return mock(DeviceIdleController.MyHandler.class, Answers.RETURNS_DEEP_STUBS);
}
@Override
PowerManager getPowerManager() {
return mPowerManager;
}
+
+ @Override
+ SensorManager getSensorManager() {
+ return mSensorManager;
+ }
+
+ @Override
+ ConstraintController getConstraintController(
+ Handler handler, DeviceIdleController.LocalService localService) {
+ return constraintController;
+ }
+
+ @Override
+ boolean useMotionSensor() {
+ return true;
+ }
}
private class AnyMotionDetectorForTest extends AnyMotionDetector {
boolean isMonitoring = false;
AnyMotionDetectorForTest() {
- super(mPowerManager, mock(Handler.class), mock(SensorManager.class),
+ super(mPowerManager, mock(Handler.class), mSensorManager,
mock(DeviceIdleCallback.class), 0.5f);
}
@@ -201,7 +224,7 @@
mMockingSession = mockitoSession()
.initMocks(this)
.strictness(Strictness.LENIENT)
- .mockStatic(LocalServices.class)
+ .spyStatic(LocalServices.class)
.startMocking();
spyOn(getContext());
doReturn(null).when(getContext()).registerReceiver(any(), any());
@@ -218,6 +241,9 @@
when(mPowerManager.newWakeLock(anyInt(), anyString())).thenReturn(mWakeLock);
doNothing().when(mWakeLock).acquire();
doNothing().when(mAlarmManager).set(anyInt(), anyLong(), anyString(), any(), any());
+ doReturn(mock(Sensor.class)).when(mSensorManager)
+ .getDefaultSensor(eq(Sensor.TYPE_SIGNIFICANT_MOTION), eq(true));
+ doReturn(true).when(mSensorManager).registerListener(any(), any(), anyInt());
mAppStateTracker = new AppStateTrackerForTest(getContext(), Looper.getMainLooper());
mAnyMotionDetector = new AnyMotionDetectorForTest();
mInjector = new InjectorForTest(getContext());
@@ -240,9 +266,10 @@
if (mMockingSession != null) {
mMockingSession.finishMocking();
}
- // DeviceIdleController adds this to LocalServices in the constructor, so we have to remove
- // it after each test, otherwise, subsequent tests will fail.
+ // DeviceIdleController adds these to LocalServices in the constructor, so we have to remove
+ // them after each test, otherwise, subsequent tests will fail.
LocalServices.removeServiceForTest(AppStateTracker.class);
+ LocalServices.removeServiceForTest(DeviceIdleController.LocalService.class);
}
@Test
@@ -1486,27 +1513,36 @@
assertFalse(mDeviceIdleController.isScreenOn());
break;
case STATE_IDLE_PENDING:
- assertTrue(mDeviceIdleController.mMotionListener.isActive());
+ assertEquals(
+ mDeviceIdleController.hasMotionSensor(),
+ mDeviceIdleController.mMotionListener.isActive());
assertFalse(mAnyMotionDetector.isMonitoring);
assertFalse(mDeviceIdleController.isCharging());
assertFalse(mDeviceIdleController.isScreenOn());
break;
case STATE_SENSING:
- assertTrue(mDeviceIdleController.mMotionListener.isActive());
- assertTrue(mAnyMotionDetector.isMonitoring);
+ assertEquals(
+ mDeviceIdleController.hasMotionSensor(),
+ mDeviceIdleController.mMotionListener.isActive());
+ assertEquals(
+ mDeviceIdleController.hasMotionSensor(),
+ mAnyMotionDetector.isMonitoring);
assertFalse(mDeviceIdleController.isCharging());
assertFalse(mDeviceIdleController.isScreenOn());
break;
case STATE_LOCATING:
- assertTrue(mDeviceIdleController.mMotionListener.isActive());
- assertTrue(mAnyMotionDetector.isMonitoring);
+ assertEquals(
+ mDeviceIdleController.hasMotionSensor(),
+ mDeviceIdleController.mMotionListener.isActive());
assertFalse(mDeviceIdleController.isCharging());
assertFalse(mDeviceIdleController.isScreenOn());
break;
case STATE_IDLE:
- assertTrue(mDeviceIdleController.mMotionListener.isActive()
+ if (mDeviceIdleController.hasMotionSensor()) {
+ assertTrue(mDeviceIdleController.mMotionListener.isActive()
// If quick doze is enabled, the motion listener should NOT be active.
|| mDeviceIdleController.isQuickDozeEnabled());
+ }
assertFalse(mAnyMotionDetector.isMonitoring);
assertFalse(mDeviceIdleController.isCharging());
assertFalse(mDeviceIdleController.isScreenOn());
@@ -1514,9 +1550,11 @@
verifyLightStateConditions(LIGHT_STATE_OVERRIDE);
break;
case STATE_IDLE_MAINTENANCE:
- assertTrue(mDeviceIdleController.mMotionListener.isActive()
+ if (mDeviceIdleController.hasMotionSensor()) {
+ assertTrue(mDeviceIdleController.mMotionListener.isActive()
// If quick doze is enabled, the motion listener should NOT be active.
|| mDeviceIdleController.isQuickDozeEnabled());
+ }
assertFalse(mAnyMotionDetector.isMonitoring);
assertFalse(mDeviceIdleController.isCharging());
assertFalse(mDeviceIdleController.isScreenOn());
diff --git a/services/tests/mockingservicestests/src/com/android/server/deviceidle/BluetoothConstraintTest.java b/services/tests/mockingservicestests/src/com/android/server/deviceidle/BluetoothConstraintTest.java
new file mode 100644
index 0000000..f74ac1f
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/deviceidle/BluetoothConstraintTest.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.deviceidle;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.inOrder;
+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.never;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.eq;
+
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.DeviceIdleController;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+
+import java.util.Arrays;
+
+/**
+ * Tests for {@link com.android.server.deviceidle.BluetoothConstraint}.
+ */
+@RunWith(AndroidJUnit4.class)
+public class BluetoothConstraintTest {
+
+ private MockitoSession mMockingSession;
+
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private Context mContext;
+
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private Handler mHandler;
+
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private BluetoothManager mBluetoothManager;
+
+ @Mock
+ private DeviceIdleController.LocalService mDeviceIdleService;
+
+ private BluetoothConstraint mConstraint;
+
+ @Before
+ public void setUp() {
+ mMockingSession = mockitoSession()
+ .initMocks(this)
+ .strictness(Strictness.LENIENT)
+ .startMocking();
+ doReturn(mBluetoothManager)
+ .when(mContext).getSystemService(BluetoothManager.class);
+ mConstraint = new BluetoothConstraint(mContext, mHandler, mDeviceIdleService);
+ }
+
+ @After
+ public void tearDown() {
+ if (mMockingSession != null) {
+ mMockingSession.finishMocking();
+ }
+ }
+
+ @Test
+ public void testIsConnected_noBluetoothAdapter() {
+ doReturn(null).when(mBluetoothManager).getAdapter();
+ assertFalse(BluetoothConstraint.isBluetoothConnected(mBluetoothManager));
+ }
+
+ @Test
+ public void testIsConnected_noConnectedDevice() {
+ enableBluetooth(true);
+ assertFalse(BluetoothConstraint.isBluetoothConnected(mBluetoothManager));
+ }
+
+ @Test
+ public void testIsConnected_twoConnectedDevices() {
+ enableBluetooth(true, mock(BluetoothDevice.class), mock(BluetoothDevice.class));
+ assertTrue(BluetoothConstraint.isBluetoothConnected(mBluetoothManager));
+ }
+
+ @Test
+ public void testStartMonitoring_updatesActiveAtCorrectTimes() {
+ // First setup -> no callbacks should fire.
+ BluetoothConstraint constraint = mConstraint;
+ verify(mDeviceIdleService, never()).onConstraintStateChanged(any(), anyBoolean());
+ verify(mContext, never()).registerReceiver(eq(constraint.mReceiver), any());
+
+ InOrder order = inOrder(mDeviceIdleService);
+
+ // No devices -> active=false should be triggered.
+ enableBluetooth(true);
+ constraint.startMonitoring();
+ order.verify(mDeviceIdleService, times(1)).onConstraintStateChanged(any(), eq(false));
+
+ // One device -> active=true should be triggered.
+ enableBluetooth(true, mock(BluetoothDevice.class));
+ constraint.mReceiver.onReceive(
+ mContext, new Intent(BluetoothDevice.ACTION_ACL_CONNECTED));
+ constraint.startMonitoring();
+ order.verify(mDeviceIdleService, times(1)).exitIdle(eq("bluetooth"));
+
+ // Stop monitoring -> broadcast receiver should be unregistered.
+ constraint.stopMonitoring();
+ verify(mContext, times(1)).unregisterReceiver(eq(constraint.mReceiver));
+ order.verifyNoMoreInteractions();
+
+ }
+
+ private void enableBluetooth(boolean enabled, BluetoothDevice... devices) {
+ when(mBluetoothManager.getAdapter().isEnabled()).thenReturn(enabled);
+ when(mBluetoothManager.getConnectedDevices(eq(BluetoothProfile.GATT)))
+ .thenReturn(Arrays.asList(devices));
+ }
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index dc3287e..a459b0a 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -61,6 +61,7 @@
import android.service.notification.Condition;
import android.service.notification.ZenModeConfig;
import android.service.notification.ZenModeConfig.ScheduleInfo;
+import android.service.notification.ZenPolicy;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -683,6 +684,92 @@
}
@Test
+ public void testWriteXmlWithZenPolicy() throws Exception {
+ final String ruleId = "customRule";
+ setupZenConfig();
+
+ // one enabled automatic rule with zen policy
+ ArrayMap<String, ZenModeConfig.ZenRule> automaticRules = new ArrayMap<>();
+ ZenModeConfig.ZenRule customRule = new ZenModeConfig.ZenRule();
+ final ScheduleInfo customRuleInfo = new ScheduleInfo();
+ customRule.enabled = true;
+ customRule.creationTime = 0;
+ customRule.id = "customRule";
+ customRule.name = "Custom Rule";
+ customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ customRule.conditionId = ZenModeConfig.toScheduleConditionId(customRuleInfo);
+ customRule.configurationActivity =
+ new ComponentName("android", "ScheduleConditionProvider");
+ customRule.pkg = customRule.configurationActivity.getPackageName();
+ customRule.zenPolicy = new ZenPolicy.Builder()
+ .allowAlarms(false)
+ .allowMedia(false)
+ .allowRepeatCallers(false)
+ .allowCalls(ZenPolicy.PEOPLE_TYPE_NONE)
+ .allowMessages(ZenPolicy.PEOPLE_TYPE_CONTACTS)
+ .allowEvents(true)
+ .allowReminders(false)
+ .build();
+ automaticRules.put("customRule", customRule);
+ mZenModeHelperSpy.mConfig.automaticRules = automaticRules;
+
+ ZenModeConfig expected = mZenModeHelperSpy.mConfig.copy();
+
+ ByteArrayOutputStream baos = writeXmlAndPurge(false, null);
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(new BufferedInputStream(
+ new ByteArrayInputStream(baos.toByteArray())), null);
+ parser.nextTag();
+ mZenModeHelperSpy.readXml(parser, false);
+
+ ZenModeConfig.ZenRule original = expected.automaticRules.get(ruleId);
+ ZenModeConfig.ZenRule current = mZenModeHelperSpy.mConfig.automaticRules.get(ruleId);
+
+ assertEquals("Automatic rules mismatch", original, current);
+ }
+
+ @Test
+ public void testReadXmlRestoreWithZenPolicy() throws Exception {
+ final String ruleId = "customRule";
+ setupZenConfig();
+
+ // one enabled automatic rule with zen policy
+ ArrayMap<String, ZenModeConfig.ZenRule> automaticRules = new ArrayMap<>();
+ ZenModeConfig.ZenRule customRule = new ZenModeConfig.ZenRule();
+ final ScheduleInfo customRuleInfo = new ScheduleInfo();
+ customRule.enabled = true;
+ customRule.creationTime = 0;
+ customRule.id = ruleId;
+ customRule.name = "Custom Rule";
+ customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ customRule.conditionId = ZenModeConfig.toScheduleConditionId(customRuleInfo);
+ customRule.configurationActivity =
+ new ComponentName("android", "ScheduleConditionProvider");
+ customRule.pkg = customRule.configurationActivity.getPackageName();
+ customRule.zenPolicy = new ZenPolicy.Builder()
+ .allowSystem(true)
+ .allowCalls(ZenPolicy.PEOPLE_TYPE_ANYONE)
+ .allowReminders(true)
+ .build();
+ automaticRules.put(ruleId, customRule);
+ mZenModeHelperSpy.mConfig.automaticRules = automaticRules;
+
+ ZenModeConfig expected = mZenModeHelperSpy.mConfig.copy();
+
+ ByteArrayOutputStream baos = writeXmlAndPurge(false, null);
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(new BufferedInputStream(
+ new ByteArrayInputStream(baos.toByteArray())), null);
+ parser.nextTag();
+ mZenModeHelperSpy.readXml(parser, true);
+
+ ZenModeConfig.ZenRule original = expected.automaticRules.get(ruleId);
+ ZenModeConfig.ZenRule current = mZenModeHelperSpy.mConfig.automaticRules.get(ruleId);
+
+ assertEquals("Automatic rules mismatch", original, current);
+ }
+
+ @Test
public void testReadXmlRulesNotOverriden() throws Exception {
setupZenConfig();
@@ -896,6 +983,10 @@
customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
customRule.conditionId = ZenModeConfig.toScheduleConditionId(customRuleInfo);
customRule.component = new ComponentName("android", "ScheduleConditionProvider");
+ customRule.zenPolicy = new ZenPolicy.Builder()
+ .allowReminders(true)
+ .allowMessages(ZenPolicy.PEOPLE_TYPE_ANYONE)
+ .build();
automaticRules.put("customRule", customRule);
ZenModeConfig.ZenRule defaultScheduleRule = new ZenModeConfig.ZenRule();
@@ -943,6 +1034,10 @@
customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
customRule.conditionId = ZenModeConfig.toScheduleConditionId(customRuleInfo);
customRule.component = new ComponentName("android", "ScheduleConditionProvider");
+ customRule.zenPolicy = new ZenPolicy.Builder()
+ .allowReminders(true)
+ .allowMessages(ZenPolicy.PEOPLE_TYPE_ANYONE)
+ .build();
automaticRules.put("customRule", customRule);
ZenModeConfig.ZenRule defaultScheduleRule = new ZenModeConfig.ZenRule();
@@ -953,6 +1048,10 @@
defaultScheduleRule.conditionId = ZenModeConfig.toScheduleConditionId(
defaultScheduleRuleInfo);
defaultScheduleRule.id = ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID;
+ defaultScheduleRule.zenPolicy = new ZenPolicy.Builder()
+ .allowEvents(true)
+ .allowMessages(ZenPolicy.PEOPLE_TYPE_ANYONE)
+ .build();
automaticRules.put(ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID, defaultScheduleRule);
ZenModeConfig.ZenRule defaultEventRule = new ZenModeConfig.ZenRule();
@@ -963,6 +1062,11 @@
defaultEventRule.conditionId = ZenModeConfig.toScheduleConditionId(
defaultEventRuleInfo);
defaultEventRule.id = ZenModeConfig.EVENTS_DEFAULT_RULE_ID;
+ defaultScheduleRule.zenPolicy = new ZenPolicy.Builder()
+ .allowAlarms(false)
+ .allowMedia(false)
+ .allowRepeatCallers(false)
+ .build();
automaticRules.put(ZenModeConfig.EVENTS_DEFAULT_RULE_ID, defaultEventRule);
mZenModeHelperSpy.mConfig.automaticRules = automaticRules;
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
index 92b4dbb..bc62de1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -155,15 +155,17 @@
// Set initial orientation and update.
mToken.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
- mWm.updateOrientationFromAppTokens(mDisplayContent.getRequestedOverrideConfiguration(),
- null, mDisplayContent.getDisplayId());
+ mDisplayContent.updateOrientationFromAppTokens(
+ mDisplayContent.getRequestedOverrideConfiguration(),
+ null /* freezeThisOneIfNeeded */, false /* forceUpdate */);
assertEquals(SCREEN_ORIENTATION_LANDSCAPE, mDisplayContent.getLastOrientation());
appWindow.mResizeReported = false;
// Update the orientation to perform 180 degree rotation and check that resize was reported.
mToken.setOrientation(SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
- mWm.updateOrientationFromAppTokens(mDisplayContent.getRequestedOverrideConfiguration(),
- null, mDisplayContent.getDisplayId());
+ mDisplayContent.updateOrientationFromAppTokens(
+ mDisplayContent.getRequestedOverrideConfiguration(),
+ null /* freezeThisOneIfNeeded */, false /* forceUpdate */);
mWm.mRoot.performSurfacePlacement(false /* recoveringMemory */);
assertEquals(SCREEN_ORIENTATION_REVERSE_LANDSCAPE, mDisplayContent.getLastOrientation());
assertTrue(appWindow.mResizeReported);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 8430616..3826fac 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -31,7 +31,13 @@
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.same;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
@@ -60,9 +66,11 @@
import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
import com.android.server.wm.utils.WmDisplayCutout;
import org.junit.Test;
+import org.mockito.ArgumentCaptor;
import java.util.ArrayList;
import java.util.Arrays;
@@ -475,6 +483,13 @@
@SuppressLint("InlinedApi")
public void testOrientationDefinedByKeyguard() {
final DisplayContent dc = createNewDisplay();
+
+ // When display content is created its configuration is not yet initialized, which could
+ // cause unnecessary configuration propagation, so initialize it here.
+ final Configuration config = new Configuration();
+ dc.computeScreenConfiguration(config);
+ dc.onRequestedOverrideConfigurationChanged(config);
+
// Create a window that requests landscape orientation. It will define device orientation
// by default.
final WindowState window = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
@@ -567,6 +582,52 @@
assertNull("default display Ime target: ", mDisplayContent.mInputMethodTarget);
}
+ @Test
+ public void testOnDescendantOrientationRequestChanged() {
+ final DisplayContent dc = createNewDisplay();
+ mWm.mAtmService.mRootActivityContainer = mock(RootActivityContainer.class);
+ final int newOrientation = dc.getLastOrientation() == SCREEN_ORIENTATION_LANDSCAPE
+ ? SCREEN_ORIENTATION_PORTRAIT
+ : SCREEN_ORIENTATION_LANDSCAPE;
+
+ final WindowState window = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
+ window.getTask().mTaskRecord = mock(TaskRecord.class, ExtendedMockito.RETURNS_DEEP_STUBS);
+ window.mAppToken.setOrientation(newOrientation);
+
+ ActivityRecord activityRecord = mock(ActivityRecord.class);
+
+ assertTrue("Display should rotate to handle orientation request by default.",
+ dc.onDescendantOrientationChanged(window.mToken.token, activityRecord));
+
+ final ArgumentCaptor<Configuration> captor = ArgumentCaptor.forClass(Configuration.class);
+ verify(mWm.mAtmService).updateDisplayOverrideConfigurationLocked(captor.capture(),
+ same(activityRecord), anyBoolean(), eq(dc.getDisplayId()));
+ final Configuration newDisplayConfig = captor.getValue();
+ assertEquals(Configuration.ORIENTATION_PORTRAIT, newDisplayConfig.orientation);
+ }
+
+ @Test
+ public void testOnDescendantOrientationRequestChanged_FrozenToUserRotation() {
+ final DisplayContent dc = createNewDisplay();
+ dc.getDisplayRotation().setFixedToUserRotation(true);
+ mWm.mAtmService.mRootActivityContainer = mock(RootActivityContainer.class);
+ final int newOrientation = dc.getLastOrientation() == SCREEN_ORIENTATION_LANDSCAPE
+ ? SCREEN_ORIENTATION_PORTRAIT
+ : SCREEN_ORIENTATION_LANDSCAPE;
+
+ final WindowState window = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
+ window.getTask().mTaskRecord = mock(TaskRecord.class, ExtendedMockito.RETURNS_DEEP_STUBS);
+ window.mAppToken.setOrientation(newOrientation);
+
+ ActivityRecord activityRecord = mock(ActivityRecord.class);
+
+ assertFalse("Display shouldn't rotate to handle orientation request if fixed to"
+ + " user rotation.",
+ dc.onDescendantOrientationChanged(window.mToken.token, activityRecord));
+ verify(mWm.mAtmService, never()).updateDisplayOverrideConfigurationLocked(any(),
+ eq(activityRecord), anyBoolean(), eq(dc.getDisplayId()));
+ }
+
private boolean isOptionsPanelAtRight(int displayId) {
return (mWm.getPreferredOptionsPanelGravity(displayId) & Gravity.RIGHT) == Gravity.RIGHT;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
index bf4b52e..6b31e6f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
@@ -33,6 +33,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import android.content.ContentResolver;
@@ -234,7 +235,7 @@
}
@Test
- public void testReturnsSidesays_UserRotationLocked_IncompatibleAppRequest()
+ public void testReturnsSideways_UserRotationLocked_IncompatibleAppRequest()
throws Exception {
mBuilder.build();
configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, false);
@@ -604,6 +605,26 @@
SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
}
+ // ========================
+ // Non-rotation API Tests
+ // ========================
+ @Test
+ public void testRespectsAppRequestedOrientationByDefault() throws Exception {
+ mBuilder.build();
+
+ assertTrue("Display rotation should respect app requested orientation by"
+ + " default.", mTarget.respectAppRequestedOrientation());
+ }
+
+ @Test
+ public void testNotRespectAppRequestedOrientation_FixedToUserRotation() throws Exception {
+ mBuilder.build();
+ mTarget.setFixedToUserRotation(true);
+
+ assertFalse("Display rotation shouldn't respect app requested orientation if"
+ + " fixed to user rotation.", mTarget.respectAppRequestedOrientation());
+ }
+
/**
* Call {@link DisplayRotation#configure(int, int, int, int)} to configure {@link #mTarget}
* according to given parameters.
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index 60f957f..e156143 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -27,6 +27,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
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.WindowContainer.POSITION_BOTTOM;
@@ -38,8 +39,10 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
+import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
@@ -559,8 +562,7 @@
builder.setLayer(2).setIsVisible(true);
final TestWindowContainer visibleUnspecifiedRootChildChildFillsParent =
visibleUnspecifiedRootChild.addChildWindow(builder);
- visibleUnspecifiedRootChildChildFillsParent.setOrientation(
- SCREEN_ORIENTATION_PORTRAIT);
+ visibleUnspecifiedRootChildChildFillsParent.setOrientation(SCREEN_ORIENTATION_PORTRAIT);
assertEquals(SCREEN_ORIENTATION_PORTRAIT,
visibleUnspecifiedRootChildChildFillsParent.getOrientation());
assertEquals(SCREEN_ORIENTATION_UNSET, visibleUnspecifiedRootChild.getOrientation());
@@ -724,6 +726,19 @@
verify(grandChild, times(1)).onParentResize();
}
+ @Test
+ public void testOnDescendantOrientationRequestChangedPropagation() {
+ final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
+ final TestWindowContainer root = spy(builder.build());
+
+ final IBinder binder = mock(IBinder.class);
+ final ActivityRecord activityRecord = mock(ActivityRecord.class);
+ final TestWindowContainer child = root.addChildWindow();
+
+ child.setOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED, binder, activityRecord);
+ verify(root).onDescendantOrientationChanged(binder, activityRecord);
+ }
+
/* Used so we can gain access to some protected members of the {@link WindowContainer} class */
private static class TestWindowContainer extends WindowContainer<TestWindowContainer> {
private final int mLayer;
diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
index 369a002..4c2a984 100644
--- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
@@ -16,16 +16,16 @@
package com.android.framework.permission.tests;
-import android.content.res.Configuration;
+import static android.view.Display.DEFAULT_DISPLAY;
+
import android.os.Binder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.test.suitebuilder.annotation.SmallTest;
import android.view.IWindowManager;
-import junit.framework.TestCase;
-import static android.view.Display.DEFAULT_DISPLAY;
+import junit.framework.TestCase;
/**
* TODO: Remove this. This is only a placeholder, need to implement this.
@@ -73,17 +73,6 @@
}
try {
- mWm.updateOrientationFromAppTokens(new Configuration(),
- null /* freezeThisOneIfNeeded */, DEFAULT_DISPLAY);
- fail("IWindowManager.updateOrientationFromAppTokens did not throw SecurityException as"
- + " expected");
- } catch (SecurityException e) {
- // expected
- } catch (RemoteException e) {
- fail("Unexpected remote exception");
- }
-
- try {
mWm.prepareAppTransition(0, false);
fail("IWindowManager.prepareAppTransition did not throw SecurityException as"
+ " expected");
diff --git a/tools/incident_report/printer.h b/tools/incident_report/printer.h
index ed93fa1..63e276b 100644
--- a/tools/incident_report/printer.h
+++ b/tools/incident_report/printer.h
@@ -22,7 +22,7 @@
class Out
{
public:
- Out(int fd);
+ explicit Out(int fd);
~Out();
void printf(const char* format, ...);