Merge "Migrate android_uiautomator generation to Soong." into pi-dev-plus-aosp
diff --git a/CleanSpec.mk b/CleanSpec.mk
index e728897..2e949c5 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -243,6 +243,7 @@
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/hardware)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/core/java/android/os/storage/*)
$(call add-clean-step, rm -rf $(OUT_DIR)/host/common/obj/JAVA_LIBRARIES/platformprotos_intermediates)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/statsdprotolite_intermediates)
# ******************************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
# ******************************************************************
diff --git a/api/test-current.txt b/api/test-current.txt
index 9403b49..dd88856 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -604,6 +604,10 @@
field public static final android.os.Parcelable.Creator<android.os.IncidentReportArgs> CREATOR;
}
+ public final class PowerManager {
+ method public void nap(long);
+ }
+
public class Process {
method public static final int getThreadScheduler(int) throws java.lang.IllegalArgumentException;
}
diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp
index 45d6281..5604973 100644
--- a/cmds/incidentd/src/Section.cpp
+++ b/cmds/incidentd/src/Section.cpp
@@ -70,6 +70,13 @@
return WriteFully(fd, buf, p - buf) ? NO_ERROR : -errno;
}
+static void write_section_stats(IncidentMetadata::SectionStats* stats, const FdBuffer& buffer) {
+ stats->set_dump_size_bytes(buffer.data().size());
+ stats->set_dump_duration_ms(buffer.durationMs());
+ stats->set_timed_out(buffer.timedOut());
+ stats->set_is_truncated(buffer.truncated());
+}
+
// Reads data from FdBuffer and writes it to the requests file descriptor.
static status_t write_report_requests(const int id, const FdBuffer& buffer,
ReportRequestSet* requests) {
@@ -77,12 +84,6 @@
EncodedBuffer::iterator data = buffer.data();
PrivacyBuffer privacyBuffer(get_privacy_of_section(id), data);
int writeable = 0;
- IncidentMetadata::SectionStats* stats = requests->sectionStats(id);
-
- stats->set_dump_size_bytes(data.size());
- stats->set_dump_duration_ms(buffer.durationMs());
- stats->set_timed_out(buffer.timedOut());
- stats->set_is_truncated(buffer.truncated());
// The streaming ones, group requests by spec in order to save unnecessary strip operations
map<PrivacySpec, vector<sp<ReportRequest>>> requestsBySpec;
@@ -140,7 +141,8 @@
writeable++;
VLOG("Section %d flushed %zu bytes to dropbox %d with spec %d", id, privacyBuffer.size(),
requests->mainFd(), spec.dest);
- stats->set_report_size_bytes(privacyBuffer.size());
+ // Reports bytes of the section uploaded via dropbox after filtering.
+ requests->sectionStats(id)->set_report_size_bytes(privacyBuffer.size());
}
DONE:
@@ -270,7 +272,7 @@
status_t readStatus = buffer.readProcessedDataInStream(fd.get(), std::move(p2cPipe.writeFd()),
std::move(c2pPipe.readFd()),
this->timeoutMs, mIsSysfs);
-
+ write_section_stats(requests->sectionStats(this->id), buffer);
if (readStatus != NO_ERROR || buffer.timedOut()) {
ALOGW("FileSection '%s' failed to read data from incident helper: %s, timedout: %s",
this->name.string(), strerror(-readStatus), buffer.timedOut() ? "true" : "false");
@@ -363,7 +365,7 @@
status_t readStatus = buffer.readProcessedDataInStream(
fd.get(), std::move(p2cPipe.writeFd()), std::move(c2pPipe.readFd()), this->timeoutMs,
isSysfs(mFilenames[index]));
-
+ write_section_stats(requests->sectionStats(this->id), buffer);
if (readStatus != NO_ERROR || buffer.timedOut()) {
ALOGW("GZipSection '%s' failed to read data from gzip: %s, timedout: %s",
this->name.string(), strerror(-readStatus), buffer.timedOut() ? "true" : "false");
@@ -499,7 +501,7 @@
}
}
}
-
+ write_section_stats(requests->sectionStats(this->id), buffer);
if (timedOut || buffer.timedOut()) {
ALOGW("WorkerThreadSection '%s' timed out", this->name.string());
return NO_ERROR;
@@ -580,6 +582,7 @@
cmdPipe.writeFd().reset();
status_t readStatus = buffer.read(ihPipe.readFd().get(), this->timeoutMs);
+ write_section_stats(requests->sectionStats(this->id), buffer);
if (readStatus != NO_ERROR || buffer.timedOut()) {
ALOGW("CommandSection '%s' failed to read data from incident helper: %s, timedout: %s",
this->name.string(), strerror(-readStatus), buffer.timedOut() ? "true" : "false");
@@ -927,4 +930,4 @@
} // namespace incidentd
} // namespace os
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/cmds/incidentd/tests/Section_test.cpp b/cmds/incidentd/tests/Section_test.cpp
index 9f92353..33f5206 100644
--- a/cmds/incidentd/tests/Section_test.cpp
+++ b/cmds/incidentd/tests/Section_test.cpp
@@ -146,6 +146,7 @@
TEST_F(SectionTest, FileSectionTimeout) {
FileSection fs(TIMEOUT_PARSER, tf.path, QUICK_TIMEOUT_MS);
ASSERT_EQ(NO_ERROR, fs.Execute(&requests));
+ ASSERT_TRUE(requests.sectionStats(TIMEOUT_PARSER)->timed_out());
}
TEST_F(SectionTest, GZipSection) {
@@ -204,12 +205,14 @@
TEST_F(SectionTest, CommandSectionCommandTimeout) {
CommandSection cs(NOOP_PARSER, QUICK_TIMEOUT_MS, "/system/bin/yes", NULL);
ASSERT_EQ(NO_ERROR, cs.Execute(&requests));
+ ASSERT_TRUE(requests.sectionStats(NOOP_PARSER)->timed_out());
}
TEST_F(SectionTest, CommandSectionIncidentHelperTimeout) {
CommandSection cs(TIMEOUT_PARSER, QUICK_TIMEOUT_MS, "/system/bin/echo", "about", NULL);
requests.setMainFd(STDOUT_FILENO);
ASSERT_EQ(NO_ERROR, cs.Execute(&requests));
+ ASSERT_TRUE(requests.sectionStats(TIMEOUT_PARSER)->timed_out());
}
TEST_F(SectionTest, CommandSectionBadCommand) {
@@ -221,6 +224,7 @@
CommandSection cs(TIMEOUT_PARSER, QUICK_TIMEOUT_MS, "nonexistcommand", "-opt", NULL);
// timeout will return first
ASSERT_EQ(NO_ERROR, cs.Execute(&requests));
+ ASSERT_TRUE(requests.sectionStats(TIMEOUT_PARSER)->timed_out());
}
TEST_F(SectionTest, LogSectionBinary) {
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index e26806b..d025337 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -27,8 +27,10 @@
#include "subscriber/SubscriberReporter.h"
#include <android-base/file.h>
+#include <android-base/stringprintf.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
+#include <binder/PermissionController.h>
#include <dirent.h>
#include <frameworks/base/cmds/statsd/src/statsd_config.pb.h>
#include <private/android_filesystem_config.h>
@@ -42,13 +44,83 @@
using namespace android;
+using android::base::StringPrintf;
+
namespace android {
namespace os {
namespace statsd {
constexpr const char* kPermissionDump = "android.permission.DUMP";
+constexpr const char* kPermissionUsage = "android.permission.PACKAGE_USAGE_STATS";
+
+constexpr const char* kOpUsage = "android:get_usage_stats";
+
#define STATS_SERVICE_DIR "/data/misc/stats-service"
+static binder::Status ok() {
+ return binder::Status::ok();
+}
+
+static binder::Status exception(uint32_t code, const std::string& msg) {
+ ALOGE("%s (%d)", msg.c_str(), code);
+ return binder::Status::fromExceptionCode(code, String8(msg.c_str()));
+}
+
+binder::Status checkUid(uid_t expectedUid) {
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ if (uid == expectedUid || uid == AID_ROOT) {
+ return ok();
+ } else {
+ return exception(binder::Status::EX_SECURITY,
+ StringPrintf("UID %d is not expected UID %d", uid, expectedUid));
+ }
+}
+
+binder::Status checkDumpAndUsageStats(const String16& packageName) {
+ pid_t pid = IPCThreadState::self()->getCallingPid();
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+
+ // Root, system, and shell always have access
+ if (uid == AID_ROOT || uid == AID_SYSTEM || uid == AID_SHELL) {
+ return ok();
+ }
+
+ // Caller must be granted these permissions
+ if (!checkCallingPermission(String16(kPermissionDump))) {
+ return exception(binder::Status::EX_SECURITY,
+ StringPrintf("UID %d / PID %d lacks permission %s", uid, pid, kPermissionDump));
+ }
+ if (!checkCallingPermission(String16(kPermissionUsage))) {
+ return exception(binder::Status::EX_SECURITY,
+ StringPrintf("UID %d / PID %d lacks permission %s", uid, pid, kPermissionUsage));
+ }
+
+ // Caller must also have usage stats op granted
+ PermissionController pc;
+ switch (pc.noteOp(String16(kOpUsage), uid, packageName)) {
+ case PermissionController::MODE_ALLOWED:
+ case PermissionController::MODE_DEFAULT:
+ return ok();
+ default:
+ return exception(binder::Status::EX_SECURITY,
+ StringPrintf("UID %d / PID %d lacks app-op %s", uid, pid, kOpUsage));
+ }
+}
+
+#define ENFORCE_UID(uid) { \
+ binder::Status status = checkUid((uid)); \
+ if (!status.isOk()) { \
+ return status; \
+ } \
+}
+
+#define ENFORCE_DUMP_AND_USAGE_STATS(packageName) { \
+ binder::Status status = checkDumpAndUsageStats(packageName); \
+ if (!status.isOk()) { \
+ return status; \
+ } \
+}
+
StatsService::StatsService(const sp<Looper>& handlerLooper)
: mAnomalyAlarmMonitor(new AlarmMonitor(MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS,
[](const sp<IStatsCompanionService>& sc, int64_t timeMillis) {
@@ -172,6 +244,9 @@
* Write debugging data about statsd.
*/
status_t StatsService::dump(int fd, const Vector<String16>& args) {
+ if (!checkCallingPermission(String16(kPermissionDump))) {
+ return PERMISSION_DENIED;
+ }
FILE* out = fdopen(fd, "w");
if (out == NULL) {
return NO_MEMORY; // the fd is already open
@@ -212,7 +287,10 @@
* Implementation of the adb shell cmd stats command.
*/
status_t StatsService::command(FILE* in, FILE* out, FILE* err, Vector<String8>& args) {
- // TODO: Permission check
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ if (uid != AID_ROOT && uid != AID_SHELL) {
+ return PERMISSION_DENIED;
+ }
const int argCount = args.size();
if (argCount >= 1) {
@@ -661,13 +739,9 @@
Status StatsService::informAllUidData(const vector<int32_t>& uid, const vector<int64_t>& version,
const vector<String16>& app) {
+ ENFORCE_UID(AID_SYSTEM);
+
VLOG("StatsService::informAllUidData was called");
-
- if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
- return Status::fromExceptionCode(Status::EX_SECURITY,
- "Only system uid can call informAllUidData");
- }
-
mUidMap->updateMap(getElapsedRealtimeNs(), uid, version, app);
VLOG("StatsService::informAllUidData succeeded");
@@ -675,36 +749,26 @@
}
Status StatsService::informOnePackage(const String16& app, int32_t uid, int64_t version) {
- VLOG("StatsService::informOnePackage was called");
+ ENFORCE_UID(AID_SYSTEM);
- if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
- return Status::fromExceptionCode(Status::EX_SECURITY,
- "Only system uid can call informOnePackage");
- }
+ VLOG("StatsService::informOnePackage was called");
mUidMap->updateApp(getElapsedRealtimeNs(), app, uid, version);
return Status::ok();
}
Status StatsService::informOnePackageRemoved(const String16& app, int32_t uid) {
- VLOG("StatsService::informOnePackageRemoved was called");
+ ENFORCE_UID(AID_SYSTEM);
- if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
- return Status::fromExceptionCode(Status::EX_SECURITY,
- "Only system uid can call informOnePackageRemoved");
- }
+ VLOG("StatsService::informOnePackageRemoved was called");
mUidMap->removeApp(getElapsedRealtimeNs(), app, uid);
mConfigManager->RemoveConfigs(uid);
return Status::ok();
}
Status StatsService::informAnomalyAlarmFired() {
+ ENFORCE_UID(AID_SYSTEM);
+
VLOG("StatsService::informAnomalyAlarmFired was called");
-
- if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
- return Status::fromExceptionCode(Status::EX_SECURITY,
- "Only system uid can call informAnomalyAlarmFired");
- }
-
int64_t currentTimeSec = getElapsedRealtimeSec();
std::unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet =
mAnomalyAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
@@ -718,14 +782,9 @@
}
Status StatsService::informAlarmForSubscriberTriggeringFired() {
+ ENFORCE_UID(AID_SYSTEM);
+
VLOG("StatsService::informAlarmForSubscriberTriggeringFired was called");
-
- if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
- return Status::fromExceptionCode(
- Status::EX_SECURITY,
- "Only system uid can call informAlarmForSubscriberTriggeringFired");
- }
-
int64_t currentTimeSec = getElapsedRealtimeSec();
std::unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet =
mPeriodicAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
@@ -739,44 +798,28 @@
}
Status StatsService::informPollAlarmFired() {
+ ENFORCE_UID(AID_SYSTEM);
+
VLOG("StatsService::informPollAlarmFired was called");
-
- if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
- return Status::fromExceptionCode(Status::EX_SECURITY,
- "Only system uid can call informPollAlarmFired");
- }
-
mProcessor->informPullAlarmFired(getElapsedRealtimeNs());
-
VLOG("StatsService::informPollAlarmFired succeeded");
-
return Status::ok();
}
Status StatsService::systemRunning() {
- if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
- return Status::fromExceptionCode(Status::EX_SECURITY,
- "Only system uid can call systemRunning");
- }
+ ENFORCE_UID(AID_SYSTEM);
// When system_server is up and running, schedule the dropbox task to run.
VLOG("StatsService::systemRunning");
-
sayHiToStatsCompanion();
-
return Status::ok();
}
Status StatsService::writeDataToDisk() {
- if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
- return Status::fromExceptionCode(Status::EX_SECURITY,
- "Only system uid can call systemRunning");
- }
+ ENFORCE_UID(AID_SYSTEM);
VLOG("StatsService::writeDataToDisk");
-
mProcessor->WriteDataToDisk();
-
return Status::ok();
}
@@ -791,13 +834,9 @@
}
Status StatsService::statsCompanionReady() {
+ ENFORCE_UID(AID_SYSTEM);
+
VLOG("StatsService::statsCompanionReady was called");
-
- if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
- return Status::fromExceptionCode(Status::EX_SECURITY,
- "Only system uid can call statsCompanionReady");
- }
-
sp<IStatsCompanionService> statsCompanion = getStatsCompanionService();
if (statsCompanion == nullptr) {
return Status::fromExceptionCode(
@@ -821,33 +860,31 @@
mProcessor->OnLogEvent(event, reconnectionStarts);
}
-Status StatsService::getData(int64_t key, vector<uint8_t>* output) {
+Status StatsService::getData(int64_t key, const String16& packageName, vector<uint8_t>* output) {
+ ENFORCE_DUMP_AND_USAGE_STATS(packageName);
+
IPCThreadState* ipc = IPCThreadState::self();
VLOG("StatsService::getData with Pid %i, Uid %i", ipc->getCallingPid(), ipc->getCallingUid());
- if (!checkCallingPermission(String16(kPermissionDump))) {
- return Status::fromExceptionCode(binder::Status::EX_SECURITY);
- }
ConfigKey configKey(ipc->getCallingUid(), key);
mProcessor->onDumpReport(configKey, getElapsedRealtimeNs(),
false /* include_current_bucket*/, output);
return Status::ok();
}
-Status StatsService::getMetadata(vector<uint8_t>* output) {
+Status StatsService::getMetadata(const String16& packageName, vector<uint8_t>* output) {
+ ENFORCE_DUMP_AND_USAGE_STATS(packageName);
+
IPCThreadState* ipc = IPCThreadState::self();
VLOG("StatsService::getMetadata with Pid %i, Uid %i", ipc->getCallingPid(),
ipc->getCallingUid());
- if (!checkCallingPermission(String16(kPermissionDump))) {
- return Status::fromExceptionCode(binder::Status::EX_SECURITY);
- }
StatsdStats::getInstance().dumpStats(output, false); // Don't reset the counters.
return Status::ok();
}
-Status StatsService::addConfiguration(int64_t key, const vector <uint8_t>& config) {
- if (!checkCallingPermission(String16(kPermissionDump))) {
- return Status::fromExceptionCode(binder::Status::EX_SECURITY);
- }
+Status StatsService::addConfiguration(int64_t key, const vector <uint8_t>& config,
+ const String16& packageName) {
+ ENFORCE_DUMP_AND_USAGE_STATS(packageName);
+
IPCThreadState* ipc = IPCThreadState::self();
if (addConfigurationChecked(ipc->getCallingUid(), key, config)) {
return Status::ok();
@@ -870,30 +907,29 @@
return true;
}
-Status StatsService::removeDataFetchOperation(int64_t key) {
- if (!checkCallingPermission(String16(kPermissionDump))) {
- return Status::fromExceptionCode(binder::Status::EX_SECURITY);
- }
+Status StatsService::removeDataFetchOperation(int64_t key, const String16& packageName) {
+ ENFORCE_DUMP_AND_USAGE_STATS(packageName);
+
IPCThreadState* ipc = IPCThreadState::self();
ConfigKey configKey(ipc->getCallingUid(), key);
mConfigManager->RemoveConfigReceiver(configKey);
return Status::ok();
}
-Status StatsService::setDataFetchOperation(int64_t key, const sp<android::IBinder>& intentSender) {
- if (!checkCallingPermission(String16(kPermissionDump))) {
- return Status::fromExceptionCode(binder::Status::EX_SECURITY);
- }
+Status StatsService::setDataFetchOperation(int64_t key,
+ const sp<android::IBinder>& intentSender,
+ const String16& packageName) {
+ ENFORCE_DUMP_AND_USAGE_STATS(packageName);
+
IPCThreadState* ipc = IPCThreadState::self();
ConfigKey configKey(ipc->getCallingUid(), key);
mConfigManager->SetConfigReceiver(configKey, intentSender);
return Status::ok();
}
-Status StatsService::removeConfiguration(int64_t key) {
- if (!checkCallingPermission(String16(kPermissionDump))) {
- return Status::fromExceptionCode(binder::Status::EX_SECURITY);
- }
+Status StatsService::removeConfiguration(int64_t key, const String16& packageName) {
+ ENFORCE_DUMP_AND_USAGE_STATS(packageName);
+
IPCThreadState* ipc = IPCThreadState::self();
ConfigKey configKey(ipc->getCallingUid(), key);
mConfigManager->RemoveConfig(configKey);
@@ -903,11 +939,11 @@
Status StatsService::setBroadcastSubscriber(int64_t configId,
int64_t subscriberId,
- const sp<android::IBinder>& intentSender) {
+ const sp<android::IBinder>& intentSender,
+ const String16& packageName) {
+ ENFORCE_DUMP_AND_USAGE_STATS(packageName);
+
VLOG("StatsService::setBroadcastSubscriber called.");
- if (!checkCallingPermission(String16(kPermissionDump))) {
- return Status::fromExceptionCode(binder::Status::EX_SECURITY);
- }
IPCThreadState* ipc = IPCThreadState::self();
ConfigKey configKey(ipc->getCallingUid(), configId);
SubscriberReporter::getInstance()
@@ -916,11 +952,11 @@
}
Status StatsService::unsetBroadcastSubscriber(int64_t configId,
- int64_t subscriberId) {
+ int64_t subscriberId,
+ const String16& packageName) {
+ ENFORCE_DUMP_AND_USAGE_STATS(packageName);
+
VLOG("StatsService::unsetBroadcastSubscriber called.");
- if (!checkCallingPermission(String16(kPermissionDump))) {
- return Status::fromExceptionCode(binder::Status::EX_SECURITY);
- }
IPCThreadState* ipc = IPCThreadState::self();
ConfigKey configKey(ipc->getCallingUid(), configId);
SubscriberReporter::getInstance()
@@ -928,7 +964,6 @@
return Status::ok();
}
-
void StatsService::binderDied(const wp <IBinder>& who) {
ALOGW("statscompanion service died");
mProcessor->WriteDataToDisk();
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index d502796..774a3e9 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -81,36 +81,44 @@
/**
* Binder call for clients to request data for this configuration key.
*/
- virtual Status getData(int64_t key, vector<uint8_t>* output) override;
+ virtual Status getData(int64_t key,
+ const String16& packageName,
+ vector<uint8_t>* output) override;
/**
* Binder call for clients to get metadata across all configs in statsd.
*/
- virtual Status getMetadata(vector<uint8_t>* output) override;
+ virtual Status getMetadata(const String16& packageName,
+ vector<uint8_t>* output) override;
/**
* Binder call to let clients send a configuration and indicate they're interested when they
* should requestData for this configuration.
*/
- virtual Status addConfiguration(int64_t key, const vector<uint8_t>& config) override;
+ virtual Status addConfiguration(int64_t key,
+ const vector<uint8_t>& config,
+ const String16& packageName) override;
/**
* Binder call to let clients register the data fetch operation for a configuration.
*/
virtual Status setDataFetchOperation(int64_t key,
- const sp<android::IBinder>& intentSender) override;
+ const sp<android::IBinder>& intentSender,
+ const String16& packageName) override;
/**
* Binder call to remove the data fetch operation for the specified config key.
*/
- virtual Status removeDataFetchOperation(int64_t key) override;
+ virtual Status removeDataFetchOperation(int64_t key,
+ const String16& packageName) override;
/**
* Binder call to allow clients to remove the specified configuration.
*/
- virtual Status removeConfiguration(int64_t key) override;
+ virtual Status removeConfiguration(int64_t key,
+ const String16& packageName) override;
/**
* Binder call to associate the given config's subscriberId with the given intentSender.
@@ -118,12 +126,15 @@
*/
virtual Status setBroadcastSubscriber(int64_t configId,
int64_t subscriberId,
- const sp<android::IBinder>& intentSender) override;
+ const sp<android::IBinder>& intentSender,
+ const String16& packageName) override;
/**
* Binder call to unassociate the given config's subscriberId with any intentSender.
*/
- virtual Status unsetBroadcastSubscriber(int64_t configId, int64_t subscriberId) override;
+ virtual Status unsetBroadcastSubscriber(int64_t configId,
+ int64_t subscriberId,
+ const String16& packageName) override;
/** Inform statsCompanion that statsd is ready. */
virtual void sayHiToStatsCompanion();
diff --git a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
index 5499ee3..af07f6b 100644
--- a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
@@ -27,6 +27,7 @@
#ifdef __ANDROID__
+const string kAndroid = "android";
const string kApp1 = "app1.sharing.1";
const int kConfigKey = 789130123; // Randomly chosen to avoid collisions with existing configs.
@@ -35,12 +36,12 @@
config.SerializeToString(&str);
std::vector<uint8_t> configAsVec(str.begin(), str.end());
bool success;
- service.addConfiguration(kConfigKey, configAsVec);
+ service.addConfiguration(kConfigKey, configAsVec, String16(kAndroid.c_str()));
}
ConfigMetricsReport GetReports(StatsService& service) {
vector<uint8_t> output;
- service.getData(kConfigKey, &output);
+ service.getData(kConfigKey, String16(kAndroid.c_str()), &output);
ConfigMetricsReportList reports;
reports.ParseFromArray(output.data(), output.size());
EXPECT_EQ(1, reports.reports_size());
@@ -134,4 +135,4 @@
} // namespace statsd
} // namespace os
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index fdc6c92..edfb8d0 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -136,6 +136,7 @@
Landroid/app/ActivityThread$ServiceArgsData;->token:Landroid/os/IBinder;
Landroid/app/ActivityThread;->sPackageManager:Landroid/content/pm/IPackageManager;
Landroid/app/ActivityThread;->startActivityNow(Landroid/app/Activity;Ljava/lang/String;Landroid/content/Intent;Landroid/content/pm/ActivityInfo;Landroid/os/IBinder;Landroid/os/Bundle;Landroid/app/Activity$NonConfigurationInstances;)Landroid/app/Activity;
+Landroid/app/admin/DevicePolicyManager;->getMandatoryBackupTransport()Landroid/content/ComponentName;
Landroid/app/admin/DevicePolicyManager;->getProfileOwnerAsUser(I)Landroid/content/ComponentName;
Landroid/app/admin/DevicePolicyManager;->getTrustAgentConfiguration(Landroid/content/ComponentName;Landroid/content/ComponentName;I)Ljava/util/List;
Landroid/app/admin/DevicePolicyManager;->packageHasActiveAdmins(Ljava/lang/String;I)Z
@@ -1500,7 +1501,6 @@
Landroid/os/PowerManager;->getMinimumScreenBrightnessSetting()I
Landroid/os/PowerManager;->isLightDeviceIdleMode()Z
Landroid/os/PowerManager;->mService:Landroid/os/IPowerManager;
-Landroid/os/PowerManager;->nap(J)V
Landroid/os/PowerManager;->userActivity(JZ)V
Landroid/os/PowerManager;->validateWakeLockParameters(ILjava/lang/String;)V
Landroid/os/PowerManager;->wakeUp(JLjava/lang/String;)V
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index eba7471..a41da0e 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -5442,7 +5442,8 @@
* runtime's instruction set is.
*/
private String getInstrumentationLibrary(ApplicationInfo appInfo, InstrumentationInfo insInfo) {
- if (appInfo.primaryCpuAbi != null && appInfo.secondaryCpuAbi != null) {
+ if (appInfo.primaryCpuAbi != null && appInfo.secondaryCpuAbi != null
+ && appInfo.secondaryCpuAbi.equals(insInfo.secondaryCpuAbi)) {
// Get the instruction set supported by the secondary ABI. In the presence
// of a native bridge this might be different than the one secondary ABI used.
String secondaryIsa =
@@ -5671,6 +5672,16 @@
"Unable to find instrumentation info for: " + data.instrumentationName);
}
+ // Warn of potential ABI mismatches.
+ if (!Objects.equals(data.appInfo.primaryCpuAbi, ii.primaryCpuAbi)
+ || !Objects.equals(data.appInfo.secondaryCpuAbi, ii.secondaryCpuAbi)) {
+ Slog.w(TAG, "Package uses different ABI(s) than its instrumentation: "
+ + "package[" + data.appInfo.packageName + "]: "
+ + data.appInfo.primaryCpuAbi + ", " + data.appInfo.secondaryCpuAbi
+ + " instrumentation[" + ii.packageName + "]: "
+ + ii.primaryCpuAbi + ", " + ii.secondaryCpuAbi);
+ }
+
mInstrumentationPackageName = ii.packageName;
mInstrumentationAppDir = ii.sourceDir;
mInstrumentationSplitAppDirs = ii.splitSourceDirs;
diff --git a/core/java/android/app/StatsManager.java b/core/java/android/app/StatsManager.java
index 8783d94..45754ae 100644
--- a/core/java/android/app/StatsManager.java
+++ b/core/java/android/app/StatsManager.java
@@ -15,10 +15,13 @@
*/
package android.app;
-import android.Manifest;
+import static android.Manifest.permission.DUMP;
+import static android.Manifest.permission.PACKAGE_USAGE_STATS;
+
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
+import android.content.Context;
import android.os.IBinder;
import android.os.IStatsManager;
import android.os.RemoteException;
@@ -33,10 +36,13 @@
*/
@SystemApi
public final class StatsManager {
- IStatsManager mService;
private static final String TAG = "StatsManager";
private static final boolean DEBUG = false;
+ private final Context mContext;
+
+ private IStatsManager mService;
+
/**
* Long extra of uid that added the relevant stats config.
*/
@@ -79,7 +85,8 @@
*
* @hide
*/
- public StatsManager() {
+ public StatsManager(Context context) {
+ mContext = context;
}
/**
@@ -92,15 +99,18 @@
* @throws StatsUnavailableException if unsuccessful due to failing to connect to stats service
* @throws IllegalArgumentException if config is not a wire-encoded StatsdConfig proto
*/
- @RequiresPermission(Manifest.permission.DUMP)
+ @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public void addConfig(long configKey, byte[] config) throws StatsUnavailableException {
synchronized (this) {
try {
IStatsManager service = getIStatsManagerLocked();
- service.addConfiguration(configKey, config); // can throw IllegalArgumentException
+ // can throw IllegalArgumentException
+ service.addConfiguration(configKey, config, mContext.getOpPackageName());
} catch (RemoteException e) {
Slog.e(TAG, "Failed to connect to statsd when adding configuration");
throw new StatsUnavailableException("could not connect", e);
+ } catch (SecurityException e) {
+ throw new StatsUnavailableException(e.getMessage(), e);
}
}
}
@@ -108,7 +118,7 @@
/**
* TODO: Temporary for backwards compatibility. Remove.
*/
- @RequiresPermission(Manifest.permission.DUMP)
+ @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public boolean addConfiguration(long configKey, byte[] config) {
try {
addConfig(configKey, config);
@@ -124,15 +134,17 @@
* @param configKey Configuration key to remove.
* @throws StatsUnavailableException if unsuccessful due to failing to connect to stats service
*/
- @RequiresPermission(Manifest.permission.DUMP)
+ @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public void removeConfig(long configKey) throws StatsUnavailableException {
synchronized (this) {
try {
IStatsManager service = getIStatsManagerLocked();
- service.removeConfiguration(configKey);
+ service.removeConfiguration(configKey, mContext.getOpPackageName());
} catch (RemoteException e) {
Slog.e(TAG, "Failed to connect to statsd when removing configuration");
throw new StatsUnavailableException("could not connect", e);
+ } catch (SecurityException e) {
+ throw new StatsUnavailableException(e.getMessage(), e);
}
}
}
@@ -140,7 +152,7 @@
/**
* TODO: Temporary for backwards compatibility. Remove.
*/
- @RequiresPermission(Manifest.permission.DUMP)
+ @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public boolean removeConfiguration(long configKey) {
try {
removeConfig(configKey);
@@ -179,7 +191,7 @@
* @param subscriberId ID of the subscriber, as used in the config.
* @throws StatsUnavailableException if unsuccessful due to failing to connect to stats service
*/
- @RequiresPermission(Manifest.permission.DUMP)
+ @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public void setBroadcastSubscriber(
PendingIntent pendingIntent, long configKey, long subscriberId)
throws StatsUnavailableException {
@@ -189,13 +201,17 @@
if (pendingIntent != null) {
// Extracts IIntentSender from the PendingIntent and turns it into an IBinder.
IBinder intentSender = pendingIntent.getTarget().asBinder();
- service.setBroadcastSubscriber(configKey, subscriberId, intentSender);
+ service.setBroadcastSubscriber(configKey, subscriberId, intentSender,
+ mContext.getOpPackageName());
} else {
- service.unsetBroadcastSubscriber(configKey, subscriberId);
+ service.unsetBroadcastSubscriber(configKey, subscriberId,
+ mContext.getOpPackageName());
}
} catch (RemoteException e) {
Slog.e(TAG, "Failed to connect to statsd when adding broadcast subscriber", e);
throw new StatsUnavailableException("could not connect", e);
+ } catch (SecurityException e) {
+ throw new StatsUnavailableException(e.getMessage(), e);
}
}
}
@@ -203,7 +219,7 @@
/**
* TODO: Temporary for backwards compatibility. Remove.
*/
- @RequiresPermission(Manifest.permission.DUMP)
+ @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public boolean setBroadcastSubscriber(
long configKey, long subscriberId, PendingIntent pendingIntent) {
try {
@@ -228,23 +244,26 @@
* @param configKey The integer naming the config to which this operation is attached.
* @throws StatsUnavailableException if unsuccessful due to failing to connect to stats service
*/
- @RequiresPermission(Manifest.permission.DUMP)
+ @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public void setFetchReportsOperation(PendingIntent pendingIntent, long configKey)
throws StatsUnavailableException {
synchronized (this) {
try {
IStatsManager service = getIStatsManagerLocked();
if (pendingIntent == null) {
- service.removeDataFetchOperation(configKey);
+ service.removeDataFetchOperation(configKey, mContext.getOpPackageName());
} else {
// Extracts IIntentSender from the PendingIntent and turns it into an IBinder.
IBinder intentSender = pendingIntent.getTarget().asBinder();
- service.setDataFetchOperation(configKey, intentSender);
+ service.setDataFetchOperation(configKey, intentSender,
+ mContext.getOpPackageName());
}
} catch (RemoteException e) {
Slog.e(TAG, "Failed to connect to statsd when registering data listener.");
throw new StatsUnavailableException("could not connect", e);
+ } catch (SecurityException e) {
+ throw new StatsUnavailableException(e.getMessage(), e);
}
}
}
@@ -252,7 +271,7 @@
/**
* TODO: Temporary for backwards compatibility. Remove.
*/
- @RequiresPermission(Manifest.permission.DUMP)
+ @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public boolean setDataFetchOperation(long configKey, PendingIntent pendingIntent) {
try {
setFetchReportsOperation(pendingIntent, configKey);
@@ -270,15 +289,17 @@
* @return Serialized ConfigMetricsReportList proto.
* @throws StatsUnavailableException if unsuccessful due to failing to connect to stats service
*/
- @RequiresPermission(Manifest.permission.DUMP)
+ @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public byte[] getReports(long configKey) throws StatsUnavailableException {
synchronized (this) {
try {
IStatsManager service = getIStatsManagerLocked();
- return service.getData(configKey);
+ return service.getData(configKey, mContext.getOpPackageName());
} catch (RemoteException e) {
Slog.e(TAG, "Failed to connect to statsd when getting data");
throw new StatsUnavailableException("could not connect", e);
+ } catch (SecurityException e) {
+ throw new StatsUnavailableException(e.getMessage(), e);
}
}
}
@@ -286,7 +307,7 @@
/**
* TODO: Temporary for backwards compatibility. Remove.
*/
- @RequiresPermission(Manifest.permission.DUMP)
+ @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public @Nullable byte[] getData(long configKey) {
try {
return getReports(configKey);
@@ -303,15 +324,17 @@
* @return Serialized StatsdStatsReport proto.
* @throws StatsUnavailableException if unsuccessful due to failing to connect to stats service
*/
- @RequiresPermission(Manifest.permission.DUMP)
+ @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public byte[] getStatsMetadata() throws StatsUnavailableException {
synchronized (this) {
try {
IStatsManager service = getIStatsManagerLocked();
- return service.getMetadata();
+ return service.getMetadata(mContext.getOpPackageName());
} catch (RemoteException e) {
Slog.e(TAG, "Failed to connect to statsd when getting metadata");
throw new StatsUnavailableException("could not connect", e);
+ } catch (SecurityException e) {
+ throw new StatsUnavailableException(e.getMessage(), e);
}
}
}
@@ -323,7 +346,7 @@
*
* @return Serialized StatsdStatsReport proto. Returns null on failure (eg, if statsd crashed).
*/
- @RequiresPermission(Manifest.permission.DUMP)
+ @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public @Nullable byte[] getMetadata() {
try {
return getStatsMetadata();
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 246d4a3..db011da 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -458,11 +458,11 @@
}});
registerService(Context.STATS_MANAGER, StatsManager.class,
- new StaticServiceFetcher<StatsManager>() {
- @Override
- public StatsManager createService() throws ServiceNotFoundException {
- return new StatsManager();
- }});
+ new CachedServiceFetcher<StatsManager>() {
+ @Override
+ public StatsManager createService(ContextImpl ctx) {
+ return new StatsManager(ctx.getOuterContext());
+ }});
registerService(Context.STATUS_BAR_SERVICE, StatusBarManager.class,
new CachedServiceFetcher<StatusBarManager>() {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 61aaad2..2feb459 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -4066,8 +4066,8 @@
* immediately, without user approval. It is a best practice not to request this unless strictly
* necessary since it opens up additional security vulnerabilities.
*
- * <p>Whether this key is offered to the user for approval at all or not depends on the
- * {@code isUserSelectable} parameter.
+ * <p>Include {@link #INSTALLKEY_SET_USER_SELECTABLE} in the {@code flags} argument to allow
+ * the user to select the key from a dialog.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
* {@code null} if calling from a delegated certificate installer.
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index ee667c2..1b6b5a0 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -80,8 +80,7 @@
* {@link #getBondedDevices()}; start device discovery with
* {@link #startDiscovery()}; or create a {@link BluetoothServerSocket} to
* listen for incoming RFComm connection requests with {@link
- * #listenUsingRfcommWithServiceRecord(String, UUID)}; listen for incoming L2CAP Connection-oriented
- * Channels (CoC) connection requests with listenUsingL2capCoc(int)}; or start a scan for
+ * #listenUsingRfcommWithServiceRecord(String, UUID)}; or start a scan for
* Bluetooth LE devices with {@link #startLeScan(LeScanCallback callback)}.
* </p>
* <p>This class is thread safe.</p>
diff --git a/core/java/android/bluetooth/BluetoothGattServer.java b/core/java/android/bluetooth/BluetoothGattServer.java
index 4ed2500..ef1b0bd 100644
--- a/core/java/android/bluetooth/BluetoothGattServer.java
+++ b/core/java/android/bluetooth/BluetoothGattServer.java
@@ -701,10 +701,14 @@
* <p>If the local device has already exposed services when this function
* is called, a service update notification will be sent to all clients.
*
+ * <p>The {@link BluetoothGattServerCallback#onServiceAdded} callback will indicate
+ * whether this service has been added successfully. Do not add another service
+ * before this callback.
+ *
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param service Service to be added to the list of services provided by this device.
- * @return true, if the service has been added successfully
+ * @return true, if the request to add service has been initiated
*/
public boolean addService(BluetoothGattService service) {
if (DBG) Log.d(TAG, "addService() - service: " + service.getUuid());
diff --git a/core/java/android/content/IContentService.aidl b/core/java/android/content/IContentService.aidl
index c500116..dc17666 100644
--- a/core/java/android/content/IContentService.aidl
+++ b/core/java/android/content/IContentService.aidl
@@ -183,4 +183,6 @@
void putCache(in String packageName, in Uri key, in Bundle value, int userId);
Bundle getCache(in String packageName, in Uri key, int userId);
+
+ void resetTodayStats();
}
diff --git a/core/java/android/content/SyncStatusInfo.java b/core/java/android/content/SyncStatusInfo.java
index abf9cc9..ded11cfd 100644
--- a/core/java/android/content/SyncStatusInfo.java
+++ b/core/java/android/content/SyncStatusInfo.java
@@ -21,23 +21,97 @@
import android.util.Log;
import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
/** @hide */
public class SyncStatusInfo implements Parcelable {
private static final String TAG = "Sync";
- static final int VERSION = 4;
+ static final int VERSION = 5;
private static final int MAX_EVENT_COUNT = 10;
public final int authorityId;
- public long totalElapsedTime;
- public int numSyncs;
- public int numSourcePoll;
- public int numSourceServer;
- public int numSourceLocal;
- public int numSourceUser;
- public int numSourcePeriodic;
+
+ /**
+ * # of syncs for each sync source, etc.
+ */
+ public static class Stats {
+ public long totalElapsedTime;
+ public int numSyncs;
+ public int numSourcePoll;
+ public int numSourceOther;
+ public int numSourceLocal;
+ public int numSourceUser;
+ public int numSourcePeriodic;
+ public int numSourceFeed;
+ public int numFailures;
+ public int numCancels;
+
+ /** Copy all the stats to another instance. */
+ public void copyTo(Stats to) {
+ to.totalElapsedTime = totalElapsedTime;
+ to.numSyncs = numSyncs;
+ to.numSourcePoll = numSourcePoll;
+ to.numSourceOther = numSourceOther;
+ to.numSourceLocal = numSourceLocal;
+ to.numSourceUser = numSourceUser;
+ to.numSourcePeriodic = numSourcePeriodic;
+ to.numSourceFeed = numSourceFeed;
+ to.numFailures = numFailures;
+ to.numCancels = numCancels;
+ }
+
+ /** Clear all the stats. */
+ public void clear() {
+ totalElapsedTime = 0;
+ numSyncs = 0;
+ numSourcePoll = 0;
+ numSourceOther = 0;
+ numSourceLocal = 0;
+ numSourceUser = 0;
+ numSourcePeriodic = 0;
+ numSourceFeed = 0;
+ numFailures = 0;
+ numCancels = 0;
+ }
+
+ /** Write all the stats to a parcel. */
+ public void writeToParcel(Parcel parcel) {
+ parcel.writeLong(totalElapsedTime);
+ parcel.writeInt(numSyncs);
+ parcel.writeInt(numSourcePoll);
+ parcel.writeInt(numSourceOther);
+ parcel.writeInt(numSourceLocal);
+ parcel.writeInt(numSourceUser);
+ parcel.writeInt(numSourcePeriodic);
+ parcel.writeInt(numSourceFeed);
+ parcel.writeInt(numFailures);
+ parcel.writeInt(numCancels);
+ }
+
+ /** Read all the stats from a parcel. */
+ public void readFromParcel(Parcel parcel) {
+ totalElapsedTime = parcel.readLong();
+ numSyncs = parcel.readInt();
+ numSourcePoll = parcel.readInt();
+ numSourceOther = parcel.readInt();
+ numSourceLocal = parcel.readInt();
+ numSourceUser = parcel.readInt();
+ numSourcePeriodic = parcel.readInt();
+ numSourceFeed = parcel.readInt();
+ numFailures = parcel.readInt();
+ numCancels = parcel.readInt();
+ }
+ }
+
+ public long lastTodayResetTime;
+
+ public final Stats totalStats = new Stats();
+ public final Stats todayStats = new Stats();
+ public final Stats yesterdayStats = new Stats();
+
public long lastSuccessTime;
public int lastSuccessSource;
public long lastFailureTime;
@@ -75,12 +149,15 @@
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(VERSION);
parcel.writeInt(authorityId);
- parcel.writeLong(totalElapsedTime);
- parcel.writeInt(numSyncs);
- parcel.writeInt(numSourcePoll);
- parcel.writeInt(numSourceServer);
- parcel.writeInt(numSourceLocal);
- parcel.writeInt(numSourceUser);
+
+ // Note we can't use Stats.writeToParcel() here; see the below constructor for the reason.
+ parcel.writeLong(totalStats.totalElapsedTime);
+ parcel.writeInt(totalStats.numSyncs);
+ parcel.writeInt(totalStats.numSourcePoll);
+ parcel.writeInt(totalStats.numSourceOther);
+ parcel.writeInt(totalStats.numSourceLocal);
+ parcel.writeInt(totalStats.numSourceUser);
+
parcel.writeLong(lastSuccessTime);
parcel.writeInt(lastSuccessSource);
parcel.writeLong(lastFailureTime);
@@ -102,7 +179,18 @@
parcel.writeLong(mLastEventTimes.get(i));
parcel.writeString(mLastEvents.get(i));
}
- parcel.writeInt(numSourcePeriodic);
+ // Version 4
+ parcel.writeInt(totalStats.numSourcePeriodic);
+
+ // Version 5
+ parcel.writeInt(totalStats.numSourceFeed);
+ parcel.writeInt(totalStats.numFailures);
+ parcel.writeInt(totalStats.numCancels);
+
+ parcel.writeLong(lastTodayResetTime);
+
+ todayStats.writeToParcel(parcel);
+ yesterdayStats.writeToParcel(parcel);
}
public SyncStatusInfo(Parcel parcel) {
@@ -111,12 +199,15 @@
Log.w("SyncStatusInfo", "Unknown version: " + version);
}
authorityId = parcel.readInt();
- totalElapsedTime = parcel.readLong();
- numSyncs = parcel.readInt();
- numSourcePoll = parcel.readInt();
- numSourceServer = parcel.readInt();
- numSourceLocal = parcel.readInt();
- numSourceUser = parcel.readInt();
+
+ // Note we can't use Stats.writeToParcel() here because the data is persisted and we need
+ // to be able to read from the old format too.
+ totalStats.totalElapsedTime = parcel.readLong();
+ totalStats.numSyncs = parcel.readInt();
+ totalStats.numSourcePoll = parcel.readInt();
+ totalStats.numSourceOther = parcel.readInt();
+ totalStats.numSourceLocal = parcel.readInt();
+ totalStats.numSourceUser = parcel.readInt();
lastSuccessTime = parcel.readLong();
lastSuccessSource = parcel.readInt();
lastFailureTime = parcel.readLong();
@@ -149,25 +240,37 @@
}
if (version < 4) {
// Before version 4, numSourcePeriodic wasn't persisted.
- numSourcePeriodic = numSyncs - numSourceLocal - numSourcePoll - numSourceServer
- - numSourceUser;
- if (numSourcePeriodic < 0) { // Sanity check.
- numSourcePeriodic = 0;
+ totalStats.numSourcePeriodic =
+ totalStats.numSyncs - totalStats.numSourceLocal - totalStats.numSourcePoll
+ - totalStats.numSourceOther
+ - totalStats.numSourceUser;
+ if (totalStats.numSourcePeriodic < 0) { // Sanity check.
+ totalStats.numSourcePeriodic = 0;
}
} else {
- numSourcePeriodic = parcel.readInt();
+ totalStats.numSourcePeriodic = parcel.readInt();
+ }
+ if (version >= 5) {
+ totalStats.numSourceFeed = parcel.readInt();
+ totalStats.numFailures = parcel.readInt();
+ totalStats.numCancels = parcel.readInt();
+
+ lastTodayResetTime = parcel.readLong();
+
+ todayStats.readFromParcel(parcel);
+ yesterdayStats.readFromParcel(parcel);
}
}
public SyncStatusInfo(SyncStatusInfo other) {
authorityId = other.authorityId;
- totalElapsedTime = other.totalElapsedTime;
- numSyncs = other.numSyncs;
- numSourcePoll = other.numSourcePoll;
- numSourceServer = other.numSourceServer;
- numSourceLocal = other.numSourceLocal;
- numSourceUser = other.numSourceUser;
- numSourcePeriodic = other.numSourcePeriodic;
+
+ other.totalStats.copyTo(totalStats);
+ other.todayStats.copyTo(todayStats);
+ other.yesterdayStats.copyTo(yesterdayStats);
+
+ lastTodayResetTime = other.lastTodayResetTime;
+
lastSuccessTime = other.lastSuccessTime;
lastSuccessSource = other.lastSuccessSource;
lastFailureTime = other.lastFailureTime;
@@ -251,4 +354,41 @@
}
}
}
+
+ /**
+ * If the last reset was not not today, move today's stats to yesterday's and clear today's.
+ */
+ public void maybeResetTodayStats(boolean clockValid, boolean force) {
+ final long now = System.currentTimeMillis();
+
+ if (!force) {
+ // Last reset was the same day, nothing to do.
+ if (areSameDates(now, lastTodayResetTime)) {
+ return;
+ }
+
+ // Hack -- on devices with no RTC, until the NTP kicks in, the device won't have the
+ // correct time. So if the time goes back, don't reset, unless we're sure the current
+ // time is correct.
+ if (now < lastTodayResetTime && !clockValid) {
+ return;
+ }
+ }
+
+ lastTodayResetTime = now;
+
+ todayStats.copyTo(yesterdayStats);
+ todayStats.clear();
+ }
+
+ private static boolean areSameDates(long time1, long time2) {
+ final Calendar c1 = new GregorianCalendar();
+ final Calendar c2 = new GregorianCalendar();
+
+ c1.setTimeInMillis(time1);
+ c2.setTimeInMillis(time2);
+
+ return c1.get(Calendar.YEAR) == c2.get(Calendar.YEAR)
+ && c1.get(Calendar.DAY_OF_YEAR) == c2.get(Calendar.DAY_OF_YEAR);
+ }
}
\ No newline at end of file
diff --git a/core/java/android/content/pm/InstrumentationInfo.java b/core/java/android/content/pm/InstrumentationInfo.java
index 3faa951..fb2e4a04 100644
--- a/core/java/android/content/pm/InstrumentationInfo.java
+++ b/core/java/android/content/pm/InstrumentationInfo.java
@@ -101,6 +101,12 @@
/** {@hide} */
public String credentialProtectedDataDir;
+ /** {@hide} */
+ public String primaryCpuAbi;
+
+ /** {@hide} */
+ public String secondaryCpuAbi;
+
/** {@hide} Full path to the directory containing primary ABI native libraries. */
public String nativeLibraryDir;
@@ -131,6 +137,8 @@
dataDir = orig.dataDir;
deviceProtectedDataDir = orig.deviceProtectedDataDir;
credentialProtectedDataDir = orig.credentialProtectedDataDir;
+ primaryCpuAbi = orig.primaryCpuAbi;
+ secondaryCpuAbi = orig.secondaryCpuAbi;
nativeLibraryDir = orig.nativeLibraryDir;
secondaryNativeLibraryDir = orig.secondaryNativeLibraryDir;
handleProfiling = orig.handleProfiling;
@@ -160,6 +168,8 @@
dest.writeString(dataDir);
dest.writeString(deviceProtectedDataDir);
dest.writeString(credentialProtectedDataDir);
+ dest.writeString(primaryCpuAbi);
+ dest.writeString(secondaryCpuAbi);
dest.writeString(nativeLibraryDir);
dest.writeString(secondaryNativeLibraryDir);
dest.writeInt((handleProfiling == false) ? 0 : 1);
@@ -190,6 +200,8 @@
dataDir = source.readString();
deviceProtectedDataDir = source.readString();
credentialProtectedDataDir = source.readString();
+ primaryCpuAbi = source.readString();
+ secondaryCpuAbi = source.readString();
nativeLibraryDir = source.readString();
secondaryNativeLibraryDir = source.readString();
handleProfiling = source.readInt() != 0;
@@ -208,6 +220,8 @@
ai.dataDir = dataDir;
ai.deviceProtectedDataDir = deviceProtectedDataDir;
ai.credentialProtectedDataDir = credentialProtectedDataDir;
+ ai.primaryCpuAbi = primaryCpuAbi;
+ ai.secondaryCpuAbi = secondaryCpuAbi;
ai.nativeLibraryDir = nativeLibraryDir;
ai.secondaryNativeLibraryDir = secondaryNativeLibraryDir;
}
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 1a5d3ac..262de15 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -864,7 +864,7 @@
/**
* <p>The camera device is a monochrome camera that doesn't contain a color filter array,
- * and the pixel values on U and Y planes are all 128.</p>
+ * and the pixel values on U and V planes are all 128.</p>
* @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
*/
public static final int REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME = 12;
diff --git a/core/java/android/os/IPermissionController.aidl b/core/java/android/os/IPermissionController.aidl
index 3de953a..dd11d49 100644
--- a/core/java/android/os/IPermissionController.aidl
+++ b/core/java/android/os/IPermissionController.aidl
@@ -20,6 +20,7 @@
/** @hide */
interface IPermissionController {
boolean checkPermission(String permission, int pid, int uid);
+ int noteOp(String op, int uid, String packageName);
String[] getPackagesForUid(int uid);
boolean isRuntimePermission(String permission);
int getPackageUid(String packageName, int flags);
diff --git a/core/java/android/os/IStatsManager.aidl b/core/java/android/os/IStatsManager.aidl
index 3b32c52..6b3b93a 100644
--- a/core/java/android/os/IStatsManager.aidl
+++ b/core/java/android/os/IStatsManager.aidl
@@ -80,14 +80,14 @@
*
* Requires Manifest.permission.DUMP.
*/
- byte[] getData(in long key);
+ byte[] getData(in long key, in String packageName);
/**
* Fetches metadata across statsd. Returns byte array representing wire-encoded proto.
*
* Requires Manifest.permission.DUMP.
*/
- byte[] getMetadata();
+ byte[] getMetadata(in String packageName);
/**
* Sets a configuration with the specified config key and subscribes to updates for this
@@ -97,7 +97,7 @@
*
* Requires Manifest.permission.DUMP.
*/
- void addConfiguration(in long configKey, in byte[] config);
+ void addConfiguration(in long configKey, in byte[] config, in String packageName);
/**
* Registers the given pending intent for this config key. This intent is invoked when the
@@ -106,14 +106,14 @@
*
* Requires Manifest.permission.DUMP.
*/
- void setDataFetchOperation(long configKey, in IBinder intentSender);
+ void setDataFetchOperation(long configKey, in IBinder intentSender, in String packageName);
/**
* Removes the data fetch operation for the specified configuration.
*
* Requires Manifest.permission.DUMP.
*/
- void removeDataFetchOperation(long configKey);
+ void removeDataFetchOperation(long configKey, in String packageName);
/**
* Removes the configuration with the matching config key. No-op if this config key does not
@@ -121,7 +121,7 @@
*
* Requires Manifest.permission.DUMP.
*/
- void removeConfiguration(in long configKey);
+ void removeConfiguration(in long configKey, in String packageName);
/**
* Set the IIntentSender (i.e. PendingIntent) to be used when broadcasting subscriber
@@ -141,7 +141,8 @@
*
* Requires Manifest.permission.DUMP.
*/
- void setBroadcastSubscriber(long configKey, long subscriberId, in IBinder intentSender);
+ void setBroadcastSubscriber(long configKey, long subscriberId, in IBinder intentSender,
+ in String packageName);
/**
* Undoes setBroadcastSubscriber() for the (configKey, subscriberId) pair.
@@ -150,5 +151,5 @@
*
* Requires Manifest.permission.DUMP.
*/
- void unsetBroadcastSubscriber(long configKey, long subscriberId);
+ void unsetBroadcastSubscriber(long configKey, long subscriberId, in String packageName);
}
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index c00100b..9c25848 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -21,6 +21,7 @@
import android.annotation.SdkConstant;
import android.annotation.SystemApi;
import android.annotation.SystemService;
+import android.annotation.TestApi;
import android.content.Context;
import android.util.Log;
import android.util.proto.ProtoOutputStream;
@@ -960,6 +961,7 @@
*
* @hide Requires signature permission.
*/
+ @TestApi
public void nap(long time) {
try {
mService.nap(time);
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 3f58afa..5b4b5f2 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -877,8 +877,12 @@
SurfaceComposerClient::getHdrCapabilities(token, &capabilities);
const auto& types = capabilities.getSupportedHdrTypes();
+ std::vector<int32_t> intTypes;
+ for (auto type : types) {
+ intTypes.push_back(static_cast<int32_t>(type));
+ }
auto typesArray = env->NewIntArray(types.size());
- env->SetIntArrayRegion(typesArray, 0, types.size(), types.data());
+ env->SetIntArrayRegion(typesArray, 0, intTypes.size(), intTypes.data());
return env->NewObject(gHdrCapabilitiesClassInfo.clazz, gHdrCapabilitiesClassInfo.ctor,
typesArray, capabilities.getDesiredMaxLuminance(),
diff --git a/core/proto/android/os/enums.proto b/core/proto/android/os/enums.proto
index aa99ac7..db4a4c4 100644
--- a/core/proto/android/os/enums.proto
+++ b/core/proto/android/os/enums.proto
@@ -60,7 +60,7 @@
// They are primarily used by android/os/HardwarePropertiesManager.java.
// Any change to the types in the thermal hal should be made here as well.
enum TemperatureTypeEnum {
- TEMPERATURE_TYPE_UKNOWN = -1;
+ TEMPERATURE_TYPE_UNKNOWN = -1;
TEMPERATURE_TYPE_CPU = 0;
TEMPERATURE_TYPE_GPU = 1;
TEMPERATURE_TYPE_BATTERY = 2;
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 3571967..395b269 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4609,7 +4609,7 @@
<string name="zen_mode_default_every_night_name">Sleeping</string>
<!-- Indication that the current volume and other effects (vibration) are being suppressed by a third party, such as a notification listener. [CHAR LIMIT=30] -->
- <string name="muted_by">Muted by <xliff:g id="third_party">%1$s</xliff:g></string>
+ <string name="muted_by"><xliff:g id="third_party">%1$s</xliff:g> is muting some sounds</string>
<!-- Error message shown when there is a system error which can be solved by user performing factory reset. [CHAR LIMIT=NONE] -->
<string name="system_error_wipe_data">There\'s an internal problem with your device, and it may be unstable until you factory data reset.</string>
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index ed29028..bde4943 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -175,6 +175,7 @@
<assign-permission name="android.permission.DUMP" uid="statsd" />
<assign-permission name="android.permission.PACKAGE_USAGE_STATS" uid="statsd" />
<assign-permission name="android.permission.STATSCOMPANION" uid="statsd" />
+ <assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="statsd" />
<!-- This is a list of all the libraries available for application
code to link against. -->
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index c1aa2dc..cfcecbc 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -576,18 +576,18 @@
<item>0</item> <item>334</item>
</array>
<array name="batterymeter_plus_points">
- <item>3</item><item>0</item>
<item>5</item><item>0</item>
- <item>5</item><item>3</item>
- <item>8</item><item>3</item>
- <item>8</item><item>5</item>
- <item>5</item><item>5</item>
- <item>5</item><item>8</item>
- <item>3</item><item>8</item>
- <item>3</item><item>5</item>
+ <item>11</item><item>0</item>
+ <item>11</item><item>5</item>
+ <item>16</item><item>5</item>
+ <item>16</item><item>11</item>
+ <item>11</item><item>11</item>
+ <item>11</item><item>16</item>
+ <item>5</item><item>16</item>
+ <item>5</item><item>11</item>
+ <item>0</item><item>11</item>
<item>0</item><item>5</item>
- <item>0</item><item>3</item>
- <item>3</item><item>3</item>
+ <item>5</item><item>5</item>
</array>
</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java b/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
index e2f279a9..343191d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
+++ b/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
@@ -393,16 +393,10 @@
mPlusFrame.top + mPlusPoints[1] * mPlusFrame.height());
}
- float fillPct = (mPlusFrame.bottom - levelTop) / (mPlusFrame.bottom - mPlusFrame.top);
- fillPct = Math.min(Math.max(fillPct, 0), 1);
- if (fillPct <= BOLT_LEVEL_THRESHOLD) {
- // draw the plus if opaque
+ // Always cut out of the whole shape, and sometimes filled colorError
+ mShapePath.op(mPlusPath, Path.Op.DIFFERENCE);
+ if (mPowerSaveAsColorError) {
c.drawPath(mPlusPath, mPlusPaint);
- } else {
- mShapePath.op(mPlusPath, Path.Op.DIFFERENCE);
- if (mPowerSaveAsColorError) {
- c.drawPath(mPlusPath, mPlusPaint);
- }
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java b/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java
index de29030..a53ff39 100644
--- a/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java
+++ b/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java
@@ -24,11 +24,10 @@
import android.icu.util.MeasureUnit;
import android.support.annotation.Nullable;
import android.text.TextUtils;
-import com.android.internal.annotations.VisibleForTesting;
+
import com.android.settingslib.R;
-import java.time.Clock;
+
import java.time.Instant;
-import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
@@ -102,7 +101,7 @@
private static String getMoreThanOneDayString(Context context, long drainTimeMs,
String percentageString, boolean basedOnUsage) {
- final long roundedTimeMs = roundToNearestThreshold(drainTimeMs, ONE_HOUR_MILLIS);
+ final long roundedTimeMs = roundTimeToNearestThreshold(drainTimeMs, ONE_HOUR_MILLIS);
CharSequence timeString = StringUtil.formatElapsedTime(context,
roundedTimeMs,
false /* withSeconds */);
@@ -139,7 +138,7 @@
String percentageString, boolean basedOnUsage) {
// Get the time of day we think device will die rounded to the nearest 15 min.
final long roundedTimeOfDayMs =
- roundToNearestThreshold(
+ roundTimeToNearestThreshold(
System.currentTimeMillis() + drainTimeMs,
FIFTEEN_MINUTES_MILLIS);
@@ -170,12 +169,24 @@
return timeMs * 1000;
}
- private static long roundToNearestThreshold(long drainTime, long threshold) {
- final long remainder = drainTime % threshold;
- if (remainder < threshold / 2) {
- return drainTime - remainder;
+ /**
+ * Rounds a time to the nearest multiple of the provided threshold. Note: This function takes
+ * the absolute value of the inputs since it is only meant to be used for times, not general
+ * purpose rounding.
+ *
+ * ex: roundTimeToNearestThreshold(41, 24) = 48
+ * @param drainTime The amount to round
+ * @param threshold The value to round to a multiple of
+ * @return The rounded value as a long
+ */
+ public static long roundTimeToNearestThreshold(long drainTime, long threshold) {
+ long time = Math.abs(drainTime);
+ long multiple = Math.abs(threshold);
+ final long remainder = time % multiple;
+ if (remainder < multiple / 2) {
+ return time - remainder;
} else {
- return drainTime - remainder + threshold;
+ return time - remainder + multiple;
}
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java
index dfd48cc..f2ef99c 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java
@@ -175,4 +175,18 @@
// Add percentage to string when provided
assertThat(info2).isEqualTo("More than 2 days remaining (10%)");
}
+
+ @Test
+ public void testRoundToNearestThreshold_roundsCorrectly() {
+ // test some pretty normal values
+ assertThat(PowerUtil.roundTimeToNearestThreshold(1200, 1000)).isEqualTo(1000);
+ assertThat(PowerUtil.roundTimeToNearestThreshold(800, 1000)).isEqualTo(1000);
+ assertThat(PowerUtil.roundTimeToNearestThreshold(1000, 1000)).isEqualTo(1000);
+
+ // test the weird stuff
+ assertThat(PowerUtil.roundTimeToNearestThreshold(80, -200)).isEqualTo(0);
+ assertThat(PowerUtil.roundTimeToNearestThreshold(-150, 100)).isEqualTo(200);
+ assertThat(PowerUtil.roundTimeToNearestThreshold(-120, 100)).isEqualTo(100);
+ assertThat(PowerUtil.roundTimeToNearestThreshold(-200, -75)).isEqualTo(225);
+ }
}
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 8b78366..28e8db9 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -83,7 +83,7 @@
<string name="def_charging_started_sound" translatable="false">/system/media/audio/ui/ChargingStarted.ogg</string>
<!-- sound trigger detection service default values -->
- <integer name="def_max_sound_trigger_detection_service_ops_per_day" translatable="false">200</integer>
+ <integer name="def_max_sound_trigger_detection_service_ops_per_day" translatable="false">1000</integer>
<integer name="def_sound_trigger_detection_service_op_timeout" translatable="false">15000</integer>
<bool name="def_lockscreen_disabled">false</bool>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 022e306..1d3e521 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -2935,7 +2935,7 @@
}
private final class UpgradeController {
- private static final int SETTINGS_VERSION = 163;
+ private static final int SETTINGS_VERSION = 164;
private final int mUserId;
@@ -3724,6 +3724,24 @@
currentVersion = 163;
}
+ if (currentVersion == 163) {
+ // Version 163: Update default value of
+ // MAX_SOUND_TRIGGER_DETECTION_SERVICE_OPS_PER_DAY from old to new default
+ final SettingsState settings = getGlobalSettingsLocked();
+ final Setting currentSetting = settings.getSettingLocked(
+ Global.MAX_SOUND_TRIGGER_DETECTION_SERVICE_OPS_PER_DAY);
+ if (currentSetting.isDefaultFromSystem()) {
+ settings.insertSettingLocked(
+ Settings.Global.MAX_SOUND_TRIGGER_DETECTION_SERVICE_OPS_PER_DAY,
+ Integer.toString(getContext().getResources().getInteger(
+ R.integer
+ .def_max_sound_trigger_detection_service_ops_per_day)),
+ null, true, SettingsState.SYSTEM_PACKAGE_NAME);
+ }
+
+ currentVersion = 164;
+ }
+
// vXXX: Add new settings above this point.
if (currentVersion != newVersion) {
diff --git a/packages/SystemUI/res/drawable/car_progress_bar.xml b/packages/SystemUI/res/drawable/car_progress_bar.xml
deleted file mode 100644
index 742fca7..0000000
--- a/packages/SystemUI/res/drawable/car_progress_bar.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<!--
- Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License
--->
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:id="@android:id/background">
- <shape>
- <solid android:color="@color/car_user_switcher_progress_bgcolor" />
- </shape>
- </item>
-
- <item android:id="@android:id/progress">
- <clip>
- <shape>
- <solid android:color="@color/car_user_switcher_progress_fgcolor" />
- </shape>
- </clip>
- </item>
-</layer-list>
diff --git a/packages/SystemUI/res/drawable/car_round_button.xml b/packages/SystemUI/res/drawable/car_round_button.xml
deleted file mode 100644
index 5f4deb3..0000000
--- a/packages/SystemUI/res/drawable/car_round_button.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<!--
- Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License
--->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
-
- <solid android:color="@color/car_start_driving_background" />
- <corners android:radius="@dimen/car_start_driving_corner_radius" />
-</shape>
diff --git a/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml b/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml
index c59b067..3242165 100644
--- a/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml
+++ b/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml
@@ -22,14 +22,13 @@
android:alpha="0"
android:layout_height="wrap_content"
android:layout_width="match_parent"
- android:gravity="fill_horizontal"
- android:layout_marginTop="@dimen/car_padding_5"
- android:layout_marginStart="@dimen/car_padding_4">
+ android:gravity="fill_horizontal">
<ImageView android:id="@+id/user_avatar"
android:layout_centerHorizontal="true"
android:layout_width="@dimen/car_fullscreen_user_pod_image_avatar_width"
android:layout_height="@dimen/car_fullscreen_user_pod_image_avatar_height"
+ android:background="@drawable/car_button_ripple_background_inverse"
/>
<TextView android:id="@+id/user_name"
diff --git a/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml b/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml
index 27d0e46..d8b52fc 100644
--- a/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml
+++ b/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml
@@ -15,6 +15,7 @@
limitations under the License.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
android:fitsSystemWindows="true"
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -31,34 +32,19 @@
android:theme="@android:style/Theme"
android:layout_alignParentTop="true"/>
- <RelativeLayout
- android:id="@+id/fullscreen_user_switcher_container"
- android:layout_width="match_parent"
+ <!-- TODO: add app:verticallyCenterListContent="true" when car support lib is updated -->
+ <com.android.systemui.statusbar.car.UserGridRecyclerView
+ android:id="@+id/user_grid"
+ android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:layout_marginStart="@dimen/car_margin"
- android:layout_marginEnd="@dimen/car_margin">
-
- <RelativeLayout
- android:id="@+id/fullscreen_user_switcher_container_inner"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/car_padding_4">
-
- <com.android.systemui.statusbar.car.UserGridRecyclerView
- android:id="@+id/user_grid"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@+id/header"
- android:scrollbars="vertical"
- android:scrollbarFadeDuration="0"
- android:verticalScrollbarPosition="left"
- android:layout_centerHorizontal="true"
- android:layout_centerVertical="true"
- android:layout_alignParentRight="true"/>
-
- </RelativeLayout>
-
- </RelativeLayout>
+ android:layout_below="@+id/header"
+ android:layout_centerHorizontal="true"
+ android:layout_centerVertical="true"
+ android:layout_alignParentRight="true"
+ app:dayNightStyle="force_night"
+ app:showPagedListViewDivider="false"
+ app:gutter="both"
+ app:itemSpacing="@dimen/car_padding_5"/>
</RelativeLayout>
</FrameLayout>
diff --git a/packages/SystemUI/res/layout/car_qs_panel.xml b/packages/SystemUI/res/layout/car_qs_panel.xml
index c01bbce..9c2b95b 100644
--- a/packages/SystemUI/res/layout/car_qs_panel.xml
+++ b/packages/SystemUI/res/layout/car_qs_panel.xml
@@ -29,6 +29,7 @@
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/user_switcher_container"
android:layout_marginStart="@dimen/car_margin"
android:layout_marginEnd="@dimen/car_margin"
@@ -36,23 +37,17 @@
android:layout_width="match_parent"
android:layout_height="@dimen/car_user_switcher_container_height">
- <RelativeLayout
- android:id="@+id/fullscreen_user_switcher_container_inner"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/car_padding_4">
-
- <com.android.systemui.statusbar.car.UserGridRecyclerView
- android:id="@+id/user_grid"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:scrollbars="vertical"
- android:verticalScrollbarPosition="left"
- android:layout_centerHorizontal="true"
- android:layout_centerVertical="true"
- android:layout_alignParentRight="true"
- android:scrollbarFadeDuration="0"/>
- </RelativeLayout>
+ <com.android.systemui.statusbar.car.UserGridRecyclerView
+ android:id="@+id/user_grid"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:layout_centerVertical="true"
+ android:layout_alignParentRight="true"
+ app:dayNightStyle="force_night"
+ app:showPagedListViewDivider="false"
+ app:gutter="both"
+ app:itemSpacing="@dimen/car_padding_4"/>
</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/qs_footer_impl.xml b/packages/SystemUI/res/layout/qs_footer_impl.xml
index f424171..f554150 100644
--- a/packages/SystemUI/res/layout/qs_footer_impl.xml
+++ b/packages/SystemUI/res/layout/qs_footer_impl.xml
@@ -38,35 +38,49 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_marginStart="16dp"
android:layout_gravity="center_vertical"
android:gravity="end" >
- <include
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical|start"
- android:layout_marginEnd="8dp"
- android:visibility="gone"
- layout="@layout/mobile_signal_group" />
-
- <com.android.keyguard.CarrierText
- android:id="@+id/qs_carrier_text"
+ <LinearLayout
android:layout_width="0dp"
- android:layout_height="wrap_content"
+ android:layout_height="match_parent"
android:layout_weight="1"
- android:layout_gravity="center_vertical|start"
- android:layout_marginEnd="32dp"
- android:ellipsize="marquee"
- android:textAppearance="@style/TextAppearance.QS.TileLabel"
- android:textColor="?android:attr/textColorPrimary"
- android:textDirection="locale"
- android:singleLine="true" />
+ android:gravity="center_vertical|start"
+ android:paddingStart="16dp">
+
+ <include
+ layout="@layout/mobile_signal_group"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="8dp"
+ android:visibility="gone" />
+
+ <com.android.keyguard.CarrierText
+ android:id="@+id/qs_carrier_text"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_marginEnd="32dp"
+ android:ellipsize="marquee"
+ android:textAppearance="@style/TextAppearance.QS.TileLabel"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textDirection="locale"
+ android:singleLine="true" />
+
+ </LinearLayout>
+
+ <com.android.systemui.qs.PageIndicator
+ android:id="@+id/footer_page_indicator"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="center_vertical"
+ android:visibility="gone" />
<com.android.keyguard.AlphaOptimizedLinearLayout
android:id="@+id/qs_footer_actions_container"
- android:layout_width="wrap_content"
+ android:layout_width="@integer/qs_footer_actions_width"
android:layout_height="match_parent"
+ android:layout_weight="@integer/qs_footer_actions_weight"
android:gravity="center_vertical|end" >
<com.android.systemui.statusbar.phone.MultiUserSwitch
android:id="@+id/multi_user_switch"
diff --git a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
index 00427cb..e96a09b 100644
--- a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
+++ b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
@@ -19,9 +19,9 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingBottom="24dp"
android:clipChildren="false"
- android:clipToPadding="false">
+ android:clipToPadding="false"
+ android:paddingBottom="@dimen/qs_paged_tile_layout_padding_bottom">
<FrameLayout
android:id="@+id/page_decor"
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index c59492f..b81d363 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -35,4 +35,5 @@
<integer name="quick_settings_num_columns">4</integer>
<bool name="quick_settings_wide">true</bool>
<dimen name="qs_detail_margin_top">0dp</dimen>
+ <dimen name="qs_paged_tile_layout_padding_bottom">0dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-land/integers.xml b/packages/SystemUI/res/values-land/integers.xml
new file mode 100644
index 0000000..fb22665
--- /dev/null
+++ b/packages/SystemUI/res/values-land/integers.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<resources>
+ <!-- Action footer width is set to 0 to allow it to stretch (through a weight of 1) and center
+ the page indicator in between the footer and the carrier text.-->
+ <integer name="qs_footer_actions_width">0</integer>
+ <integer name="qs_footer_actions_weight">1</integer>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 1e55eb3..b220091 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -382,6 +382,7 @@
<dimen name="qs_footer_padding_start">16dp</dimen>
<dimen name="qs_footer_padding_end">16dp</dimen>
<dimen name="qs_footer_icon_size">16dp</dimen>
+ <dimen name="qs_paged_tile_layout_padding_bottom">24dp</dimen>
<dimen name="qs_notif_collapsed_space">64dp</dimen>
diff --git a/packages/SystemUI/res/values/dimens_car.xml b/packages/SystemUI/res/values/dimens_car.xml
index 0cd3825..6bc8e26 100644
--- a/packages/SystemUI/res/values/dimens_car.xml
+++ b/packages/SystemUI/res/values/dimens_car.xml
@@ -16,9 +16,6 @@
*/
-->
<resources>
- <dimen name="car_margin">148dp</dimen>
- <dimen name="car_margin_standard">112dp</dimen>
-
<!-- TODO replace with car support lib sizes when available -->
<dimen name="car_fullscreen_user_pod_icon_text_size">64sp</dimen>
<dimen name="car_fullscreen_user_pod_width">243dp</dimen>
@@ -31,14 +28,6 @@
<dimen name="car_left_navigation_bar_width">96dp</dimen>
<dimen name="car_right_navigation_bar_width">96dp</dimen>
- <dimen name="car_page_indicator_dot_diameter">12dp</dimen>
- <dimen name="car_page_indicator_margin_bottom">24dp</dimen>
-
- <dimen name="car_start_driving_corner_radius">16dp</dimen>
- <dimen name="car_start_driving_padding_side">30dp</dimen>
- <dimen name="car_start_driving_height">80dp</dimen>
- <dimen name="car_start_driving_text_size">@dimen/car_body2_size</dimen>
-
<dimen name="car_qs_footer_height">112dp</dimen>
<dimen name="car_qs_footer_padding_bottom">16dp</dimen>
<dimen name="car_qs_footer_padding_top">16dp</dimen>
diff --git a/packages/SystemUI/res/values/integers.xml b/packages/SystemUI/res/values/integers.xml
index 8f23283..87c4bbb 100644
--- a/packages/SystemUI/res/values/integers.xml
+++ b/packages/SystemUI/res/values/integers.xml
@@ -16,4 +16,9 @@
-->
<resources>
<integer name="fingerprint_dialog_text_gravity">8388611</integer> <!-- gravity start -->
+
+ <!-- Action footer width used for layout_width to indicate WRAP_CONTENT (along with a weight of
+ 0) as we can allow the carrier text to stretch as far as needed in the QS footer. -->
+ <integer name="qs_footer_actions_width">-2</integer>
+ <integer name="qs_footer_actions_weight">0</integer>
</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index a4ea5e8..090d012 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -240,6 +240,8 @@
<string name="accessibility_waiting_for_fingerprint">Waiting for fingerprint</string>
<!-- Accessibility action of the unlock button when fingerpint is on (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_unlock_without_fingerprint">Unlock without using your fingerprint</string>
+ <!-- Click action label for accessibility for the smart reply buttons (not shown on-screen).". [CHAR LIMIT=NONE] -->
+ <string name="accessibility_send_smart_reply">Send</string>
<!-- Click action label for accessibility for the unlock button. [CHAR LIMIT=NONE] -->
<string name="unlock_label">unlock</string>
<!-- Click action label for accessibility for the phone button. [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/res/values/styles_car.xml b/packages/SystemUI/res/values/styles_car.xml
deleted file mode 100644
index 2aaef86..0000000
--- a/packages/SystemUI/res/values/styles_car.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (c) 2017, The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <style name="CarUserSwitcher.StartDrivingButton" parent="@android:style/Widget.Material.Button">
- <item name="android:background">@drawable/car_round_button</item>
- <item name="android:textSize">@dimen/car_start_driving_text_size</item>
- <item name="android:textColor">@color/car_start_driving_text</item>
- <item name="android:paddingLeft">@dimen/car_start_driving_padding_side</item>
- <item name="android:paddingRight">@dimen/car_start_driving_padding_side</item>
- </style>
-</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java b/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java
index 2629f30..aa2f8d1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java
@@ -45,7 +45,7 @@
}
public void setNumPages(int numPages) {
- setVisibility(numPages > 1 ? View.VISIBLE : View.INVISIBLE);
+ setVisibility(numPages > 1 ? View.VISIBLE : View.GONE);
if (mAnimating) {
Log.w(TAG, "setNumPages during animation");
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index c548cf6..d8d07c0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -46,6 +46,7 @@
private final ArrayList<TilePage> mPages = new ArrayList<>();
private PageIndicator mPageIndicator;
+ private float mPageIndicatorPosition;
private int mNumPages;
private PageListener mPageListener;
@@ -145,6 +146,8 @@
public void setPageIndicator(PageIndicator indicator) {
mPageIndicator = indicator;
+ mPageIndicator.setNumPages(mNumPages);
+ mPageIndicator.setLocation(mPageIndicatorPosition);
}
@Override
@@ -212,7 +215,6 @@
}
if (DEBUG) Log.d(TAG, "Size: " + mNumPages);
mPageIndicator.setNumPages(mNumPages);
- mPageIndicator.setVisibility(mNumPages > 1 ? View.VISIBLE : View.GONE);
setAdapter(mAdapter);
mAdapter.notifyDataSetChanged();
setCurrentItem(0, false);
@@ -221,6 +223,12 @@
@Override
public boolean updateResources() {
+ // Update bottom padding, useful for removing extra space once the panel page indicator is
+ // hidden.
+ setPadding(0, 0, 0,
+ getContext().getResources().getDimensionPixelSize(
+ R.dimen.qs_paged_tile_layout_padding_bottom));
+
boolean changed = false;
for (int i = 0; i < mPages.size(); i++) {
changed |= mPages.get(i).updateResources();
@@ -326,7 +334,8 @@
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels) {
if (mPageIndicator == null) return;
- mPageIndicator.setLocation(position + positionOffset);
+ mPageIndicatorPosition = position + positionOffset;
+ mPageIndicator.setLocation(mPageIndicatorPosition);
if (mPageListener != null) {
mPageListener.onPageChanged(positionOffsetPixels == 0 &&
(isLayoutRtl() ? position == mPages.size() - 1 : position == 0));
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index 28dd26f..abe819b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -17,6 +17,7 @@
package com.android.systemui.qs;
import static android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import android.content.Context;
import android.content.Intent;
@@ -35,6 +36,7 @@
import android.view.View.OnClickListener;
import android.widget.FrameLayout;
import android.widget.ImageView;
+import android.widget.LinearLayout;
import android.widget.Toast;
import com.android.internal.logging.MetricsLogger;
@@ -66,6 +68,7 @@
private UserInfoController mUserInfoController;
private SettingsButton mSettingsButton;
protected View mSettingsContainer;
+ private PageIndicator mPageIndicator;
private CarrierText mCarrierText;
private boolean mQsDisabled;
@@ -108,6 +111,8 @@
Dependency.get(ActivityStarter.class).postQSRunnableDismissingKeyguard(() ->
mQsPanel.showEdit(view)));
+ mPageIndicator = findViewById(R.id.footer_page_indicator);
+
mSettingsButton = findViewById(R.id.settings_button);
mSettingsContainer = findViewById(R.id.settings_button_container);
mSettingsButton.setOnClickListener(this);
@@ -167,6 +172,14 @@
private void updateResources() {
updateFooterAnimator();
+
+ // Update the width and weight of the actions container as the page indicator can sometimes
+ // show and the layout needs to center it between the carrier text and actions container.
+ LinearLayout.LayoutParams params =
+ (LinearLayout.LayoutParams) mActionsContainer.getLayoutParams();
+ params.width = mContext.getResources().getInteger(R.integer.qs_footer_actions_width);
+ params.weight = mContext.getResources().getInteger(R.integer.qs_footer_actions_weight);
+ mActionsContainer.setLayoutParams(params);
}
private void updateFooterAnimator() {
@@ -181,6 +194,7 @@
.addFloat(mMobileGroup, "alpha", 0, 1)
.addFloat(mActionsContainer, "alpha", 0, 1)
.addFloat(mDragHandle, "alpha", 1, 0, 0)
+ .addFloat(mPageIndicator, "alpha", 0, 1)
.setStartDelay(0.15f)
.build();
}
@@ -291,6 +305,7 @@
mQsPanel = qsPanel;
if (mQsPanel != null) {
mMultiUserSwitch.setQsPanel(qsPanel);
+ mQsPanel.setFooterPageIndicator(mPageIndicator);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 3e1eed5..0876a5d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -16,6 +16,7 @@
package com.android.systemui.qs;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static com.android.systemui.qs.tileimpl.QSTileImpl.getColorForState;
import android.annotation.Nullable;
@@ -63,7 +64,6 @@
protected final ArrayList<TileRecord> mRecords = new ArrayList<>();
protected final View mBrightnessView;
private final H mHandler = new H();
- private final View mPageIndicator;
private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
private final QSTileRevealController mQsTileRevealController;
@@ -75,6 +75,8 @@
protected QSTileHost mHost;
protected QSSecurityFooter mFooter;
+ private PageIndicator mPanelPageIndicator;
+ private PageIndicator mFooterPageIndicator;
private boolean mGridContentVisible = true;
protected QSTileLayout mTileLayout;
@@ -104,13 +106,13 @@
mTileLayout.setListening(mListening);
addView((View) mTileLayout);
- mPageIndicator = LayoutInflater.from(context).inflate(
+ mPanelPageIndicator = (PageIndicator) LayoutInflater.from(context).inflate(
R.layout.qs_page_indicator, this, false);
- addView(mPageIndicator);
+ addView(mPanelPageIndicator);
- ((PagedTileLayout) mTileLayout).setPageIndicator((PageIndicator) mPageIndicator);
+ ((PagedTileLayout) mTileLayout).setPageIndicator(mPanelPageIndicator);
mQsTileRevealController = new QSTileRevealController(mContext, this,
- ((PagedTileLayout) mTileLayout));
+ (PagedTileLayout) mTileLayout);
addDivider();
@@ -136,7 +138,7 @@
}
public View getPageIndicator() {
- return mPageIndicator;
+ return mPanelPageIndicator;
}
public QSTileRevealController getQsTileRevealController() {
@@ -241,6 +243,38 @@
}
}
+ /**
+ * Links the footer's page indicator, which is used in landscape orientation to save space.
+ *
+ * @param pageIndicator indicator to use for page scrolling
+ */
+ public void setFooterPageIndicator(PageIndicator pageIndicator) {
+ if (mTileLayout instanceof PagedTileLayout) {
+ mFooterPageIndicator = pageIndicator;
+ updatePageIndicator();
+ }
+ }
+
+ private void updatePageIndicator() {
+ if (mTileLayout instanceof PagedTileLayout) {
+ // If we're in landscape, and we have the footer page indicator (which we should if the
+ // footer has been initialized & linked), then we'll show the footer page indicator to
+ // save space in the main QS tile area. Otherwise, we'll use the default one under the
+ // tiles/above the footer.
+ boolean shouldUseFooterPageIndicator =
+ getResources().getConfiguration().orientation == ORIENTATION_LANDSCAPE
+ && mFooterPageIndicator != null;
+
+ mPanelPageIndicator.setVisibility(View.GONE);
+ if (mFooterPageIndicator != null) {
+ mFooterPageIndicator.setVisibility(View.GONE);
+ }
+
+ ((PagedTileLayout) mTileLayout).setPageIndicator(
+ shouldUseFooterPageIndicator ? mFooterPageIndicator : mPanelPageIndicator);
+ }
+ }
+
public QSTileHost getHost() {
return mHost;
}
@@ -248,6 +282,9 @@
public void updateResources() {
final Resources res = mContext.getResources();
setPadding(0, res.getDimensionPixelSize(R.dimen.qs_panel_padding_top), 0, res.getDimensionPixelSize(R.dimen.qs_panel_padding_bottom));
+
+ updatePageIndicator();
+
for (TileRecord r : mRecords) {
r.tile.clearState();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index d1913df..5d7dcbb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -375,9 +375,12 @@
Pair<Integer, Integer> padding = PhoneStatusBarView.cornerCutoutMargins(
insets.getDisplayCutout(), getDisplay());
if (padding == null) {
- setPadding(0, 0, 0, 0);
+ mSystemIconsView.setPaddingRelative(
+ getResources().getDimensionPixelSize(R.dimen.status_bar_padding_start), 0,
+ getResources().getDimensionPixelSize(R.dimen.status_bar_padding_end), 0);
} else {
- setPadding(padding.first, 0, padding.second, 0);
+ mSystemIconsView.setPadding(padding.first, 0, padding.second, 0);
+
}
return super.onApplyWindowInsets(insets);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java
index da21aa5..608a236 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java
@@ -75,7 +75,7 @@
mUserGridView = mUserSwitcherContainer.findViewById(R.id.user_grid);
GridLayoutManager layoutManager = new GridLayoutManager(context,
context.getResources().getInteger(R.integer.user_fullscreen_switcher_num_col));
- mUserGridView.setLayoutManager(layoutManager);
+ mUserGridView.getRecyclerView().setLayoutManager(layoutManager);
mUserGridView.buildAdapter();
mUserSwitchCallback = new UserSwitchCallback();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
index c1af1fa..6cb80c0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
@@ -23,7 +23,6 @@
import android.view.ViewStub;
import android.support.v7.widget.GridLayoutManager;
-import android.support.v7.widget.RecyclerView;
import com.android.settingslib.users.UserManagerHelper;
import com.android.systemui.R;
@@ -49,7 +48,7 @@
mUserGridView = mContainer.findViewById(R.id.user_grid);
GridLayoutManager layoutManager = new GridLayoutManager(context,
context.getResources().getInteger(R.integer.user_fullscreen_switcher_num_col));
- mUserGridView.setLayoutManager(layoutManager);
+ mUserGridView.getRecyclerView().setLayoutManager(layoutManager);
mUserGridView.buildAdapter();
mUserGridView.setUserSelectionListener(this::onUserSelected);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
index 5006a2c..41b70f8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
@@ -16,19 +16,12 @@
package com.android.systemui.statusbar.car;
-import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.UserInfo;
+import android.content.res.ColorStateList;
import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Paint.Align;
-import android.graphics.drawable.GradientDrawable;
import android.os.AsyncTask;
-import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.RecyclerView.ViewHolder;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
@@ -36,6 +29,8 @@
import android.widget.ImageView;
import android.widget.TextView;
+import androidx.car.widget.PagedListView;
+
import com.android.settingslib.users.UserManagerHelper;
import com.android.systemui.R;
@@ -46,7 +41,7 @@
* Displays a GridLayout with icons for the users in the system to allow switching between users.
* One of the uses of this is for the lock screen in auto.
*/
-public class UserGridRecyclerView extends RecyclerView implements
+public class UserGridRecyclerView extends PagedListView implements
UserManagerHelper.OnUsersUpdateListener {
private UserSelectionListener mUserSelectionListener;
private UserAdapter mAdapter;
@@ -55,7 +50,6 @@
public UserGridRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
- super.setHasFixedSize(true);
mContext = context;
mUserManagerHelper = new UserManagerHelper(mContext);
}
@@ -65,6 +59,7 @@
*/
@Override
public void onFinishInflate() {
+ super.onFinishInflate();
mUserManagerHelper.registerOnUsersUpdateListener(this);
}
@@ -73,6 +68,7 @@
*/
@Override
public void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
mUserManagerHelper.unregisterOnUsersUpdateListener();
}
@@ -152,8 +148,6 @@
private final Context mContext;
private List<UserRecord> mUsers;
- private final int mPodImageAvatarWidth;
- private final int mPodImageAvatarHeight;
private final Resources mRes;
private final String mGuestName;
private final String mNewUserName;
@@ -162,10 +156,6 @@
mRes = context.getResources();
mContext = context;
updateUsers(users);
- mPodImageAvatarWidth = mRes.getDimensionPixelSize(
- R.dimen.car_fullscreen_user_pod_image_avatar_width);
- mPodImageAvatarHeight = mRes.getDimensionPixelSize(
- R.dimen.car_fullscreen_user_pod_image_avatar_height);
mGuestName = mRes.getString(R.string.car_guest);
mNewUserName = mRes.getString(R.string.car_new_user);
}
@@ -190,13 +180,22 @@
@Override
public void onBindViewHolder(UserAdapterViewHolder holder, int position) {
UserRecord userRecord = mUsers.get(position);
- holder.mUserAvatarImageView.setImageBitmap(getDefaultUserIcon(userRecord));
+ if (!userRecord.mIsAddUser) {
+ holder.mUserAvatarImageView.setImageBitmap(mUserManagerHelper
+ .getUserIcon(userRecord.mInfo));
+ } else {
+ holder.mUserAvatarImageView.setImageDrawable(mContext
+ .getDrawable(R.drawable.ic_add_circle_qs));
+ }
holder.mUserNameTextView.setText(userRecord.mInfo.name);
holder.mView.setOnClickListener(v -> {
if (userRecord == null) {
return;
}
+ // Disable button so it cannot be clicked multiple times
+ holder.mView.setEnabled(false);
+
// Notify the listener which user was selected
if (mUserSelectionListener != null) {
mUserSelectionListener.onUserSelected(userRecord);
@@ -244,57 +243,6 @@
return mUsers.size();
}
- /**
- * Returns the default user icon. This icon is a circle with a letter in it. The letter is
- * the first character in the username.
- *
- * @param record the profile of the user for which the icon should be created
- */
- private Bitmap getDefaultUserIcon(UserRecord record) {
- CharSequence displayText;
- boolean isAddUserText = false;
- if (record.mIsAddUser) {
- displayText = "+";
- isAddUserText = true;
- } else {
- displayText = record.mInfo.name.subSequence(0, 1);
- }
- Bitmap out = Bitmap.createBitmap(mPodImageAvatarWidth, mPodImageAvatarHeight,
- Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(out);
-
- // Draw the circle background.
- GradientDrawable shape = new GradientDrawable();
- shape.setShape(GradientDrawable.RADIAL_GRADIENT);
- shape.setGradientRadius(1.0f);
- shape.setColor(mContext.getColor(R.color.car_grey_50));
- shape.setBounds(0, 0, mPodImageAvatarWidth, mPodImageAvatarHeight);
- shape.draw(canvas);
-
- // Draw the letter in the center.
- Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
- paint.setColor(mContext.getColor(R.color.car_grey_900));
- paint.setTextAlign(Align.CENTER);
- if (isAddUserText) {
- paint.setTextSize(mRes.getDimensionPixelSize(
- R.dimen.car_touch_target_size));
- } else {
- paint.setTextSize(mRes.getDimensionPixelSize(
- R.dimen.car_fullscreen_user_pod_icon_text_size));
- }
-
- Paint.FontMetricsInt metrics = paint.getFontMetricsInt();
- // The Y coordinate is measured by taking half the height of the pod, but that would
- // draw the character putting the bottom of the font in the middle of the pod. To
- // correct this, half the difference between the top and bottom distance metrics of the
- // font gives the offset of the font. Bottom is a positive value, top is negative, so
- // the different is actually a sum. The "half" operation is then factored out.
- canvas.drawText(displayText.toString(), mPodImageAvatarWidth / 2,
- (mPodImageAvatarHeight - (metrics.bottom + metrics.top)) / 2, paint);
-
- return out;
- }
-
public class UserAdapterViewHolder extends RecyclerView.ViewHolder {
public ImageView mUserAvatarImageView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 1fb1ddd..d9a55c5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -232,8 +232,7 @@
if (mCurrentlySecure) {
alphaKeyguard = 1;
} else {
- alphaKeyguard = Math.max(0, Math.min(1, (y - mMinTopMargin)
- / Math.max(1f, getExpandedClockPosition() - mMinTopMargin)));
+ alphaKeyguard = Math.max(0, y / Math.max(1f, getExpandedClockPosition()));
alphaKeyguard = Interpolators.ACCELERATE.getInterpolation(alphaKeyguard);
}
return MathUtils.lerp(alphaKeyguard, 1f, mDarkAmount);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 4e8003e..d6b45d6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -449,6 +449,18 @@
mScrimBehind.setDrawable(drawable);
}
+ /**
+ * Sets the front alpha while in AOD.
+ */
+ public void setAodFrontScrimAlpha(float alpha) {
+ if (mState == ScrimState.AOD && mCurrentInFrontAlpha != alpha) {
+ mCurrentInFrontAlpha = alpha;
+ scheduleUpdate();
+ }
+
+ mState.AOD.setAodFrontScrimAlpha(alpha);
+ }
+
protected void scheduleUpdate() {
if (mUpdatePending) return;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index e7d5c4e..235b1a9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -4883,7 +4883,7 @@
@Override
public void setAodDimmingScrim(float scrimOpacity) {
- ScrimState.AOD.setAodFrontScrimAlpha(scrimOpacity);
+ mScrimController.setAodFrontScrimAlpha(scrimOpacity);
}
public void dispatchDoubleTap(float viewX, float viewY) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
index 4d86ae9..1431682 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
@@ -17,6 +17,8 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.widget.Button;
import com.android.internal.annotations.VisibleForTesting;
@@ -179,6 +181,15 @@
mKeyguardDismissUtil.dismissKeyguardThenExecute(
action, null /* cancelAction */, false /* afterKeyguardGone */);
});
+
+ b.setAccessibilityDelegate(new AccessibilityDelegate() {
+ public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(host, info);
+ String label = getResources().getString(R.string.accessibility_send_smart_reply);
+ info.addAction(new AccessibilityAction(AccessibilityNodeInfo.ACTION_CLICK, label));
+ }
+ });
+
return b;
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index d78a6cb..c8fcfce 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -71,7 +71,7 @@
import android.view.Window;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
+import android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener;
import android.view.animation.DecelerateInterpolator;
import android.widget.ImageButton;
import android.widget.ImageView;
@@ -1182,12 +1182,12 @@
}
});
mDialogView.setAccessibilityDelegate(this);
- mAccessibilityMgr.addAccessibilityStateChangeListener(mListener);
+ mAccessibilityMgr.addCallback(mListener);
updateFeedbackEnabled();
}
public void destroy() {
- mAccessibilityMgr.removeAccessibilityStateChangeListener(mListener);
+ mAccessibilityMgr.removeCallback(mListener);
}
@Override
@@ -1213,7 +1213,7 @@
return false;
}
- private final AccessibilityStateChangeListener mListener =
+ private final AccessibilityServicesStateChangeListener mListener =
enabled -> updateFeedbackEnabled();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 69508ac..4e04790 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -157,6 +157,38 @@
}
@Test
+ public void transitionToAod_withFrontAlphaUpdates() {
+ // Assert that setting the AOD front scrim alpha doesn't take effect in a non-AOD state.
+ mScrimController.transitionTo(ScrimState.KEYGUARD);
+ mScrimController.setAodFrontScrimAlpha(0.5f);
+ mScrimController.finishAnimationsImmediately();
+ // Front scrim should be transparent
+ // Back scrim should be visible without tint
+ assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_SEMI_TRANSPARENT);
+
+ // ... but that it does take effect once we enter the AOD state.
+ mScrimController.transitionTo(ScrimState.AOD);
+ mScrimController.finishAnimationsImmediately();
+ // Front scrim should be semi-transparent
+ // Back scrim should be visible
+ assertScrimVisibility(VISIBILITY_SEMI_TRANSPARENT, VISIBILITY_FULLY_OPAQUE);
+
+ // ... and that if we set it while we're in AOD, it does take immediate effect.
+ mScrimController.setAodFrontScrimAlpha(1f);
+ assertScrimVisibility(VISIBILITY_FULLY_OPAQUE, VISIBILITY_FULLY_OPAQUE);
+
+ // ... and make sure we recall the previous front scrim alpha even if we transition away
+ // for a bit.
+ mScrimController.transitionTo(ScrimState.UNLOCKED);
+ mScrimController.transitionTo(ScrimState.AOD);
+ mScrimController.finishAnimationsImmediately();
+ assertScrimVisibility(VISIBILITY_FULLY_OPAQUE, VISIBILITY_FULLY_OPAQUE);
+
+ // Reset value since enums are static.
+ mScrimController.setAodFrontScrimAlpha(0f);
+ }
+
+ @Test
public void transitionToPulsing() {
// Pre-condition
// Need to go to AoD first because PULSING doesn't change
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 85eeba0..5c5f0f8 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -141,6 +141,13 @@
static final int ALARM_EVENT = 1;
static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
+ // Indices into the APP_STANDBY_MIN_DELAYS and KEYS_APP_STANDBY_DELAY arrays
+ static final int ACTIVE_INDEX = 0;
+ static final int WORKING_INDEX = 1;
+ static final int FREQUENT_INDEX = 2;
+ static final int RARE_INDEX = 3;
+ static final int NEVER_INDEX = 4;
+
private final Intent mBackgroundIntent
= new Intent().addFlags(Intent.FLAG_FROM_BACKGROUND);
static final IncreasingTimeOrder sIncreasingTimeOrder = new IncreasingTimeOrder();
@@ -381,9 +388,10 @@
DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION);
LISTENER_TIMEOUT = mParser.getLong(KEY_LISTENER_TIMEOUT,
DEFAULT_LISTENER_TIMEOUT);
- APP_STANDBY_MIN_DELAYS[0] = mParser.getDurationMillis(KEYS_APP_STANDBY_DELAY[0],
- DEFAULT_APP_STANDBY_DELAYS[0]);
- for (int i = 1; i < KEYS_APP_STANDBY_DELAY.length; i++) {
+ APP_STANDBY_MIN_DELAYS[ACTIVE_INDEX] = mParser.getDurationMillis(
+ KEYS_APP_STANDBY_DELAY[ACTIVE_INDEX],
+ DEFAULT_APP_STANDBY_DELAYS[ACTIVE_INDEX]);
+ for (int i = WORKING_INDEX; i < KEYS_APP_STANDBY_DELAY.length; i++) {
APP_STANDBY_MIN_DELAYS[i] = mParser.getDurationMillis(KEYS_APP_STANDBY_DELAY[i],
Math.max(APP_STANDBY_MIN_DELAYS[i-1], DEFAULT_APP_STANDBY_DELAYS[i]));
}
@@ -1526,22 +1534,24 @@
setImplLocked(a, false, doValidate);
}
+ /**
+ * Return the minimum time that should elapse before an app in the specified bucket
+ * can receive alarms again
+ */
private long getMinDelayForBucketLocked(int bucket) {
- // Return the minimum time that should elapse before an app in the specified bucket
- // can receive alarms again
- if (bucket == UsageStatsManager.STANDBY_BUCKET_NEVER) {
- return mConstants.APP_STANDBY_MIN_DELAYS[4];
- }
- else if (bucket >= UsageStatsManager.STANDBY_BUCKET_RARE) {
- return mConstants.APP_STANDBY_MIN_DELAYS[3];
- }
- else if (bucket >= UsageStatsManager.STANDBY_BUCKET_FREQUENT) {
- return mConstants.APP_STANDBY_MIN_DELAYS[2];
- }
- else if (bucket >= UsageStatsManager.STANDBY_BUCKET_WORKING_SET) {
- return mConstants.APP_STANDBY_MIN_DELAYS[1];
- }
- else return mConstants.APP_STANDBY_MIN_DELAYS[0];
+ // UsageStats bucket values are treated as floors of their behavioral range.
+ // In other words, a bucket value between WORKING and ACTIVE is treated as
+ // WORKING, not as ACTIVE. The ACTIVE and NEVER bucket apply only at specific
+ // values.
+ final int index;
+
+ if (bucket == UsageStatsManager.STANDBY_BUCKET_NEVER) index = NEVER_INDEX;
+ else if (bucket > UsageStatsManager.STANDBY_BUCKET_FREQUENT) index = RARE_INDEX;
+ else if (bucket > UsageStatsManager.STANDBY_BUCKET_WORKING_SET) index = FREQUENT_INDEX;
+ else if (bucket > UsageStatsManager.STANDBY_BUCKET_ACTIVE) index = WORKING_INDEX;
+ else index = ACTIVE_INDEX;
+
+ return mConstants.APP_STANDBY_MIN_DELAYS[index];
}
/**
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 3a4de28..d2c0efb 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -8861,6 +8861,12 @@
}
@Override
+ public int noteOp(String op, int uid, String packageName) {
+ return mActivityManagerService.mAppOpsService
+ .noteOperation(AppOpsManager.strOpToOp(op), uid, packageName);
+ }
+
+ @Override
public String[] getPackagesForUid(int uid) {
return mActivityManagerService.mContext.getPackageManager()
.getPackagesForUid(uid);
diff --git a/services/core/java/com/android/server/am/CarUserSwitchingDialog.java b/services/core/java/com/android/server/am/CarUserSwitchingDialog.java
index e34ee63..676f0c7 100644
--- a/services/core/java/com/android/server/am/CarUserSwitchingDialog.java
+++ b/services/core/java/com/android/server/am/CarUserSwitchingDialog.java
@@ -20,17 +20,16 @@
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
-import android.graphics.Canvas;
+import android.graphics.BitmapFactory;
import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Paint.Align;
import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.GradientDrawable;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.android.internal.R;
+import com.android.server.pm.UserManagerService;
+import java.io.FileDescriptor;
/**
* Dialog to show when a user switch it about to happen for the car. The intent is to snapshot the
@@ -60,54 +59,13 @@
View view = LayoutInflater.from(getContext()).inflate(R.layout.car_user_switching_dialog,
null);
+ FileDescriptor fileDescriptor = UserManagerService.getInstance()
+ .getUserIcon(mNewUser.id).getFileDescriptor();
+ Bitmap bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor);
((ImageView) view.findViewById(R.id.user_loading_avatar))
- .setImageBitmap(getDefaultUserIcon(mNewUser));
+ .setImageBitmap(bitmap);
((TextView) view.findViewById(R.id.user_loading))
.setText(res.getString(R.string.car_loading_profile));
setView(view);
}
-
- /**
- * Returns the default user icon. This icon is a circle with a letter in it. The letter is
- * the first character in the username.
- *
- * @param userInfo the profile of the user for which the icon should be created
- */
- private Bitmap getDefaultUserIcon(UserInfo userInfo) {
- Resources res = mContext.getResources();
- int mPodImageAvatarWidth = res.getDimensionPixelSize(
- R.dimen.car_fullscreen_user_pod_image_avatar_width);
- int mPodImageAvatarHeight = res.getDimensionPixelSize(
- R.dimen.car_fullscreen_user_pod_image_avatar_height);
- CharSequence displayText = userInfo.name.subSequence(0, 1);
- Bitmap out = Bitmap.createBitmap(mPodImageAvatarWidth, mPodImageAvatarHeight,
- Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(out);
-
- // Draw the circle background.
- GradientDrawable shape = new GradientDrawable();
- shape.setShape(GradientDrawable.RADIAL_GRADIENT);
- shape.setGradientRadius(1.0f);
- shape.setColor(mContext.getColor(R.color.car_user_switcher_user_image_bgcolor));
- shape.setBounds(0, 0, mPodImageAvatarWidth, mPodImageAvatarHeight);
- shape.draw(canvas);
-
- // Draw the letter in the center.
- Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
- paint.setColor(mContext.getColor(R.color.car_user_switcher_user_image_fgcolor));
- paint.setTextAlign(Align.CENTER);
- paint.setTextSize(res.getDimensionPixelSize(
- R.dimen.car_fullscreen_user_pod_icon_text_size));
-
- Paint.FontMetricsInt metrics = paint.getFontMetricsInt();
- // The Y coordinate is measured by taking half the height of the pod, but that would
- // draw the character putting the bottom of the font in the middle of the pod. To
- // correct this, half the difference between the top and bottom distance metrics of the
- // font gives the offset of the font. Bottom is a positive value, top is negative, so
- // the different is actually a sum. The "half" operation is then factored out.
- canvas.drawText(displayText.toString(), mPodImageAvatarWidth / 2,
- (mPodImageAvatarHeight - (metrics.bottom + metrics.top)) / 2, paint);
-
- return out;
- }
}
diff --git a/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java b/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java
index ff1e29b..f2e44ee 100644
--- a/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java
+++ b/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java
@@ -80,8 +80,6 @@
@NonNull RadioManager.BandConfig config);
private native RadioManager.BandConfig nativeGetConfiguration(long nativeContext, int region);
- private native void nativeSetMuted(long nativeContext, boolean mute);
-
private native void nativeStep(long nativeContext, boolean directionDown, boolean skipSubChannel);
private native void nativeScan(long nativeContext, boolean directionDown, boolean skipSubChannel);
private native void nativeTune(long nativeContext, @NonNull ProgramSelector selector);
@@ -155,8 +153,7 @@
checkNotClosedLocked();
if (mIsMuted == mute) return;
mIsMuted = mute;
-
- nativeSetMuted(mNativeContext, mute);
+ Slog.w(TAG, "Mute via RadioService is not implemented - please handle it via app");
}
}
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
index 8f3f099..9833507 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
@@ -25,7 +25,6 @@
import android.hardware.radio.ProgramList;
import android.hardware.radio.ProgramSelector;
import android.hardware.radio.RadioManager;
-import android.media.AudioSystem;
import android.os.RemoteException;
import android.util.MutableBoolean;
import android.util.MutableInt;
@@ -45,7 +44,6 @@
private final ITunerSession mHwSession;
private final TunerCallback mCallback;
private boolean mIsClosed = false;
- private boolean mIsAudioConnected = false;
private boolean mIsMuted = false;
// necessary only for older APIs compatibility
@@ -56,7 +54,6 @@
mModule = Objects.requireNonNull(module);
mHwSession = Objects.requireNonNull(hwSession);
mCallback = Objects.requireNonNull(callback);
- notifyAudioServiceLocked(true);
}
@Override
@@ -64,7 +61,6 @@
synchronized (mLock) {
if (mIsClosed) return;
mIsClosed = true;
- notifyAudioServiceLocked(false);
}
}
@@ -79,22 +75,6 @@
}
}
- private void notifyAudioServiceLocked(boolean connected) {
- if (mIsAudioConnected == connected) return;
-
- Slog.d(TAG, "Notifying AudioService about new state: " + connected);
- int ret = AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_FM_TUNER,
- connected ? AudioSystem.DEVICE_STATE_AVAILABLE : AudioSystem.DEVICE_STATE_UNAVAILABLE,
- null, kAudioDeviceName);
-
- if (ret == AudioSystem.AUDIO_STATUS_OK) {
- mIsAudioConnected = connected;
- } else {
- Slog.e(TAG, "Failed to notify AudioService about new state: "
- + connected + ", response was: " + ret);
- }
- }
-
@Override
public void setConfiguration(RadioManager.BandConfig config) {
synchronized (mLock) {
@@ -119,7 +99,7 @@
checkNotClosedLocked();
if (mIsMuted == mute) return;
mIsMuted = mute;
- notifyAudioServiceLocked(!mute);
+ Slog.w(TAG, "Mute via RadioService is not implemented - please handle it via app");
}
}
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index e3d0bdd..e840a29 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -51,6 +51,8 @@
import android.os.Parcel;
import android.os.Process;
import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -1577,4 +1579,32 @@
}
}
}
+
+ private void enforceShell(String method) {
+ final int callingUid = Binder.getCallingUid();
+ if (callingUid != Process.SHELL_UID && callingUid != Process.ROOT_UID) {
+ throw new SecurityException("Non-shell user attempted to call " + method);
+ }
+ }
+
+ @Override
+ public void resetTodayStats() {
+ enforceShell("resetTodayStats");
+
+ if (mSyncManager != null) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mSyncManager.resetTodayStats();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ }
+
+ @Override
+ public void onShellCommand(FileDescriptor in, FileDescriptor out,
+ FileDescriptor err, String[] args, ShellCallback callback,
+ ResultReceiver resultReceiver) {
+ (new ContentShellCommand(this)).exec(this, in, out, err, args, callback, resultReceiver);
+ }
}
diff --git a/services/core/java/com/android/server/content/ContentShellCommand.java b/services/core/java/com/android/server/content/ContentShellCommand.java
new file mode 100644
index 0000000..6c2991f
--- /dev/null
+++ b/services/core/java/com/android/server/content/ContentShellCommand.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.content;
+
+import android.content.IContentService;
+import android.content.Intent;
+import android.os.RemoteException;
+import android.os.ShellCommand;
+
+import java.io.PrintWriter;
+
+public class ContentShellCommand extends ShellCommand {
+ final IContentService mInterface;
+
+ ContentShellCommand(IContentService service) {
+ mInterface = service;
+ }
+
+ @Override
+ public int onCommand(String cmd) {
+ if (cmd == null) {
+ return handleDefaultCommands(cmd);
+ }
+
+ final PrintWriter pw = getOutPrintWriter();
+ try {
+ switch(cmd) {
+ case "reset-today-stats":
+ return runResetTodayStats();
+ default:
+ return handleDefaultCommands(cmd);
+ }
+ } catch (RemoteException e) {
+ pw.println("Remote exception: " + e);
+ }
+ return -1;
+ }
+
+ private int runResetTodayStats() throws RemoteException {
+ mInterface.resetTodayStats();
+ return 0;
+ }
+
+ @Override
+ public void onHelp() {
+ final PrintWriter pw = getOutPrintWriter();
+ pw.println("Content service commands:");
+ pw.println(" help");
+ pw.println(" Print this help text.");
+ pw.println("");
+ pw.println(" reset-today-stats");
+ pw.println(" Reset 1-day sync stats.");
+ pw.println();
+ }
+}
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index a312fe1..decae18 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -48,6 +48,7 @@
import android.content.SyncInfo;
import android.content.SyncResult;
import android.content.SyncStatusInfo;
+import android.content.SyncStatusInfo.Stats;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -95,6 +96,7 @@
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.function.QuadConsumer;
import com.android.server.DeviceIdleController;
import com.android.server.LocalServices;
import com.android.server.SystemService;
@@ -122,6 +124,7 @@
import java.util.Objects;
import java.util.Random;
import java.util.Set;
+import java.util.function.Function;
import java.util.function.Predicate;
/**
@@ -242,7 +245,7 @@
/** Track whether the device has already been provisioned. */
private volatile boolean mProvisioned;
- protected SyncAdaptersCache mSyncAdapters;
+ protected final SyncAdaptersCache mSyncAdapters;
private final Random mRand;
@@ -423,6 +426,17 @@
}
};
+ private final BroadcastReceiver mOtherIntentsReceiver =
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_TIME_CHANGED.equals(intent.getAction())) {
+ mSyncStorageEngine.setClockValid();
+ return;
+ }
+ }
+ };
+
private BroadcastReceiver mUserIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -631,6 +645,9 @@
mContext.registerReceiverAsUser(
mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null);
+ intentFilter = new IntentFilter(Intent.ACTION_TIME_CHANGED);
+ context.registerReceiver(mOtherIntentsReceiver, intentFilter);
+
if (!factoryTest) {
mNotificationMgr = (NotificationManager)
context.getSystemService(Context.NOTIFICATION_SERVICE);
@@ -947,9 +964,13 @@
} else if (requestedAuthority == null) {
source = SyncStorageEngine.SOURCE_POLL;
} else {
- // This isn't strictly server, since arbitrary callers can (and do) request
- // a non-forced two-way sync on a specific url.
- source = SyncStorageEngine.SOURCE_SERVER;
+ if (extras.containsKey("feed")) {
+ source = SyncStorageEngine.SOURCE_FEED;
+ } else{
+ // This isn't strictly server, since arbitrary callers can (and do) request
+ // a non-forced two-way sync on a specific url.
+ source = SyncStorageEngine.SOURCE_OTHER;
+ }
}
for (AccountAndUser account : accounts) {
@@ -2134,6 +2155,7 @@
pw.print("Memory low: "); pw.println(mStorageIsLow);
pw.print("Device idle: "); pw.println(mDeviceIsIdle);
pw.print("Reported active: "); pw.println(mReportedSyncActive);
+ pw.print("Clock valid: "); pw.println(mSyncStorageEngine.isClockValid());
final AccountAndUser[] accounts = AccountManagerService.getSingleton().getAllAccounts();
@@ -2181,26 +2203,35 @@
final ArrayList<Pair<EndPoint, SyncStatusInfo>> statuses = new ArrayList<>();
+ mSyncStorageEngine.resetTodayStats(/* force=*/ false);
+
for (AccountAndUser account : accounts) {
pw.printf("Account %s u%d %s\n",
account.account.name, account.userId, account.account.type);
pw.println("=======================================================================");
- final PrintTable table = new PrintTable(13);
+ final PrintTable table = new PrintTable(16);
table.set(0, 0,
"Authority", // 0
"Syncable", // 1
"Enabled", // 2
- "Delay", // 3
- "Loc", // 4
- "Poll", // 5
- "Per", // 6
- "Serv", // 7
- "User", // 8
- "Tot", // 9
- "Time", // 10
- "Last Sync", // 11
- "Backoff" // 12
+
+ "Stats", // 3 "Total", "Today" or "Yesterday".
+
+ "Loc", // 4 # of syncs with local sources. (including failures/cancels. )
+ "Poll", // 5 "poll" syncs.
+ "Per", // 6 Periodic syncs.
+ "Feed", // 7 Syncs with a "feed" extra. (subscribedfeeds?)
+ "User", // 8 User-initiated
+ "Othr", // 9 Other sources.
+
+ "Tot", // 10 Total syncs (including failures / cancels)
+ "Fail", // 11 (Failure)
+ "Can", // 12 (Cancel)
+
+ "Time", // 13 Total time
+ "Last Sync", // 14
+ "Backoff" // 15
);
final List<RegisteredServicesCache.ServiceInfo<SyncAdapterType>> sorted =
@@ -2234,37 +2265,50 @@
}
table.set(row, 0, authority, settings.syncable, settings.enabled);
- sb.setLength(0);
- table.set(row, 4,
- status.numSourceLocal,
- status.numSourcePoll,
- status.numSourcePeriodic,
- status.numSourceServer,
- status.numSourceUser,
- status.numSyncs,
- formatDurationHMS(sb, status.totalElapsedTime));
+ QuadConsumer<String, Stats, Function<Integer, String>, Integer> c =
+ (label, stats, filter, r) -> {
+ sb.setLength(0);
+ table.set(r, 3,
+ label,
+ filter.apply(stats.numSourceLocal),
+ filter.apply(stats.numSourcePoll),
+ filter.apply(stats.numSourcePeriodic),
+ filter.apply(stats.numSourceFeed),
+ filter.apply(stats.numSourceUser),
+ filter.apply(stats.numSourceOther),
+ filter.apply(stats.numSyncs),
+ filter.apply(stats.numFailures),
+ filter.apply(stats.numCancels),
+ formatDurationHMS(sb, stats.totalElapsedTime));
+ };
+ c.accept("Total", status.totalStats, (i) -> Integer.toString(i), row);
+ c.accept("Today", status.todayStats, this::zeroToEmpty, row + 1);
+ c.accept("Yestr", status.yesterdayStats, this::zeroToEmpty, row + 2);
+
+ final int LAST_SYNC = 14;
+ final int BACKOFF = LAST_SYNC + 1;
int row1 = row;
if (settings.delayUntil > now) {
- table.set(row1++, 12, "D: " + (settings.delayUntil - now) / 1000);
+ table.set(row1++, BACKOFF, "D: " + (settings.delayUntil - now) / 1000);
if (settings.backoffTime > now) {
- table.set(row1++, 12, "B: " + (settings.backoffTime - now) / 1000);
- table.set(row1++, 12, settings.backoffDelay / 1000);
+ table.set(row1++, BACKOFF, "B: " + (settings.backoffTime - now) / 1000);
+ table.set(row1++, BACKOFF, settings.backoffDelay / 1000);
}
}
row1 = row;
if (status.lastSuccessTime != 0) {
- table.set(row1++, 11, SyncStorageEngine.SOURCES[status.lastSuccessSource]
+ table.set(row1++, LAST_SYNC, SyncStorageEngine.SOURCES[status.lastSuccessSource]
+ " " + "SUCCESS");
- table.set(row1++, 11, formatTime(status.lastSuccessTime));
+ table.set(row1++, LAST_SYNC, formatTime(status.lastSuccessTime));
}
if (status.lastFailureTime != 0) {
- table.set(row1++, 11, SyncStorageEngine.SOURCES[status.lastFailureSource]
+ table.set(row1++, LAST_SYNC, SyncStorageEngine.SOURCES[status.lastFailureSource]
+ " " + "FAILURE");
- table.set(row1++, 11, formatTime(status.lastFailureTime));
+ table.set(row1++, LAST_SYNC, formatTime(status.lastFailureTime));
//noinspection UnusedAssignment
- table.set(row1++, 11, status.lastFailureMesg);
+ table.set(row1++, LAST_SYNC, status.lastFailureMesg);
}
}
table.writeTo(pw);
@@ -2274,6 +2318,7 @@
pw.println();
pw.println("Per Adapter History");
+ pw.println("(SERVER is now split up to FEED and OTHER)");
for (int i = 0; i < statuses.size(); i++) {
final Pair<EndPoint, SyncStatusInfo> event = statuses.get(i);
@@ -2299,6 +2344,10 @@
}
}
+ private String zeroToEmpty(int value) {
+ return (value != 0) ? Integer.toString(value) : "";
+ }
+
private void dumpTimeSec(PrintWriter pw, long time) {
pw.print(time/1000); pw.print('.'); pw.print((time/100)%10);
pw.print('s');
@@ -2459,6 +2508,7 @@
pw.println();
pw.println("Recent Sync History");
+ pw.println("(SERVER is now split up to FEED and OTHER)");
final String format = " %-" + maxAccount + "s %-" + maxAuthority + "s %s\n";
final Map<String, Long> lastTimeMap = Maps.newHashMap();
final PackageManager pm = mContext.getPackageManager();
@@ -2525,6 +2575,7 @@
}
pw.println();
pw.println("Recent Sync History Extras");
+ pw.println("(SERVER is now split up to FEED and OTHER)");
for (int i = 0; i < N; i++) {
final SyncStorageEngine.SyncHistoryItem item = items.get(i);
final Bundle extras = item.extras;
@@ -3104,6 +3155,10 @@
final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
if (isLoggable) Slog.v(TAG, op.toString());
+ // At this point, we know the device has been connected to the server, so
+ // assume the clock is correct.
+ mSyncStorageEngine.setClockValid();
+
mSyncJobService.markSyncStarted(op.jobId);
if (mStorageIsLow) {
@@ -4015,4 +4070,8 @@
Slog.wtf(TAG, message);
mLogger.log("WTF: ", message);
}
+
+ public void resetTodayStats() {
+ mSyncStorageEngine.resetTodayStats(/*force=*/ true);
+ }
}
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index 8dd229c..f54a9a0 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -108,11 +108,12 @@
/** Enum value for a sync stop event. */
public static final int EVENT_STOP = 1;
- /** Enum value for a server-initiated sync. */
- public static final int SOURCE_SERVER = 0;
+ /** Enum value for a sync with other sources. */
+ public static final int SOURCE_OTHER = 0;
/** Enum value for a local-initiated sync. */
public static final int SOURCE_LOCAL = 1;
+
/** Enum value for a poll-based sync (e.g., upon connection to network) */
public static final int SOURCE_POLL = 2;
@@ -122,16 +123,18 @@
/** Enum value for a periodic sync. */
public static final int SOURCE_PERIODIC = 4;
+ /** Enum a sync with a "feed" extra */
+ public static final int SOURCE_FEED = 5;
+
public static final long NOT_IN_BACKOFF_MODE = -1;
- // TODO: i18n -- grab these out of resources.
/** String names for the sync source types. */
- public static final String[] SOURCES = { "SERVER",
+ public static final String[] SOURCES = { "OTHER",
"LOCAL",
"POLL",
"USER",
"PERIODIC",
- "SERVICE"};
+ "FEED"};
// The MESG column will contain one of these or one of the Error types.
public static final String MESG_SUCCESS = "success";
@@ -153,6 +156,8 @@
private static HashMap<String, String> sAuthorityRenames;
private static PeriodicSyncAddedListener mPeriodicSyncAddedListener;
+ private volatile boolean mIsClockValid;
+
static {
sAuthorityRenames = new HashMap<String, String>();
sAuthorityRenames.put("contacts", "com.android.contacts");
@@ -1174,23 +1179,36 @@
SyncStatusInfo status = getOrCreateSyncStatusLocked(item.authorityId);
- status.numSyncs++;
- status.totalElapsedTime += elapsedTime;
+ status.maybeResetTodayStats(isClockValid(), /*force=*/ false);
+
+ status.totalStats.numSyncs++;
+ status.todayStats.numSyncs++;
+ status.totalStats.totalElapsedTime += elapsedTime;
+ status.todayStats.totalElapsedTime += elapsedTime;
switch (item.source) {
case SOURCE_LOCAL:
- status.numSourceLocal++;
+ status.totalStats.numSourceLocal++;
+ status.todayStats.numSourceLocal++;
break;
case SOURCE_POLL:
- status.numSourcePoll++;
+ status.totalStats.numSourcePoll++;
+ status.todayStats.numSourcePoll++;
break;
case SOURCE_USER:
- status.numSourceUser++;
+ status.totalStats.numSourceUser++;
+ status.todayStats.numSourceUser++;
break;
- case SOURCE_SERVER:
- status.numSourceServer++;
+ case SOURCE_OTHER:
+ status.totalStats.numSourceOther++;
+ status.todayStats.numSourceOther++;
break;
case SOURCE_PERIODIC:
- status.numSourcePeriodic++;
+ status.totalStats.numSourcePeriodic++;
+ status.todayStats.numSourcePeriodic++;
+ break;
+ case SOURCE_FEED:
+ status.totalStats.numSourceFeed++;
+ status.todayStats.numSourceFeed++;
break;
}
@@ -1225,6 +1243,9 @@
if (status.lastFailureTime == 0) {
writeStatusNow = true;
}
+ status.totalStats.numFailures++;
+ status.todayStats.numFailures++;
+
status.lastFailureTime = lastSyncTime;
status.lastFailureSource = item.source;
status.lastFailureMesg = resultMessage;
@@ -1233,6 +1254,11 @@
}
ds.failureCount++;
ds.failureTime += elapsedTime;
+ } else {
+ // Cancel
+ status.totalStats.numCancels++;
+ status.todayStats.numCancels++;
+ writeStatusNow = true;
}
final StringBuilder event = new StringBuilder();
event.append("" + resultMessage + " Source=" + SyncStorageEngine.SOURCES[item.source]
@@ -1969,9 +1995,8 @@
}
/**
- * Load sync engine state from the old syncmanager database, and then
- * erase it. Note that we don't deal with pending operations, active
- * sync, or history.
+ * TODO Remove it. It's super old code that was used to migrate the information from a sqlite
+ * database that we used a long time ago, and is no longer relevant.
*/
private void readAndDeleteLegacyAccountInfoLocked() {
// Look for old database to initialize from.
@@ -2049,13 +2074,13 @@
st = new SyncStatusInfo(authority.ident);
mSyncStatus.put(authority.ident, st);
}
- st.totalElapsedTime = getLongColumn(c, "totalElapsedTime");
- st.numSyncs = getIntColumn(c, "numSyncs");
- st.numSourceLocal = getIntColumn(c, "numSourceLocal");
- st.numSourcePoll = getIntColumn(c, "numSourcePoll");
- st.numSourceServer = getIntColumn(c, "numSourceServer");
- st.numSourceUser = getIntColumn(c, "numSourceUser");
- st.numSourcePeriodic = 0;
+ st.totalStats.totalElapsedTime = getLongColumn(c, "totalElapsedTime");
+ st.totalStats.numSyncs = getIntColumn(c, "numSyncs");
+ st.totalStats.numSourceLocal = getIntColumn(c, "numSourceLocal");
+ st.totalStats.numSourcePoll = getIntColumn(c, "numSourcePoll");
+ st.totalStats.numSourceOther = getIntColumn(c, "numSourceServer");
+ st.totalStats.numSourceUser = getIntColumn(c, "numSourceUser");
+ st.totalStats.numSourcePeriodic = 0;
st.lastSuccessSource = getIntColumn(c, "lastSuccessSource");
st.lastSuccessTime = getLongColumn(c, "lastSuccessTime");
st.lastFailureSource = getIntColumn(c, "lastFailureSource");
@@ -2296,4 +2321,29 @@
public void queueBackup() {
BackupManager.dataChanged("android");
}
+
+ public void setClockValid() {
+ if (!mIsClockValid) {
+ mIsClockValid = true;
+ Slog.w(TAG, "Clock is valid now.");
+ }
+ }
+
+ public boolean isClockValid() {
+ return mIsClockValid;
+ }
+
+ public void resetTodayStats(boolean force) {
+ if (force) {
+ Log.w(TAG, "Force resetting today stats.");
+ }
+ synchronized (mAuthorities) {
+ final int N = mSyncStatus.size();
+ for (int i = 0; i < N; i++) {
+ SyncStatusInfo cur = mSyncStatus.valueAt(i);
+ cur.maybeResetTodayStats(isClockValid(), force);
+ }
+ writeStatusLocked();
+ }
+ }
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index cfec114..46e883c 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -174,6 +174,12 @@
// The default screen brightness.
private final int mScreenBrightnessDefault;
+ // The minimum allowed brightness while in VR.
+ private final int mScreenBrightnessForVrRangeMinimum;
+
+ // The maximum allowed brightness while in VR.
+ private final int mScreenBrightnessForVrRangeMaximum;
+
// The default screen brightness for VR.
private final int mScreenBrightnessForVrDefault;
@@ -386,6 +392,11 @@
com.android.internal.R.integer.config_screenBrightnessSettingMaximum));
mScreenBrightnessDefault = clampAbsoluteBrightness(resources.getInteger(
com.android.internal.R.integer.config_screenBrightnessSettingDefault));
+
+ mScreenBrightnessForVrRangeMinimum = clampAbsoluteBrightness(resources.getInteger(
+ com.android.internal.R.integer.config_screenBrightnessForVrSettingMinimum));
+ mScreenBrightnessForVrRangeMaximum = clampAbsoluteBrightness(resources.getInteger(
+ com.android.internal.R.integer.config_screenBrightnessForVrSettingMaximum));
mScreenBrightnessForVrDefault = clampAbsoluteBrightness(resources.getInteger(
com.android.internal.R.integer.config_screenBrightnessForVrSettingDefault));
@@ -622,6 +633,9 @@
Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS),
false /*notifyForDescendants*/, mSettingsObserver, UserHandle.USER_ALL);
mContext.getContentResolver().registerContentObserver(
+ Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_FOR_VR),
+ false /*notifyForDescendants*/, mSettingsObserver, UserHandle.USER_ALL);
+ mContext.getContentResolver().registerContentObserver(
Settings.System.getUriFor(Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ),
false /*notifyForDescendants*/, mSettingsObserver, UserHandle.USER_ALL);
}
@@ -1146,6 +1160,11 @@
mReportedScreenStateToPolicy = state;
}
+ private int clampScreenBrightnessForVr(int value) {
+ return MathUtils.constrain(
+ value, mScreenBrightnessForVrRangeMinimum, mScreenBrightnessForVrRangeMaximum);
+ }
+
private int clampScreenBrightness(int value) {
return MathUtils.constrain(
value, mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum);
@@ -1458,7 +1477,7 @@
final int brightness = Settings.System.getIntForUser(mContext.getContentResolver(),
Settings.System.SCREEN_BRIGHTNESS_FOR_VR, mScreenBrightnessForVrDefault,
UserHandle.USER_CURRENT);
- return clampAbsoluteBrightness(brightness);
+ return clampScreenBrightnessForVr(brightness);
}
private void putScreenBrightnessSetting(int brightness) {
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 736aa46..0135085 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -248,6 +248,7 @@
static final int WORKING_INDEX = 1;
static final int FREQUENT_INDEX = 2;
static final int RARE_INDEX = 3;
+ static final int NEVER_INDEX = 4;
/**
* Bookkeeping about when jobs last run. We keep our own record in heartbeat time,
@@ -2432,11 +2433,11 @@
public static int standbyBucketToBucketIndex(int bucket) {
// Normalize AppStandby constants to indices into our bookkeeping
- if (bucket == UsageStatsManager.STANDBY_BUCKET_NEVER) return 4;
- else if (bucket >= UsageStatsManager.STANDBY_BUCKET_RARE) return 3;
- else if (bucket >= UsageStatsManager.STANDBY_BUCKET_FREQUENT) return 2;
- else if (bucket >= UsageStatsManager.STANDBY_BUCKET_WORKING_SET) return 1;
- else return 0;
+ if (bucket == UsageStatsManager.STANDBY_BUCKET_NEVER) return NEVER_INDEX;
+ else if (bucket > UsageStatsManager.STANDBY_BUCKET_FREQUENT) return RARE_INDEX;
+ else if (bucket > UsageStatsManager.STANDBY_BUCKET_WORKING_SET) return FREQUENT_INDEX;
+ else if (bucket > UsageStatsManager.STANDBY_BUCKET_ACTIVE) return WORKING_INDEX;
+ else return ACTIVE_INDEX;
}
// Static to support external callers
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index fb1874c..f1fd00b 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -584,10 +584,43 @@
if (mUserManager.getUserInfo(userId).isManagedProfile()) {
tieManagedProfileLockIfNecessary(userId, null);
}
+
+ // If the user doesn't have a credential, try and derive their secret for the
+ // AuthSecret HAL. The secret will have been enrolled if the user previously set a
+ // credential and still needs to be passed to the HAL once that credential is
+ // removed.
+ if (mUserManager.getUserInfo(userId).isPrimary() && !isUserSecure(userId)) {
+ tryDeriveAuthTokenForUnsecuredPrimaryUser(userId);
+ }
}
});
}
+ private void tryDeriveAuthTokenForUnsecuredPrimaryUser(@UserIdInt int userId) {
+ synchronized (mSpManager) {
+ // Make sure the user has a synthetic password to derive
+ if (!isSyntheticPasswordBasedCredentialLocked(userId)) {
+ return;
+ }
+
+ try {
+ final long handle = getSyntheticPasswordHandleLocked(userId);
+ final String noCredential = null;
+ AuthenticationResult result =
+ mSpManager.unwrapPasswordBasedSyntheticPassword(
+ getGateKeeperService(), handle, noCredential, userId, null);
+ if (result.authToken != null) {
+ Slog.i(TAG, "Retrieved auth token for user " + userId);
+ onAuthTokenKnownForUser(userId, result.authToken);
+ } else {
+ Slog.e(TAG, "Auth token not available for user " + userId);
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failure retrieving auth token", e);
+ }
+ }
+ }
+
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 6c0a7a7..5b8e8c0 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -71,6 +71,7 @@
import static android.net.NetworkTemplate.MATCH_WIFI;
import static android.net.NetworkTemplate.buildTemplateMobileAll;
import static android.net.TrafficStats.MB_IN_BYTES;
+import static android.os.Trace.TRACE_TAG_NETWORK;
import static android.provider.Settings.Global.NETPOLICY_OVERRIDE_ENABLED;
import static android.provider.Settings.Global.NETPOLICY_QUOTA_ENABLED;
import static android.provider.Settings.Global.NETPOLICY_QUOTA_FRAC_JOBS;
@@ -1100,6 +1101,7 @@
*/
void updateNotificationsNL() {
if (LOGV) Slog.v(TAG, "updateNotificationsNL()");
+ Trace.traceBegin(TRACE_TAG_NETWORK, "updateNotificationsNL");
// keep track of previously active notifications
final ArraySet<NotificationId> beforeNotifs = new ArraySet<NotificationId>(mActiveNotifs);
@@ -1191,6 +1193,8 @@
cancelNotification(notificationId);
}
}
+
+ Trace.traceEnd(TRACE_TAG_NETWORK);
}
/**
@@ -1604,6 +1608,7 @@
*/
void updateNetworkEnabledNL() {
if (LOGV) Slog.v(TAG, "updateNetworkEnabledNL()");
+ Trace.traceBegin(TRACE_TAG_NETWORK, "updateNetworkEnabledNL");
// TODO: reset any policy-disabled networks when any policy is removed
// completely, which is currently rare case.
@@ -1633,6 +1638,7 @@
}
mStatLogger.logDurationStat(Stats.UPDATE_NETWORK_ENABLED, startTime);
+ Trace.traceEnd(TRACE_TAG_NETWORK);
}
/**
@@ -1693,6 +1699,7 @@
*/
void updateNetworkRulesNL() {
if (LOGV) Slog.v(TAG, "updateNetworkRulesNL()");
+ Trace.traceBegin(TRACE_TAG_NETWORK, "updateNetworkRulesNL");
final NetworkState[] states;
try {
@@ -1866,6 +1873,8 @@
mHandler.obtainMessage(MSG_METERED_IFACES_CHANGED, meteredIfaces).sendToTarget();
mHandler.obtainMessage(MSG_ADVISE_PERSIST_THRESHOLD, lowestRule).sendToTarget();
+
+ Trace.traceEnd(TRACE_TAG_NETWORK);
}
/**
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 0563107..d2d3779 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -43,6 +43,7 @@
import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
import static android.net.TrafficStats.KB_IN_BYTES;
import static android.net.TrafficStats.MB_IN_BYTES;
+import static android.os.Trace.TRACE_TAG_NETWORK;
import static android.provider.Settings.Global.NETSTATS_AUGMENT_ENABLED;
import static android.provider.Settings.Global.NETSTATS_DEV_BUCKET_DURATION;
import static android.provider.Settings.Global.NETSTATS_DEV_DELETE_AGE;
@@ -109,6 +110,7 @@
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.os.Trace;
import android.os.UserHandle;
import android.provider.Settings;
import android.provider.Settings.Global;
@@ -1189,27 +1191,43 @@
private void recordSnapshotLocked(long currentTime) throws RemoteException {
// snapshot and record current counters; read UID stats first to
// avoid over counting dev stats.
+ Trace.traceBegin(TRACE_TAG_NETWORK, "snapshotUid");
final NetworkStats uidSnapshot = getNetworkStatsUidDetail(INTERFACES_ALL);
+ Trace.traceEnd(TRACE_TAG_NETWORK);
+ Trace.traceBegin(TRACE_TAG_NETWORK, "snapshotXt");
final NetworkStats xtSnapshot = getNetworkStatsXt();
+ Trace.traceEnd(TRACE_TAG_NETWORK);
+ Trace.traceBegin(TRACE_TAG_NETWORK, "snapshotDev");
final NetworkStats devSnapshot = mNetworkManager.getNetworkStatsSummaryDev();
+ Trace.traceEnd(TRACE_TAG_NETWORK);
// Tethering snapshot for dev and xt stats. Counts per-interface data from tethering stats
// providers that isn't already counted by dev and XT stats.
+ Trace.traceBegin(TRACE_TAG_NETWORK, "snapshotTether");
final NetworkStats tetherSnapshot = getNetworkStatsTethering(STATS_PER_IFACE);
+ Trace.traceEnd(TRACE_TAG_NETWORK);
xtSnapshot.combineAllValues(tetherSnapshot);
devSnapshot.combineAllValues(tetherSnapshot);
// For xt/dev, we pass a null VPN array because usage is aggregated by UID, so VPN traffic
// can't be reattributed to responsible apps.
+ Trace.traceBegin(TRACE_TAG_NETWORK, "recordDev");
mDevRecorder.recordSnapshotLocked(
devSnapshot, mActiveIfaces, null /* vpnArray */, currentTime);
+ Trace.traceEnd(TRACE_TAG_NETWORK);
+ Trace.traceBegin(TRACE_TAG_NETWORK, "recordXt");
mXtRecorder.recordSnapshotLocked(
xtSnapshot, mActiveIfaces, null /* vpnArray */, currentTime);
+ Trace.traceEnd(TRACE_TAG_NETWORK);
// For per-UID stats, pass the VPN info so VPN traffic is reattributed to responsible apps.
VpnInfo[] vpnArray = mConnManager.getAllVpnInfo();
+ Trace.traceBegin(TRACE_TAG_NETWORK, "recordUid");
mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, vpnArray, currentTime);
+ Trace.traceEnd(TRACE_TAG_NETWORK);
+ Trace.traceBegin(TRACE_TAG_NETWORK, "recordUidTag");
mUidTagRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, vpnArray, currentTime);
+ Trace.traceEnd(TRACE_TAG_NETWORK);
// We need to make copies of member fields that are sent to the observer to avoid
// a race condition between the service handler thread and the observer's
@@ -1254,8 +1272,7 @@
private void performPollLocked(int flags) {
if (!mSystemReady) return;
if (LOGV) Slog.v(TAG, "performPollLocked(flags=0x" + Integer.toHexString(flags) + ")");
-
- final long startRealtime = SystemClock.elapsedRealtime();
+ Trace.traceBegin(TRACE_TAG_NETWORK, "performPollLocked");
final boolean persistNetwork = (flags & FLAG_PERSIST_NETWORK) != 0;
final boolean persistUid = (flags & FLAG_PERSIST_UID) != 0;
@@ -1275,6 +1292,7 @@
}
// persist any pending data depending on requested flags
+ Trace.traceBegin(TRACE_TAG_NETWORK, "[persisting]");
if (persistForce) {
mDevRecorder.forcePersistLocked(currentTime);
mXtRecorder.forcePersistLocked(currentTime);
@@ -1290,11 +1308,7 @@
mUidTagRecorder.maybePersistLocked(currentTime);
}
}
-
- if (LOGV) {
- final long duration = SystemClock.elapsedRealtime() - startRealtime;
- Slog.v(TAG, "performPollLocked() took " + duration + "ms");
- }
+ Trace.traceEnd(TRACE_TAG_NETWORK);
if (mSettings.getSampleEnabled()) {
// sample stats after each full poll
@@ -1306,6 +1320,8 @@
updatedIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
mContext.sendBroadcastAsUser(updatedIntent, UserHandle.ALL,
READ_NETWORK_USAGE_HISTORY);
+
+ Trace.traceEnd(TRACE_TAG_NETWORK);
}
/**
@@ -1388,12 +1404,22 @@
private class NetworkStatsManagerInternalImpl extends NetworkStatsManagerInternal {
@Override
public long getNetworkTotalBytes(NetworkTemplate template, long start, long end) {
- return NetworkStatsService.this.getNetworkTotalBytes(template, start, end);
+ Trace.traceBegin(TRACE_TAG_NETWORK, "getNetworkTotalBytes");
+ try {
+ return NetworkStatsService.this.getNetworkTotalBytes(template, start, end);
+ } finally {
+ Trace.traceEnd(TRACE_TAG_NETWORK);
+ }
}
@Override
public NetworkStats getNetworkUidBytes(NetworkTemplate template, long start, long end) {
- return NetworkStatsService.this.getNetworkUidBytes(template, start, end);
+ Trace.traceBegin(TRACE_TAG_NETWORK, "getNetworkUidBytes");
+ try {
+ return NetworkStatsService.this.getNetworkUidBytes(template, start, end);
+ } finally {
+ Trace.traceEnd(TRACE_TAG_NETWORK);
+ }
}
@Override
diff --git a/services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java b/services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java
index 864ce5d..3b3ee58 100644
--- a/services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java
+++ b/services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java
@@ -75,6 +75,7 @@
private final WatchlistReportDbHelper mDbHelper;
private final WatchlistConfig mConfig;
private final WatchlistSettings mSettings;
+ private int mPrimaryUserId = -1;
// A cache for uid and apk digest mapping.
// As uid won't be reused until reboot, it's safe to assume uid is unique per signature and app.
// TODO: Use more efficient data structure.
@@ -97,6 +98,7 @@
mConfig = WatchlistConfig.getInstance();
mSettings = WatchlistSettings.getInstance();
mDropBoxManager = mContext.getSystemService(DropBoxManager.class);
+ mPrimaryUserId = getPrimaryUserId();
}
@Override
@@ -131,6 +133,19 @@
}
/**
+ * Get primary user id.
+ * @return Primary user id. -1 if primary user not found.
+ */
+ private int getPrimaryUserId() {
+ final UserInfo primaryUserInfo = ((UserManager) mContext.getSystemService(
+ Context.USER_SERVICE)).getPrimaryUser();
+ if (primaryUserInfo != null) {
+ return primaryUserInfo.id;
+ }
+ return -1;
+ }
+
+ /**
* Return if a given package has testOnly is true.
*/
private boolean isPackageTestOnly(int uid) {
@@ -182,6 +197,18 @@
if (DEBUG) {
Slog.i(TAG, "handleNetworkEvent with host: " + hostname + ", uid: " + uid);
}
+ // Update primary user id if necessary
+ if (mPrimaryUserId == -1) {
+ mPrimaryUserId = getPrimaryUserId();
+ }
+
+ // Only process primary user data
+ if (UserHandle.getUserId(uid) != mPrimaryUserId) {
+ if (DEBUG) {
+ Slog.i(TAG, "Do not log non-system user records");
+ }
+ return;
+ }
final String cncDomain = searchAllSubDomainsInWatchlist(hostname);
if (cncDomain != null) {
insertRecord(uid, cncDomain, timestamp);
@@ -272,28 +299,15 @@
@VisibleForTesting
List<String> getAllDigestsForReport(WatchlistReportDbHelper.AggregatedResult record) {
// Step 1: Get all installed application digests.
- final List<UserInfo> users = ((UserManager) mContext.getSystemService(
- Context.USER_SERVICE)).getUsers();
- final int totalUsers = users.size();
final List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications(
- PackageManager.MATCH_ANY_USER | PackageManager.MATCH_ALL);
+ PackageManager.MATCH_ALL);
final HashSet<String> result = new HashSet<>(apps.size() + record.appDigestCNCList.size());
final int size = apps.size();
for (int i = 0; i < size; i++) {
- final int appUid = apps.get(i).uid;
- boolean added = false;
- // As the uid returned by getInstalledApplications() is for primary user only, it
- // may exist in secondary users but not primary user, so we need to loop and see if
- // that user has the app enabled.
- for (int j = 0; j < totalUsers && !added; j++) {
- int uid = UserHandle.getUid(users.get(j).id, appUid);
- byte[] digest = getDigestFromUid(uid);
- if (digest != null) {
- result.add(HexDump.toHexString(digest));
- added = true;
- }
- }
- if (!added) {
+ byte[] digest = getDigestFromUid(apps.get(i).uid);
+ if (digest != null) {
+ result.add(HexDump.toHexString(digest));
+ } else {
Slog.e(TAG, "Cannot get digest from uid: " + apps.get(i).uid
+ ",pkg: " + apps.get(i).packageName);
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index d5b2ee3..d112c02 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -782,18 +782,8 @@
@Override
public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id,
int uid, int initialPid, String message, int userId) {
- Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
- + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")");
cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
REASON_ERROR, null);
- long ident = Binder.clearCallingIdentity();
- try {
- ActivityManager.getService().crashApplication(uid, initialPid, pkg, -1,
- "Bad notification posted from package " + pkg
- + ": " + message);
- } catch (RemoteException e) {
- }
- Binder.restoreCallingIdentity(ident);
}
@Override
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index fb81ebf..fde13ac 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -312,12 +312,14 @@
return;
}
- // For backwards compatibility we accept match based on first signature only in the case
- // of multiply-signed packagse
+ // For backwards compatibility we accept match based on any signature, since we may have
+ // recorded only the first for multiply-signed packages
final String[] signaturesSha256Digests =
PackageUtils.computeSignaturesSha256Digests(pkg.mSigningDetails.signatures);
- if (signaturesSha256Digests[0].equals(currentCookieSha256)) {
- return;
+ for (String s : signaturesSha256Digests) {
+ if (s.equals(currentCookieSha256)) {
+ return;
+ }
}
// Sorry, you are out of luck - different signatures - nuke data
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 6ee4b5c..40c179f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -11499,6 +11499,8 @@
a.info.dataDir = pkg.applicationInfo.dataDir;
a.info.deviceProtectedDataDir = pkg.applicationInfo.deviceProtectedDataDir;
a.info.credentialProtectedDataDir = pkg.applicationInfo.credentialProtectedDataDir;
+ a.info.primaryCpuAbi = pkg.applicationInfo.primaryCpuAbi;
+ a.info.secondaryCpuAbi = pkg.applicationInfo.secondaryCpuAbi;
a.info.nativeLibraryDir = pkg.applicationInfo.nativeLibraryDir;
a.info.secondaryNativeLibraryDir = pkg.applicationInfo.secondaryNativeLibraryDir;
mInstrumentation.put(a.getComponentName(), a);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index bba7772..61ce062 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1278,6 +1278,7 @@
if (mContentInsetsChanged
|| mVisibleInsetsChanged
+ || mStableInsetsChanged
|| winAnimator.mSurfaceResized
|| mOutsetsChanged
|| mFrameSizeChanged
@@ -1701,12 +1702,17 @@
return changed;
}
- if (visible != isVisibleNow()) {
- if (!runningAppAnimation) {
+ final boolean isVisibleNow = isVisibleNow();
+ if (visible != isVisibleNow) {
+ // Run exit animation if:
+ // 1. App visibility and WS visibility are different
+ // 2. App is not running an animation
+ // 3. WS is currently visible
+ if (!runningAppAnimation && isVisibleNow) {
final AccessibilityController accessibilityController =
mService.mAccessibilityController;
- final int winTransit = visible ? TRANSIT_ENTER : TRANSIT_EXIT;
- mWinAnimator.applyAnimationLocked(winTransit, visible);
+ final int winTransit = TRANSIT_EXIT;
+ mWinAnimator.applyAnimationLocked(winTransit, false /* isEntrance */);
//TODO (multidisplay): Magnification is supported only for the default
if (accessibilityController != null && getDisplayId() == DEFAULT_DISPLAY) {
accessibilityController.onWindowTransitionLocked(this, winTransit);
diff --git a/services/core/jni/BroadcastRadio/Tuner.cpp b/services/core/jni/BroadcastRadio/Tuner.cpp
index a04697f..9c2e1e5 100644
--- a/services/core/jni/BroadcastRadio/Tuner.cpp
+++ b/services/core/jni/BroadcastRadio/Tuner.cpp
@@ -26,7 +26,6 @@
#include <binder/IPCThreadState.h>
#include <broadcastradio-utils-1x/Utils.h>
#include <core_jni_helpers.h>
-#include <media/AudioSystem.h>
#include <nativehelper/JNIHelp.h>
#include <utils/Log.h>
@@ -70,8 +69,6 @@
} Tuner;
} gjni;
-static const char* const kAudioDeviceName = "Radio tuner source";
-
class HalDeathRecipient : public hidl_death_recipient {
wp<V1_1::ITunerCallback> mTunerCallback;
@@ -154,20 +151,6 @@
return V1_1::IBroadcastRadio::castFrom(halModule).withDefault(nullptr);
}
-// TODO(b/62713378): implement support for multiple tuners open at the same time
-static void notifyAudioService(TunerContext& ctx, bool connected) {
- if (!ctx.mWithAudio) return;
- if (ctx.mIsAudioConnected == connected) return;
- ctx.mIsAudioConnected = connected;
-
- ALOGD("Notifying AudioService about new state: %d", connected);
- auto token = IPCThreadState::self()->clearCallingIdentity();
- AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_IN_FM_TUNER,
- connected ? AUDIO_POLICY_DEVICE_STATE_AVAILABLE : AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
- nullptr, kAudioDeviceName);
- IPCThreadState::self()->restoreCallingIdentity(token);
-}
-
void assignHalInterfaces(JNIEnv *env, JavaRef<jobject> const &jTuner,
sp<V1_0::IBroadcastRadio> halModule, sp<V1_0::ITuner> halTuner) {
ALOGV("%s(%p)", __func__, halTuner.get());
@@ -193,8 +176,6 @@
ctx.mHalDeathRecipient = new HalDeathRecipient(getNativeCallback(env, jTuner));
halTuner->linkToDeath(ctx.mHalDeathRecipient, 0);
-
- notifyAudioService(ctx, true);
}
static sp<V1_0::ITuner> getHalTuner(const TunerContext& ctx) {
@@ -236,8 +217,6 @@
ALOGI("Closing tuner %p", ctx.mHalTuner.get());
- notifyAudioService(ctx, false);
-
ctx.mHalTuner->unlinkToDeath(ctx.mHalDeathRecipient);
ctx.mHalDeathRecipient = nullptr;
@@ -280,14 +259,6 @@
return convert::BandConfigFromHal(env, halConfig, region).release();
}
-static void nativeSetMuted(JNIEnv *env, jobject obj, jlong nativeContext, bool mute) {
- ALOGV("%s(%d)", __func__, mute);
- lock_guard<mutex> lk(gContextMutex);
- auto& ctx = getNativeContext(nativeContext);
-
- notifyAudioService(ctx, !mute);
-}
-
static void nativeStep(JNIEnv *env, jobject obj, jlong nativeContext,
bool directionDown, bool skipSubChannel) {
ALOGV("%s", __func__);
@@ -467,7 +438,6 @@
(void*)nativeSetConfiguration },
{ "nativeGetConfiguration", "(JI)Landroid/hardware/radio/RadioManager$BandConfig;",
(void*)nativeGetConfiguration },
- { "nativeSetMuted", "(JZ)V", (void*)nativeSetMuted },
{ "nativeStep", "(JZZ)V", (void*)nativeStep },
{ "nativeScan", "(JZZ)V", (void*)nativeScan },
{ "nativeTune", "(JLandroid/hardware/radio/ProgramSelector;)V", (void*)nativeTune },
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 5519d22..74b40ba 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1111,45 +1111,47 @@
}
traceEnd();
- if (context.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_WIFI)) {
- // Wifi Service must be started first for wifi-related services.
- traceBeginAndSlog("StartWifi");
- mSystemServiceManager.startService(WIFI_SERVICE_CLASS);
- traceEnd();
- traceBeginAndSlog("StartWifiScanning");
- mSystemServiceManager.startService(
- "com.android.server.wifi.scanner.WifiScanningService");
- traceEnd();
- }
+ if (!mOnlyCore) {
+ if (context.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_WIFI)) {
+ // Wifi Service must be started first for wifi-related services.
+ traceBeginAndSlog("StartWifi");
+ mSystemServiceManager.startService(WIFI_SERVICE_CLASS);
+ traceEnd();
+ traceBeginAndSlog("StartWifiScanning");
+ mSystemServiceManager.startService(
+ "com.android.server.wifi.scanner.WifiScanningService");
+ traceEnd();
+ }
- if (context.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_WIFI_RTT)) {
- traceBeginAndSlog("StartRttService");
- mSystemServiceManager.startService(
- "com.android.server.wifi.rtt.RttService");
- traceEnd();
- }
+ if (context.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_WIFI_RTT)) {
+ traceBeginAndSlog("StartRttService");
+ mSystemServiceManager.startService(
+ "com.android.server.wifi.rtt.RttService");
+ traceEnd();
+ }
- if (context.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_WIFI_AWARE)) {
- traceBeginAndSlog("StartWifiAware");
- mSystemServiceManager.startService(WIFI_AWARE_SERVICE_CLASS);
- traceEnd();
- }
+ if (context.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_WIFI_AWARE)) {
+ traceBeginAndSlog("StartWifiAware");
+ mSystemServiceManager.startService(WIFI_AWARE_SERVICE_CLASS);
+ traceEnd();
+ }
- if (context.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_WIFI_DIRECT)) {
- traceBeginAndSlog("StartWifiP2P");
- mSystemServiceManager.startService(WIFI_P2P_SERVICE_CLASS);
- traceEnd();
- }
+ if (context.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_WIFI_DIRECT)) {
+ traceBeginAndSlog("StartWifiP2P");
+ mSystemServiceManager.startService(WIFI_P2P_SERVICE_CLASS);
+ traceEnd();
+ }
- if (context.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_LOWPAN)) {
- traceBeginAndSlog("StartLowpan");
- mSystemServiceManager.startService(LOWPAN_SERVICE_CLASS);
- traceEnd();
+ if (context.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_LOWPAN)) {
+ traceBeginAndSlog("StartLowpan");
+ mSystemServiceManager.startService(LOWPAN_SERVICE_CLASS);
+ traceEnd();
+ }
}
if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_ETHERNET) ||
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
index 96f8160..2dc3510 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
@@ -25,6 +25,7 @@
import static org.mockito.Mockito.when;
import android.app.IActivityManager;
+import android.app.KeyguardManager;
import android.app.NotificationManager;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManagerInternal;
@@ -102,7 +103,8 @@
LocalServices.addService(DevicePolicyManagerInternal.class, mDevicePolicyManagerInternal);
mContext = new MockLockSettingsContext(getContext(), mUserManager, mNotificationManager,
- mDevicePolicyManager, mock(StorageManager.class), mock(TrustManager.class));
+ mDevicePolicyManager, mock(StorageManager.class), mock(TrustManager.class),
+ mock(KeyguardManager.class));
mStorage = new LockSettingsStorageTestable(mContext,
new File(getContext().getFilesDir(), "locksettings"));
File storageDir = mStorage.mStorageDir;
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
index 237091d..6e1f357 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
@@ -20,6 +20,7 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import android.app.KeyguardManager;
import android.app.NotificationManager;
import android.app.admin.DevicePolicyManager;
import android.app.trust.TrustManager;
@@ -79,7 +80,7 @@
MockLockSettingsContext context = new MockLockSettingsContext(getContext(), mockUserManager,
mock(NotificationManager.class), mock(DevicePolicyManager.class),
- mock(StorageManager.class), mock(TrustManager.class));
+ mock(StorageManager.class), mock(TrustManager.class), mock(KeyguardManager.class));
mStorage = new LockSettingsStorageTestable(context,
new File(getContext().getFilesDir(), "locksettings"));
mStorage.setDatabaseOnCreateCallback(new LockSettingsStorage.Callback() {
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/MockLockSettingsContext.java b/services/tests/servicestests/src/com/android/server/locksettings/MockLockSettingsContext.java
index 3ad30f3..b332532 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/MockLockSettingsContext.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/MockLockSettingsContext.java
@@ -16,6 +16,7 @@
package com.android.server.locksettings;
+import android.app.KeyguardManager;
import android.app.NotificationManager;
import android.app.admin.DevicePolicyManager;
import android.app.trust.TrustManager;
@@ -32,16 +33,19 @@
private DevicePolicyManager mDevicePolicyManager;
private StorageManager mStorageManager;
private TrustManager mTrustManager;
+ private KeyguardManager mKeyguardManager;
public MockLockSettingsContext(Context base, UserManager userManager,
NotificationManager notificationManager, DevicePolicyManager devicePolicyManager,
- StorageManager storageManager, TrustManager trustManager) {
+ StorageManager storageManager, TrustManager trustManager,
+ KeyguardManager keyguardManager) {
super(base);
mUserManager = userManager;
mNotificationManager = notificationManager;
mDevicePolicyManager = devicePolicyManager;
mStorageManager = storageManager;
mTrustManager = trustManager;
+ mKeyguardManager = keyguardManager;
}
@Override
@@ -56,6 +60,8 @@
return mStorageManager;
} else if (TRUST_SERVICE.equals(name)) {
return mTrustManager;
+ } else if (KEYGUARD_SERVICE.equals(name)) {
+ return mKeyguardManager;
} else {
throw new RuntimeException("System service not mocked: " + name);
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
index e9f9800..142b950 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
@@ -217,6 +217,38 @@
verify(mAuthSecretService, never()).primaryUserCredential(any(ArrayList.class));
}
+ public void testNoSyntheticPasswordOrCredentialDoesNotPassAuthSecret() throws RemoteException {
+ // Setting null doesn't create a synthetic password
+ initializeCredentialUnderSP(null, PRIMARY_USER_ID);
+
+ reset(mAuthSecretService);
+ mService.onUnlockUser(PRIMARY_USER_ID);
+ mService.mHandler.runWithScissors(() -> {}, 0 /*now*/); // Flush runnables on handler
+ verify(mAuthSecretService, never()).primaryUserCredential(any(ArrayList.class));
+ }
+
+ public void testSyntheticPasswordAndCredentialDoesNotPassAuthSecret() throws RemoteException {
+ final String PASSWORD = "passwordForASyntheticPassword";
+ initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
+
+ reset(mAuthSecretService);
+ mService.onUnlockUser(PRIMARY_USER_ID);
+ mService.mHandler.runWithScissors(() -> {}, 0 /*now*/); // Flush runnables on handler
+ verify(mAuthSecretService, never()).primaryUserCredential(any(ArrayList.class));
+ }
+
+ public void testSyntheticPasswordButNoCredentialPassesAuthSecret() throws RemoteException {
+ final String PASSWORD = "getASyntheticPassword";
+ initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
+ mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, PASSWORD,
+ PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
+
+ reset(mAuthSecretService);
+ mService.onUnlockUser(PRIMARY_USER_ID);
+ mService.mHandler.runWithScissors(() -> {}, 0 /*now*/); // Flush runnables on handler
+ verify(mAuthSecretService).primaryUserCredential(any(ArrayList.class));
+ }
+
public void testManagedProfileUnifiedChallengeMigration() throws RemoteException {
final String UnifiedPassword = "testManagedProfileUnifiedChallengeMigration-pwd";
disableSyntheticPassword();
diff --git a/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistLoggingHandlerTests.java b/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistLoggingHandlerTests.java
index a38b353..8399dac 100644
--- a/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistLoggingHandlerTests.java
+++ b/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistLoggingHandlerTests.java
@@ -63,8 +63,10 @@
private static final String APK_A = "A.apk";
private static final String APK_B = "B.apk";
+ private static final String APK_C = "C.apk";
private static final String APK_A_CONTENT = "AAA";
private static final String APK_B_CONTENT = "BBB";
+ private static final String APK_C_CONTENT = "CCC";
// Sha256 of "AAA"
private static final String APK_A_CONTENT_HASH =
"CB1AD2119D8FAFB69566510EE712661F9F14B83385006EF92AEC47F523A38358";
@@ -120,8 +122,9 @@
return result;
}).when(mockPackageManager).getInstalledApplications(anyInt());
- // Uid 1 app with is installed in primary user and package name is "A"
- // Uid 2 app is installed in secondary user and package name is "B"
+ // Uid 1 app is installed in primary user only and package name is "A"
+ // Uid 2 app is installed in both primary user and secondary user, package name is "B"
+ // Uid 3 app is installed in secondary user and package name is "C"
doAnswer((InvocationOnMock invocation) -> {
int uid = (int) invocation.getArguments()[0];
if (uid == 1) {
@@ -129,9 +132,13 @@
} else if (uid == 1000001) {
return null;
} else if (uid == 2) {
- return null;
+ return new String[]{"B"};
} else if (uid == 1000002) {
return new String[]{"B"};
+ } else if (uid == 3) {
+ return null;
+ } else if (uid == 1000002) {
+ return new String[]{"C"};
}
return null;
}).when(mockPackageManager).getPackagesForUid(anyInt());
diff --git a/telephony/java/android/telephony/UiccSlotInfo.java b/telephony/java/android/telephony/UiccSlotInfo.java
index 125161d..a39992b 100644
--- a/telephony/java/android/telephony/UiccSlotInfo.java
+++ b/telephony/java/android/telephony/UiccSlotInfo.java
@@ -148,7 +148,7 @@
UiccSlotInfo that = (UiccSlotInfo) obj;
return (mIsActive == that.mIsActive)
&& (mIsEuicc == that.mIsEuicc)
- && (mCardId == that.mCardId)
+ && (Objects.equals(mCardId, that.mCardId))
&& (mCardStateInfo == that.mCardStateInfo)
&& (mLogicalSlotIdx == that.mLogicalSlotIdx)
&& (mIsExtendedApduSupported == that.mIsExtendedApduSupported);
diff --git a/tests/permission/src/com/android/framework/permission/tests/ServiceManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/ServiceManagerPermissionTests.java
index 0504c79..dcbbdbb 100644
--- a/tests/permission/src/com/android/framework/permission/tests/ServiceManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/ServiceManagerPermissionTests.java
@@ -18,6 +18,7 @@
import com.android.internal.os.BinderInternal;
+import android.app.AppOpsManager;
import android.os.Binder;
import android.os.IPermissionController;
import android.os.RemoteException;
@@ -49,11 +50,17 @@
public void testSetPermissionController() {
try {
IPermissionController pc = new IPermissionController.Stub() {
+ @Override
public boolean checkPermission(java.lang.String permission, int pid, int uid) {
return true;
}
@Override
+ public int noteOp(String op, int uid, String packageName) {
+ return AppOpsManager.MODE_ALLOWED;
+ }
+
+ @Override
public String[] getPackagesForUid(int uid) {
return new String[0];
}