Merge "Eliminate native/JNI/callback USB Descriptor parsing mechanism"
diff --git a/Android.mk b/Android.mk
index 1ed8a25..a7cb362 100644
--- a/Android.mk
+++ b/Android.mk
@@ -218,6 +218,7 @@
core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl \
core/java/android/hardware/location/IContextHubCallback.aidl \
core/java/android/hardware/location/IContextHubService.aidl \
+ core/java/android/hardware/location/IContextHubTransactionCallback.aidl \
core/java/android/hardware/radio/IRadioService.aidl \
core/java/android/hardware/radio/ITuner.aidl \
core/java/android/hardware/radio/ITunerCallback.aidl \
diff --git a/api/current.txt b/api/current.txt
index 5a947dd..7074de5 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -484,6 +484,7 @@
field public static final int detailSocialSummary = 16843428; // 0x10102a4
field public static final int detailsElementBackground = 16843598; // 0x101034e
field public static final int dial = 16843010; // 0x1010102
+ field public static final int dialogCornerRadius = 16844145; // 0x1010571
field public static final int dialogIcon = 16843252; // 0x10101f4
field public static final int dialogLayout = 16843255; // 0x10101f7
field public static final int dialogMessage = 16843251; // 0x10101f3
@@ -39924,8 +39925,8 @@
field public static final java.lang.String KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT = "duration_blocking_disabled_after_emergency_int";
field public static final java.lang.String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool";
field public static final java.lang.String KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL = "editable_voicemail_number_bool";
- field public static final java.lang.String KEY_ENABLE_APPS_STRING_ARRAY = "enable_apps_string_array";
field public static final java.lang.String KEY_EDITABLE_VOICEMAIL_NUMBER_SETTING_BOOL = "editable_voicemail_number_setting_bool";
+ field public static final java.lang.String KEY_ENABLE_APPS_STRING_ARRAY = "enable_apps_string_array";
field public static final java.lang.String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool";
field public static final java.lang.String KEY_FORCE_HOME_NETWORK_BOOL = "force_home_network_bool";
field public static final java.lang.String KEY_GSM_DTMF_TONE_DELAY_INT = "gsm_dtmf_tone_delay_int";
diff --git a/api/system-current.txt b/api/system-current.txt
index c0d106f..af15a00 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -88,6 +88,7 @@
field public static final java.lang.String CAPTURE_SECURE_VIDEO_OUTPUT = "android.permission.CAPTURE_SECURE_VIDEO_OUTPUT";
field public static final java.lang.String CAPTURE_TV_INPUT = "android.permission.CAPTURE_TV_INPUT";
field public static final java.lang.String CAPTURE_VIDEO_OUTPUT = "android.permission.CAPTURE_VIDEO_OUTPUT";
+ field public static final java.lang.String CHANGE_APP_IDLE_STATE = "android.permission.CHANGE_APP_IDLE_STATE";
field public static final java.lang.String CHANGE_COMPONENT_ENABLED_STATE = "android.permission.CHANGE_COMPONENT_ENABLED_STATE";
field public static final java.lang.String CHANGE_CONFIGURATION = "android.permission.CHANGE_CONFIGURATION";
field public static final java.lang.String CHANGE_DEVICE_IDLE_TEMP_WHITELIST = "android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST";
@@ -616,6 +617,7 @@
field public static final int detailSocialSummary = 16843428; // 0x10102a4
field public static final int detailsElementBackground = 16843598; // 0x101034e
field public static final int dial = 16843010; // 0x1010102
+ field public static final int dialogCornerRadius = 16844145; // 0x1010571
field public static final int dialogIcon = 16843252; // 0x10101f4
field public static final int dialogLayout = 16843255; // 0x10101f7
field public static final int dialogMessage = 16843251; // 0x10101f3
@@ -7676,6 +7678,7 @@
method public java.util.List<android.app.usage.ConfigurationStats> queryConfigurations(int, long, long);
method public android.app.usage.UsageEvents queryEvents(long, long);
method public java.util.List<android.app.usage.UsageStats> queryUsageStats(int, long, long);
+ method public void setAppStandbyBucket(java.lang.String, int);
method public void whitelistAppTemporarily(java.lang.String, long, android.os.UserHandle);
field public static final int INTERVAL_BEST = 4; // 0x4
field public static final int INTERVAL_DAILY = 0; // 0x0
@@ -10234,6 +10237,7 @@
field public static final java.lang.String EXTRA_PROCESS_TEXT_READONLY = "android.intent.extra.PROCESS_TEXT_READONLY";
field public static final java.lang.String EXTRA_QUICK_VIEW_FEATURES = "android.intent.extra.QUICK_VIEW_FEATURES";
field public static final java.lang.String EXTRA_QUIET_MODE = "android.intent.extra.QUIET_MODE";
+ field public static final java.lang.String EXTRA_REASON = "android.intent.extra.REASON";
field public static final java.lang.String EXTRA_REFERRER = "android.intent.extra.REFERRER";
field public static final java.lang.String EXTRA_REFERRER_NAME = "android.intent.extra.REFERRER_NAME";
field public static final java.lang.String EXTRA_REMOTE_CALLBACK = "android.intent.extra.REMOTE_CALLBACK";
@@ -43440,8 +43444,8 @@
field public static final java.lang.String KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT = "duration_blocking_disabled_after_emergency_int";
field public static final java.lang.String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool";
field public static final java.lang.String KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL = "editable_voicemail_number_bool";
- field public static final java.lang.String KEY_ENABLE_APPS_STRING_ARRAY = "enable_apps_string_array";
field public static final java.lang.String KEY_EDITABLE_VOICEMAIL_NUMBER_SETTING_BOOL = "editable_voicemail_number_setting_bool";
+ field public static final java.lang.String KEY_ENABLE_APPS_STRING_ARRAY = "enable_apps_string_array";
field public static final java.lang.String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool";
field public static final java.lang.String KEY_FORCE_HOME_NETWORK_BOOL = "force_home_network_bool";
field public static final java.lang.String KEY_GSM_DTMF_TONE_DELAY_INT = "gsm_dtmf_tone_delay_int";
diff --git a/api/test-current.txt b/api/test-current.txt
index 9c0bc92..0bc0cd9 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -484,6 +484,7 @@
field public static final int detailSocialSummary = 16843428; // 0x10102a4
field public static final int detailsElementBackground = 16843598; // 0x101034e
field public static final int dial = 16843010; // 0x1010102
+ field public static final int dialogCornerRadius = 16844145; // 0x1010571
field public static final int dialogIcon = 16843252; // 0x10101f4
field public static final int dialogLayout = 16843255; // 0x10101f7
field public static final int dialogMessage = 16843251; // 0x10101f3
@@ -3873,6 +3874,7 @@
method public void resizeStack(int, android.graphics.Rect) throws java.lang.SecurityException;
method public deprecated void restartPackage(java.lang.String);
method public void setTaskWindowingMode(int, int, boolean) throws java.lang.SecurityException;
+ method public void setTaskWindowingModeSplitScreenPrimary(int, int, boolean, boolean, android.graphics.Rect) throws java.lang.SecurityException;
method public static void setVrThread(int);
method public void setWatchHeapLimit(long);
method public static boolean supportsMultiWindow(android.content.Context);
@@ -3886,6 +3888,8 @@
field public static final int MOVE_TASK_WITH_HOME = 1; // 0x1
field public static final int RECENT_IGNORE_UNAVAILABLE = 2; // 0x2
field public static final int RECENT_WITH_EXCLUDED = 1; // 0x1
+ field public static final int SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT = 1; // 0x1
+ field public static final int SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT = 0; // 0x0
}
public static class ActivityManager.AppTask {
@@ -40318,8 +40322,8 @@
field public static final java.lang.String KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT = "duration_blocking_disabled_after_emergency_int";
field public static final java.lang.String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool";
field public static final java.lang.String KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL = "editable_voicemail_number_bool";
- field public static final java.lang.String KEY_ENABLE_APPS_STRING_ARRAY = "enable_apps_string_array";
field public static final java.lang.String KEY_EDITABLE_VOICEMAIL_NUMBER_SETTING_BOOL = "editable_voicemail_number_setting_bool";
+ field public static final java.lang.String KEY_ENABLE_APPS_STRING_ARRAY = "enable_apps_string_array";
field public static final java.lang.String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool";
field public static final java.lang.String KEY_FORCE_HOME_NETWORK_BOOL = "force_home_network_bool";
field public static final java.lang.String KEY_GSM_DTMF_TONE_DELAY_INT = "gsm_dtmf_tone_delay_int";
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index 54ade35..c5805fbb 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -29,7 +29,8 @@
src/config/ConfigKey.cpp \
src/config/ConfigListener.cpp \
src/config/ConfigManager.cpp \
- src/external/KernelWakelockPuller.cpp \
+ src/external/StatsCompanionServicePuller.cpp \
+ src/external/ResourcePowerManagerPuller.cpp \
src/external/StatsPullerManager.cpp \
src/logd/LogEvent.cpp \
src/logd/LogListener.cpp \
@@ -71,7 +72,15 @@
libutils \
libservices \
libandroidfw \
- libprotoutil
+ libprotoutil \
+ libstatslog \
+ libhardware \
+ libhardware_legacy \
+ libhidlbase \
+ libhidltransport \
+ libhwbinder \
+ android.hardware.power@1.0 \
+ android.hardware.power@1.1
# =========
# statsd
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index edb1a0f..11c5de1 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -373,12 +373,15 @@
status_t StatsService::cmd_print_pulled_metrics(FILE* out, const Vector<String8>& args) {
int s = atoi(args[1].c_str());
- auto stats = m_stats_puller_manager.Pull(s, time(nullptr));
- for (const auto& it : stats) {
- fprintf(out, "Pull from %d: %s\n", s, it->ToString().c_str());
+ vector<shared_ptr<LogEvent> > stats;
+ if (mStatsPullerManager.Pull(s, &stats)) {
+ for (const auto& it : stats) {
+ fprintf(out, "Pull from %d: %s\n", s, it->ToString().c_str());
+ }
+ fprintf(out, "Pull from %d: Received %zu elements\n", s, stats.size());
+ return NO_ERROR;
}
- fprintf(out, "Pull from %d: Received %zu elements\n", s, stats.size());
- return NO_ERROR;
+ return UNKNOWN_ERROR;
}
Status StatsService::informAllUidData(const vector<int32_t>& uid, const vector<int32_t>& version,
@@ -440,7 +443,7 @@
"Only system uid can call informPollAlarmFired");
}
- m_stats_puller_manager.OnAlarmFired();
+ mStatsPullerManager.OnAlarmFired();
if (DEBUG) ALOGD("StatsService::informPollAlarmFired succeeded");
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 3930d31..1d7e5a61 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -157,7 +157,7 @@
/**
* Fetches external metrics.
*/
- StatsPullerManager& m_stats_puller_manager = StatsPullerManager::GetInstance();
+ StatsPullerManager& mStatsPullerManager = StatsPullerManager::GetInstance();
/**
* Tracks the configurations that have been passed to statsd.
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index 8812719..890f44b 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -139,7 +139,7 @@
int UID_PROCESS_STATE_TAG_ID = 27;
int UID_PROCESS_STATE_UID_KEY = 1;
- int KERNEL_WAKELOCK_TAG_ID = 41;
+ int KERNEL_WAKELOCK_TAG_ID = 1004;
int KERNEL_WAKELOCK_NAME_KEY = 4;
// Count Screen ON events.
@@ -301,6 +301,12 @@
keyValueMatcher->mutable_key_matcher()->set_key(WAKE_LOCK_STATE_KEY);
keyValueMatcher->set_eq_int(WAKE_LOCK_RELEASE_VALUE);
+ // pulled events
+ eventMatcher = config.add_log_entry_matcher();
+ eventMatcher->set_name("KERNEL_WAKELOCK");
+ simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
+ simpleLogEntryMatcher->set_tag(KERNEL_WAKELOCK_TAG_ID);
+
// Conditions.............
Condition* condition = config.add_condition();
condition->set_name("SCREEN_IS_ON");
diff --git a/cmds/statsd/src/external/ResourcePowerManagerPuller.cpp b/cmds/statsd/src/external/ResourcePowerManagerPuller.cpp
new file mode 100644
index 0000000..38953f1
--- /dev/null
+++ b/cmds/statsd/src/external/ResourcePowerManagerPuller.cpp
@@ -0,0 +1,165 @@
+/*
+ * 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.
+ */
+
+#define DEBUG true // STOPSHIP if true
+#include "Log.h"
+
+#include <android/hardware/power/1.0/IPower.h>
+#include <android/hardware/power/1.1/IPower.h>
+#include <fcntl.h>
+#include <hardware/power.h>
+#include <hardware_legacy/power.h>
+#include <inttypes.h>
+#include <semaphore.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "external/ResourcePowerManagerPuller.h"
+#include "external/StatsPuller.h"
+
+#include "logd/LogEvent.h"
+
+using android::hardware::hidl_vec;
+using android::hardware::power::V1_0::IPower;
+using android::hardware::power::V1_0::PowerStatePlatformSleepState;
+using android::hardware::power::V1_0::PowerStateVoter;
+using android::hardware::power::V1_0::Status;
+using android::hardware::power::V1_1::PowerStateSubsystem;
+using android::hardware::power::V1_1::PowerStateSubsystemSleepState;
+using android::hardware::Return;
+using android::hardware::Void;
+
+using std::make_shared;
+using std::shared_ptr;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+sp<android::hardware::power::V1_0::IPower> gPowerHalV1_0 = nullptr;
+sp<android::hardware::power::V1_1::IPower> gPowerHalV1_1 = nullptr;
+std::mutex gPowerHalMutex;
+bool gPowerHalExists = true;
+
+static const int power_state_platform_sleep_state_tag = 1011;
+static const int power_state_voter_tag = 1012;
+static const int power_state_subsystem_state_tag = 1013;
+
+bool getPowerHal() {
+ if (gPowerHalExists && gPowerHalV1_0 == nullptr) {
+ gPowerHalV1_0 = android::hardware::power::V1_0::IPower::getService();
+ if (gPowerHalV1_0 != nullptr) {
+ gPowerHalV1_1 = android::hardware::power::V1_1::IPower::castFrom(gPowerHalV1_0);
+ ALOGI("Loaded power HAL service");
+ } else {
+ ALOGW("Couldn't load power HAL service");
+ gPowerHalExists = false;
+ }
+ }
+ return gPowerHalV1_0 != nullptr;
+}
+
+bool ResourcePowerManagerPuller::Pull(const int tagId, vector<shared_ptr<LogEvent>>* data) {
+ std::lock_guard<std::mutex> lock(gPowerHalMutex);
+
+ if (!getPowerHal()) {
+ ALOGE("Power Hal not loaded");
+ return false;
+ }
+
+ data->clear();
+ Return<void> ret = gPowerHalV1_0->getPlatformLowPowerStats(
+ [&data](hidl_vec<PowerStatePlatformSleepState> states, Status status) {
+
+ if (status != Status::SUCCESS) return;
+
+ for (size_t i = 0; i < states.size(); i++) {
+ const PowerStatePlatformSleepState& state = states[i];
+
+ auto statePtr = make_shared<LogEvent>(power_state_platform_sleep_state_tag);
+ auto elemList = statePtr->GetAndroidLogEventList();
+ *elemList << state.name;
+ *elemList << state.residencyInMsecSinceBoot;
+ *elemList << state.totalTransitions;
+ *elemList << state.supportedOnlyInSuspend;
+ data->push_back(statePtr);
+
+ VLOG("powerstate: %s, %lld, %lld, %d", state.name.c_str(),
+ (long long)state.residencyInMsecSinceBoot,
+ (long long)state.totalTransitions, state.supportedOnlyInSuspend ? 1 : 0);
+ for (auto voter : state.voters) {
+ auto voterPtr = make_shared<LogEvent>(power_state_voter_tag);
+ auto elemList = voterPtr->GetAndroidLogEventList();
+ *elemList << state.name;
+ *elemList << voter.name;
+ *elemList << voter.totalTimeInMsecVotedForSinceBoot;
+ *elemList << voter.totalNumberOfTimesVotedSinceBoot;
+ data->push_back(voterPtr);
+ VLOG("powerstatevoter: %s, %s, %lld, %lld", state.name.c_str(),
+ voter.name.c_str(), (long long)voter.totalTimeInMsecVotedForSinceBoot,
+ (long long)voter.totalNumberOfTimesVotedSinceBoot);
+ }
+ }
+ });
+ if (!ret.isOk()) {
+ ALOGE("getLowPowerStats() failed: power HAL service not available");
+ gPowerHalV1_0 = nullptr;
+ return false;
+ }
+
+ // Trying to cast to IPower 1.1, this will succeed only for devices supporting 1.1
+ sp<android::hardware::power::V1_1::IPower> gPowerHal_1_1 =
+ android::hardware::power::V1_1::IPower::castFrom(gPowerHalV1_0);
+ if (gPowerHal_1_1 != nullptr) {
+ ret = gPowerHal_1_1->getSubsystemLowPowerStats(
+ [&data](hidl_vec<PowerStateSubsystem> subsystems, Status status) {
+
+ if (status != Status::SUCCESS) return;
+
+ if (subsystems.size() > 0) {
+ for (size_t i = 0; i < subsystems.size(); i++) {
+ const PowerStateSubsystem& subsystem = subsystems[i];
+ for (size_t j = 0; j < subsystem.states.size(); j++) {
+ const PowerStateSubsystemSleepState& state = subsystem.states[j];
+ auto subsystemStatePtr =
+ make_shared<LogEvent>(power_state_subsystem_state_tag);
+ auto elemList = subsystemStatePtr->GetAndroidLogEventList();
+ *elemList << subsystem.name;
+ *elemList << state.name;
+ *elemList << state.residencyInMsecSinceBoot;
+ *elemList << state.totalTransitions;
+ *elemList << state.lastEntryTimestampMs;
+ *elemList << state.supportedOnlyInSuspend;
+ data->push_back(subsystemStatePtr);
+ VLOG("subsystemstate: %s, %s, %lld, %lld, %lld",
+ subsystem.name.c_str(), state.name.c_str(),
+ (long long)state.residencyInMsecSinceBoot,
+ (long long)state.totalTransitions,
+ (long long)state.lastEntryTimestampMs);
+ }
+ }
+ }
+ });
+ }
+ return true;
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/external/KernelWakelockPuller.h b/cmds/statsd/src/external/ResourcePowerManagerPuller.h
similarity index 78%
rename from cmds/statsd/src/external/KernelWakelockPuller.h
rename to cmds/statsd/src/external/ResourcePowerManagerPuller.h
index cc8059d..c396c12 100644
--- a/cmds/statsd/src/external/KernelWakelockPuller.h
+++ b/cmds/statsd/src/external/ResourcePowerManagerPuller.h
@@ -23,12 +23,12 @@
namespace os {
namespace statsd {
-class KernelWakelockPuller : public StatsPuller {
+/**
+ * Reads hal for sleep states
+ */
+class ResourcePowerManagerPuller : public StatsPuller {
public:
- // a number of stats need to be pulled from StatsCompanionService
- //
- const static int PULL_CODE_KERNEL_WAKELOCKS;
- vector<StatsLogEventWrapper> Pull() override;
+ bool Pull(const int tagId, vector<std::shared_ptr<LogEvent>>* data) override;
};
} // namespace statsd
diff --git a/cmds/statsd/src/external/KernelWakelockPuller.cpp b/cmds/statsd/src/external/StatsCompanionServicePuller.cpp
similarity index 63%
rename from cmds/statsd/src/external/KernelWakelockPuller.cpp
rename to cmds/statsd/src/external/StatsCompanionServicePuller.cpp
index 00259a8..8e96399 100644
--- a/cmds/statsd/src/external/KernelWakelockPuller.cpp
+++ b/cmds/statsd/src/external/StatsCompanionServicePuller.cpp
@@ -20,37 +20,49 @@
#include <android/os/IStatsCompanionService.h>
#include <binder/IPCThreadState.h>
#include <private/android_filesystem_config.h>
-#include "KernelWakelockPuller.h"
+#include "StatsCompanionServicePuller.h"
#include "StatsService.h"
using namespace android;
using namespace android::base;
using namespace android::binder;
using namespace android::os;
-using namespace std;
+using std::make_shared;
+using std::shared_ptr;
+using std::vector;
namespace android {
namespace os {
namespace statsd {
-const int KernelWakelockPuller::PULL_CODE_KERNEL_WAKELOCKS = 1004;
+const int kLogMsgHeaderSize = 28;
// The reading and parsing are implemented in Java. It is not difficult to port over. But for now
// let StatsCompanionService handle that and send the data back.
-vector<StatsLogEventWrapper> KernelWakelockPuller::Pull() {
+bool StatsCompanionServicePuller::Pull(const int tagId, vector<shared_ptr<LogEvent> >* data) {
sp<IStatsCompanionService> statsCompanion = StatsService::getStatsCompanionService();
vector<StatsLogEventWrapper> returned_value;
if (statsCompanion != NULL) {
- Status status = statsCompanion->pullData(KernelWakelockPuller::PULL_CODE_KERNEL_WAKELOCKS,
- &returned_value);
+ Status status = statsCompanion->pullData(tagId, &returned_value);
if (!status.isOk()) {
ALOGW("error pulling kernel wakelock");
+ return false;
+ }
+ data->clear();
+ for (const StatsLogEventWrapper& it : returned_value) {
+ log_msg tmp;
+ tmp.entry_v1.len = it.bytes.size();
+ // Manually set the header size to 28 bytes to match the pushed log events.
+ tmp.entry.hdr_size = kLogMsgHeaderSize;
+ // And set the received bytes starting after the 28 bytes reserved for header.
+ std::copy(it.bytes.begin(), it.bytes.end(), tmp.buf + kLogMsgHeaderSize);
+ data->push_back(make_shared<LogEvent>(tmp));
}
ALOGD("KernelWakelockPuller::pull succeeded!");
- return returned_value;
+ return true;
} else {
ALOGW("statsCompanion not found!");
- return returned_value;
+ return false;
}
}
diff --git a/cmds/statsd/src/external/KernelWakelockPuller.h b/cmds/statsd/src/external/StatsCompanionServicePuller.h
similarity index 78%
copy from cmds/statsd/src/external/KernelWakelockPuller.h
copy to cmds/statsd/src/external/StatsCompanionServicePuller.h
index cc8059d..3ff2274f 100644
--- a/cmds/statsd/src/external/KernelWakelockPuller.h
+++ b/cmds/statsd/src/external/StatsCompanionServicePuller.h
@@ -23,12 +23,9 @@
namespace os {
namespace statsd {
-class KernelWakelockPuller : public StatsPuller {
+class StatsCompanionServicePuller : public StatsPuller {
public:
- // a number of stats need to be pulled from StatsCompanionService
- //
- const static int PULL_CODE_KERNEL_WAKELOCKS;
- vector<StatsLogEventWrapper> Pull() override;
+ bool Pull(const int tagId, vector<std::shared_ptr<LogEvent> >* data) override;
};
} // namespace statsd
diff --git a/cmds/statsd/src/external/StatsPuller.h b/cmds/statsd/src/external/StatsPuller.h
index 774e7f0..940ad9c 100644
--- a/cmds/statsd/src/external/StatsPuller.h
+++ b/cmds/statsd/src/external/StatsPuller.h
@@ -19,6 +19,7 @@
#include <android/os/StatsLogEventWrapper.h>
#include <utils/String16.h>
#include <vector>
+#include "logd/LogEvent.h"
using android::os::StatsLogEventWrapper;
using std::vector;
@@ -31,7 +32,7 @@
public:
virtual ~StatsPuller(){};
- virtual vector<StatsLogEventWrapper> Pull() = 0;
+ virtual bool Pull(const int tagId, vector<std::shared_ptr<LogEvent>>* data) = 0;
};
} // namespace statsd
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index f45cb1c..003b5c4 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -21,89 +21,69 @@
#include <cutils/log.h>
#include <algorithm>
#include <climits>
-#include "KernelWakelockPuller.h"
+#include "ResourcePowerManagerPuller.h"
+#include "StatsCompanionServicePuller.h"
#include "StatsPullerManager.h"
#include "StatsService.h"
#include "logd/LogEvent.h"
+#include "statslog.h"
#include <iostream>
+using std::map;
using std::string;
using std::vector;
+using std::make_shared;
+using std::shared_ptr;
namespace android {
namespace os {
namespace statsd {
-const int kernel_wakelock = 1;
-const unordered_map<string, int> StatsPullerManager::kPullCodes({{"KERNEL_WAKELOCK",
- kernel_wakelock}});
-
StatsPullerManager::StatsPullerManager()
: mCurrentPullingInterval(LONG_MAX), mPullStartTimeMs(get_pull_start_time_ms()) {
- mPullers.insert({kernel_wakelock, make_unique<KernelWakelockPuller>()});
- mStatsCompanionService = get_stats_companion_service();
- if (mStatsCompanionService != nullptr) {
- mStatsCompanionService->cancelPullingAlarms();
- } else {
- VLOG("Failed to update pulling interval");
- }
+ shared_ptr<StatsPuller> statsCompanionServicePuller = make_shared<StatsCompanionServicePuller>();
+ shared_ptr <StatsPuller>
+ resourcePowerManagerPuller = make_shared<ResourcePowerManagerPuller>();
+
+ mPullers.insert({android::util::KERNEL_WAKELOCK_PULLED,
+ statsCompanionServicePuller});
+ mPullers.insert({android::util::WIFI_BYTES_TRANSFERRED,
+ statsCompanionServicePuller});
+ mPullers.insert({android::util::MOBILE_BYTES_TRANSFERRED,
+ statsCompanionServicePuller});
+ mPullers.insert({android::util::WIFI_BYTES_TRANSFERRED_BY_FG_BG,
+ statsCompanionServicePuller});
+ mPullers.insert({android::util::MOBILE_BYTES_TRANSFERRED_BY_FG_BG,
+ statsCompanionServicePuller});
+ mPullers.insert({android::util::POWER_STATE_PLATFORM_SLEEP_STATE_PULLED,
+ resourcePowerManagerPuller});
+ mPullers.insert({android::util::POWER_STATE_VOTER_PULLED,
+ resourcePowerManagerPuller});
+ mPullers.insert({android::util::POWER_STATE_SUBSYSTEM_SLEEP_STATE_PULLED,
+ resourcePowerManagerPuller});
+
+ mStatsCompanionService = StatsService::getStatsCompanionService();
}
-static const int log_msg_header_size = 28;
+ bool StatsPullerManager::Pull(int tagId, vector<shared_ptr<LogEvent>>* data) {
+ if (DEBUG) ALOGD("Initiating pulling %d", tagId);
-vector<shared_ptr<LogEvent>> StatsPullerManager::Pull(int pullCode, uint64_t timestampSec) {
- if (DEBUG) ALOGD("Initiating pulling %d", pullCode);
-
- vector<shared_ptr<LogEvent>> ret;
- auto itr = mPullers.find(pullCode);
- if (itr != mPullers.end()) {
- vector<StatsLogEventWrapper> outputs = itr->second->Pull();
- for (const StatsLogEventWrapper& it : outputs) {
- log_msg tmp;
- tmp.entry_v1.sec = timestampSec;
- tmp.entry_v1.nsec = 0;
- tmp.entry_v1.len = it.bytes.size();
- // Manually set the header size to 28 bytes to match the pushed log events.
- tmp.entry.hdr_size = log_msg_header_size;
- // And set the received bytes starting after the 28 bytes reserved for header.
- copy(it.bytes.begin(), it.bytes.end(), tmp.buf + log_msg_header_size);
- shared_ptr<LogEvent> evt = make_shared<LogEvent>(tmp);
- ret.push_back(evt);
+ if (mPullers.find(tagId) != mPullers.end()) {
+ return mPullers.find(tagId)->second->Pull(tagId, data);
+ } else {
+ ALOGD("Unknown tagId %d", tagId);
+ return false; // Return early since we don't know what to pull.
+ }
}
- return ret;
- } else {
- ALOGD("Unknown pull code %d", pullCode);
- return ret; // Return early since we don't know what to pull.
- }
-}
-
-sp<IStatsCompanionService> StatsPullerManager::get_stats_companion_service() {
- sp<IStatsCompanionService> statsCompanion = nullptr;
- // Get statscompanion service from service manager
- const sp<IServiceManager> sm(defaultServiceManager());
- if (sm != nullptr) {
- const String16 name("statscompanion");
- statsCompanion = interface_cast<IStatsCompanionService>(sm->checkService(name));
- if (statsCompanion == nullptr) {
- ALOGW("statscompanion service unavailable!");
- return nullptr;
- }
- }
- return statsCompanion;
-}
StatsPullerManager& StatsPullerManager::GetInstance() {
static StatsPullerManager instance;
return instance;
}
-int StatsPullerManager::GetPullCode(string atomName) {
- if (kPullCodes.find(atomName) != kPullCodes.end()) {
- return kPullCodes.find(atomName)->second;
- } else {
- return -1;
- }
+bool StatsPullerManager::PullerForMatcherExists(int tagId) {
+ return mPullers.find(tagId) != mPullers.end();
}
long StatsPullerManager::get_pull_start_time_ms() {
@@ -111,9 +91,9 @@
return time(nullptr) * 1000;
}
-void StatsPullerManager::RegisterReceiver(int pullCode, sp<PullDataReceiver> receiver, long intervalMs) {
+void StatsPullerManager::RegisterReceiver(int tagId, sp<PullDataReceiver> receiver, long intervalMs) {
AutoMutex _l(mReceiversLock);
- vector<ReceiverInfo>& receivers = mReceivers[pullCode];
+ vector<ReceiverInfo>& receivers = mReceivers[tagId];
for (auto it = receivers.begin(); it != receivers.end(); it++) {
if (it->receiver.get() == receiver.get()) {
VLOG("Receiver already registered of %d", (int)receivers.size());
@@ -135,20 +115,20 @@
VLOG("Failed to update pulling interval");
}
}
- VLOG("Puller for pullcode %d registered of %d", pullCode, (int)receivers.size());
+ VLOG("Puller for tagId %d registered of %d", tagId, (int)receivers.size());
}
-void StatsPullerManager::UnRegisterReceiver(int pullCode, sp<PullDataReceiver> receiver) {
+void StatsPullerManager::UnRegisterReceiver(int tagId, sp<PullDataReceiver> receiver) {
AutoMutex _l(mReceiversLock);
- if (mReceivers.find(pullCode) == mReceivers.end()) {
- VLOG("Unknown pull code or no receivers: %d", pullCode);
+ if (mReceivers.find(tagId) == mReceivers.end()) {
+ VLOG("Unknown pull code or no receivers: %d", tagId);
return;
}
- auto& receivers = mReceivers.find(pullCode)->second;
+ auto& receivers = mReceivers.find(tagId)->second;
for (auto it = receivers.begin(); it != receivers.end(); it++) {
if (receiver.get() == it->receiver.get()) {
receivers.erase(it);
- VLOG("Puller for pullcode %d unregistered of %d", pullCode, (int)receivers.size());
+ VLOG("Puller for tagId %d unregistered of %d", tagId, (int)receivers.size());
return;
}
}
@@ -176,10 +156,12 @@
}
for (const auto& pullInfo : needToPull) {
- const vector<shared_ptr<LogEvent>>& data = Pull(pullInfo.first, currentTimeMs/1000);
- for(const auto& receiverInfo : pullInfo.second) {
- receiverInfo->receiver->onDataPulled(data);
- receiverInfo->timeInfo.second = currentTimeMs;
+ vector<shared_ptr<LogEvent>> data;
+ if (Pull(pullInfo.first, &data)) {
+ for (const auto& receiverInfo : pullInfo.second) {
+ receiverInfo->receiver->onDataPulled(data);
+ receiverInfo->timeInfo.second = currentTimeMs;
+ }
}
}
}
diff --git a/cmds/statsd/src/external/StatsPullerManager.h b/cmds/statsd/src/external/StatsPullerManager.h
index e599b69..67580d6 100644
--- a/cmds/statsd/src/external/StatsPullerManager.h
+++ b/cmds/statsd/src/external/StatsPullerManager.h
@@ -37,44 +37,42 @@
public:
static StatsPullerManager& GetInstance();
- void RegisterReceiver(int pullCode, sp<PullDataReceiver> receiver, long intervalMs);
+ void RegisterReceiver(int tagId, sp<PullDataReceiver> receiver, long intervalMs);
- void UnRegisterReceiver(int pullCode, sp<PullDataReceiver> receiver);
+ void UnRegisterReceiver(int tagId, sp<PullDataReceiver> receiver);
- // We return a vector of shared_ptr since LogEvent's copy constructor is not available.
- vector<std::shared_ptr<LogEvent>> Pull(const int pullCode, const uint64_t timestampSec);
-
- // Translate metric name to pullCodes.
- // return -1 if no valid pullCode is found
- int GetPullCode(std::string metricName);
+ // Verify if we know how to pull for this matcher
+ bool PullerForMatcherExists(int tagId);
void OnAlarmFired();
+ bool Pull(const int pullCode, vector<std::shared_ptr<LogEvent>>* data);
+
private:
StatsPullerManager();
+ // use this to update alarm
sp<IStatsCompanionService> mStatsCompanionService = nullptr;
sp<IStatsCompanionService> get_stats_companion_service();
- std::unordered_map<int, std::unique_ptr<StatsPuller>> mPullers;
+ // mapping from simple matcher tagId to puller
+ std::map<int, std::shared_ptr<StatsPuller>> mPullers;
-
-
- // internal state of a bucket.
typedef struct {
// pull_interval_sec : last_pull_time_sec
std::pair<uint64_t, uint64_t> timeInfo;
sp<PullDataReceiver> receiver;
} ReceiverInfo;
+ // mapping from simple matcher tagId to receivers
std::map<int, std::vector<ReceiverInfo>> mReceivers;
Mutex mReceiversLock;
long mCurrentPullingInterval;
- // for value metrics, it is important for the buckets to be aligned to multiple of smallest
+ // for pulled metrics, it is important for the buckets to be aligned to multiple of smallest
// bucket size. All pulled metrics start pulling based on this time, so that they can be
// correctly attributed to the correct buckets. Pulled data attach a timestamp which is the
// request time.
@@ -83,10 +81,8 @@
long get_pull_start_time_ms();
LogEvent parse_pulled_data(String16 data);
-
- static const std::unordered_map<std::string, int> kPullCodes;
};
} // namespace statsd
} // namespace os
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 26a82cb..8220fcb 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -24,6 +24,7 @@
namespace os {
namespace statsd {
+using namespace android::util;
using std::ostringstream;
using std::string;
using android::util::ProtoOutputStream;
@@ -207,20 +208,20 @@
}
void LogEvent::ToProto(ProtoOutputStream& proto) const {
- long long atomToken = proto.start(TYPE_MESSAGE + mTagId);
+ long long atomToken = proto.start(FIELD_TYPE_MESSAGE | mTagId);
const size_t N = mElements.size();
for (size_t i=0; i<N; i++) {
const int key = i + 1;
const android_log_list_element& elem = mElements[i];
if (elem.type == EVENT_TYPE_INT) {
- proto.write(TYPE_INT32 + key, elem.data.int32);
+ proto.write(FIELD_TYPE_INT32 | key, elem.data.int32);
} else if (elem.type == EVENT_TYPE_LONG) {
- proto.write(TYPE_INT64 + key, (long long)elem.data.int64);
+ proto.write(FIELD_TYPE_INT64 | key, (long long)elem.data.int64);
} else if (elem.type == EVENT_TYPE_FLOAT) {
- proto.write(TYPE_FLOAT + key, elem.data.float32);
+ proto.write(FIELD_TYPE_FLOAT | key, elem.data.float32);
} else if (elem.type == EVENT_TYPE_STRING) {
- proto.write(TYPE_STRING + key, elem.data.string);
+ proto.write(FIELD_TYPE_STRING | key, elem.data.string);
}
}
proto.end(atomToken);
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index 9f8558d..71cb7717 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -24,6 +24,8 @@
#include <limits.h>
#include <stdlib.h>
+using namespace android::util;
+using android::util::ProtoOutputStream;
using std::map;
using std::string;
using std::unordered_map;
@@ -33,6 +35,27 @@
namespace os {
namespace statsd {
+// for StatsLogReport
+const int FIELD_ID_METRIC_ID = 1;
+const int FIELD_ID_START_REPORT_NANOS = 2;
+const int FIELD_ID_END_REPORT_NANOS = 3;
+const int FIELD_ID_COUNT_METRICS = 5;
+// for CountMetricDataWrapper
+const int FIELD_ID_DATA = 1;
+// for CountMetricData
+const int FIELD_ID_DIMENSION = 1;
+const int FIELD_ID_BUCKET_INFO = 2;
+// for KeyValuePair
+const int FIELD_ID_KEY = 1;
+const int FIELD_ID_VALUE_STR = 2;
+const int FIELD_ID_VALUE_INT = 3;
+const int FIELD_ID_VALUE_BOOL = 4;
+const int FIELD_ID_VALUE_FLOAT = 5;
+// for CountBucketInfo
+const int FIELD_ID_START_BUCKET_NANOS = 1;
+const int FIELD_ID_END_BUCKET_NANOS = 2;
+const int FIELD_ID_COUNT = 3;
+
// TODO: add back AnomalyTracker.
CountMetricProducer::CountMetricProducer(const CountMetric& metric, const int conditionIndex,
const sp<ConditionWizard>& wizard)
@@ -66,6 +89,8 @@
mConditionSliced = true;
}
+ startNewProtoOutputStream(mStartTimeNs);
+
VLOG("metric %lld created. bucket size %lld start_time: %lld", metric.metric_id(),
(long long)mBucketSizeNs, (long long)mStartTimeNs);
}
@@ -74,23 +99,14 @@
VLOG("~CountMetricProducer() called");
}
-void CountMetricProducer::finish() {
- // TODO: write the StatsLogReport to dropbox using
- // DropboxWriter.
+void CountMetricProducer::startNewProtoOutputStream(long long startTime) {
+ mProto = std::make_unique<ProtoOutputStream>();
+ mProto->write(FIELD_TYPE_INT32 | FIELD_ID_METRIC_ID, mMetric.metric_id());
+ mProto->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, startTime);
+ mProtoToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_COUNT_METRICS);
}
-static void addSlicedCounterToReport(StatsLogReport_CountMetricDataWrapper& wrapper,
- const vector<KeyValuePair>& key,
- const vector<CountBucketInfo>& buckets) {
- CountMetricData* data = wrapper.add_data();
- for (const auto& kv : key) {
- data->add_dimension()->CopyFrom(kv);
- }
- for (const auto& bucket : buckets) {
- data->add_bucket_info()->CopyFrom(bucket);
- VLOG("\t bucket [%lld - %lld] count: %lld", bucket.start_bucket_nanos(),
- bucket.end_bucket_nanos(), bucket.count());
- }
+void CountMetricProducer::finish() {
}
void CountMetricProducer::onSlicedConditionMayChange(const uint64_t eventTime) {
@@ -98,33 +114,81 @@
}
StatsLogReport CountMetricProducer::onDumpReport() {
- VLOG("metric %lld dump report now...", mMetric.metric_id());
-
- StatsLogReport report;
- report.set_metric_id(mMetric.metric_id());
- report.set_start_report_nanos(mStartTimeNs);
+ long long endTime = time(nullptr) * NANO_SECONDS_IN_A_SECOND;
// Dump current bucket if it's stale.
// If current bucket is still on-going, don't force dump current bucket.
// In finish(), We can force dump current bucket.
- flushCounterIfNeeded(time(nullptr) * NANO_SECONDS_IN_A_SECOND);
- report.set_end_report_nanos(mCurrentBucketStartTimeNs);
+ flushCounterIfNeeded(endTime);
- StatsLogReport_CountMetricDataWrapper* wrapper = report.mutable_count_metrics();
-
- for (const auto& pair : mPastBuckets) {
- const HashableDimensionKey& hashableKey = pair.first;
+ for (const auto& counter : mPastBucketProtos) {
+ const HashableDimensionKey& hashableKey = counter.first;
auto it = mDimensionKeyMap.find(hashableKey);
if (it == mDimensionKeyMap.end()) {
ALOGE("Dimension key %s not found?!?! skip...", hashableKey.c_str());
continue;
}
+ long long wrapperToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_DATA);
- VLOG(" dimension key %s", hashableKey.c_str());
- addSlicedCounterToReport(*wrapper, it->second, pair.second);
+ // First fill dimension (KeyValuePairs).
+ for (const auto& kv : it->second) {
+ long long dimensionToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION);
+ mProto->write(FIELD_TYPE_INT32 | FIELD_ID_KEY, kv.key());
+ if (kv.has_value_str()) {
+ mProto->write(FIELD_TYPE_INT32 | FIELD_ID_VALUE_STR, kv.value_str());
+ } else if (kv.has_value_int()) {
+ mProto->write(FIELD_TYPE_INT64 | FIELD_ID_VALUE_INT, kv.value_int());
+ } else if (kv.has_value_bool()) {
+ mProto->write(FIELD_TYPE_BOOL | FIELD_ID_VALUE_BOOL, kv.value_bool());
+ } else if (kv.has_value_float()) {
+ mProto->write(FIELD_TYPE_FLOAT | FIELD_ID_VALUE_FLOAT, kv.value_float());
+ }
+ mProto->end(dimensionToken);
+ }
+
+ // Then fill bucket_info (CountBucketInfo).
+ for (const auto& proto : counter.second) {
+ size_t bufferSize = proto->size();
+ char* buffer(new char[bufferSize]);
+ size_t pos = 0;
+ auto it = proto->data();
+ while (it.readBuffer() != NULL) {
+ size_t toRead = it.currentToRead();
+ std::memcpy(&buffer[pos], it.readBuffer(), toRead);
+ pos += toRead;
+ it.rp()->move(toRead);
+ }
+ mProto->write(FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION, buffer, bufferSize);
+ }
+
+ mProto->end(wrapperToken);
}
- return report;
- // TODO: Clear mPastBuckets, mDimensionKeyMap once the report is dumped.
+
+ mProto->end(mProtoToken);
+ mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS,
+ (long long)mCurrentBucketStartTimeNs);
+
+ size_t bufferSize = mProto->size();
+ VLOG("metric %lld dump report now...", mMetric.metric_id());
+ std::unique_ptr<uint8_t[]> buffer(new uint8_t[bufferSize]);
+ size_t pos = 0;
+ auto it = mProto->data();
+ while (it.readBuffer() != NULL) {
+ size_t toRead = it.currentToRead();
+ std::memcpy(&buffer[pos], it.readBuffer(), toRead);
+ pos += toRead;
+ it.rp()->move(toRead);
+ }
+
+ startNewProtoOutputStream(endTime);
+ mPastBucketProtos.clear();
+ mByteSize = 0;
+
+ // TODO: Once we migrate all MetricProducers to use ProtoOutputStream, we should return this:
+ // return std::move(buffer);
+ return StatsLogReport();
+
+ // TODO: Clear mDimensionKeyMap once the report is dumped.
}
void CountMetricProducer::onConditionChanged(const bool conditionMet, const uint64_t eventTime) {
@@ -175,15 +239,17 @@
// adjust the bucket start time
int64_t numBucketsForward = (eventTimeNs - mCurrentBucketStartTimeNs) / mBucketSizeNs;
- CountBucketInfo info;
- info.set_start_bucket_nanos(mCurrentBucketStartTimeNs);
- info.set_end_bucket_nanos(mCurrentBucketStartTimeNs + mBucketSizeNs);
-
for (const auto& counter : mCurrentSlicedCounter) {
- info.set_count(counter.second);
- // it will auto create new vector of CountbucketInfo if the key is not found.
- auto& bucketList = mPastBuckets[counter.first];
- bucketList.push_back(info);
+ unique_ptr<ProtoOutputStream> proto = make_unique<ProtoOutputStream>();
+ proto->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_NANOS,
+ (long long)mCurrentBucketStartTimeNs);
+ proto->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_NANOS,
+ (long long)mCurrentBucketStartTimeNs + mBucketSizeNs);
+ proto->write(FIELD_TYPE_INT64 | FIELD_ID_COUNT, (long long)counter.second);
+
+ auto& bucketList = mPastBucketProtos[counter.first];
+ bucketList.push_back(std::move(proto));
+ mByteSize += proto->size();
VLOG("metric %lld, dump key value: %s -> %d", mMetric.metric_id(), counter.first.c_str(),
counter.second);
@@ -202,11 +268,11 @@
(long long)mCurrentBucketStartTimeNs);
}
+// Rough estimate of CountMetricProducer buffer stored. This number will be
+// greater than actual data size as it contains each dimension of
+// CountMetricData is duplicated.
size_t CountMetricProducer::byteSize() {
-// TODO: return actual proto size when ProtoOutputStream is ready for use for
-// CountMetricsProducer.
-// return mProto->size();
- return 0;
+ return mByteSize;
}
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
index 80e80d9..473a4ba 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -19,6 +19,7 @@
#include <unordered_map>
+#include <android/util/ProtoOutputStream.h>
#include "../condition/ConditionTracker.h"
#include "../matchers/matcher_util.h"
#include "CountAnomalyTracker.h"
@@ -65,8 +66,10 @@
private:
const CountMetric mMetric;
- // Save the past buckets and we can clear when the StatsLogReport is dumped.
- std::unordered_map<HashableDimensionKey, std::vector<CountBucketInfo>> mPastBuckets;
+ std::unordered_map<HashableDimensionKey,
+ std::vector<unique_ptr<android::util::ProtoOutputStream>>> mPastBucketProtos;
+
+ size_t mByteSize;
// The current bucket.
std::unordered_map<HashableDimensionKey, int> mCurrentSlicedCounter;
@@ -74,6 +77,12 @@
vector<unique_ptr<CountAnomalyTracker>> mAnomalyTrackers;
void flushCounterIfNeeded(const uint64_t newEventTime);
+
+ std::unique_ptr<android::util::ProtoOutputStream> mProto;
+
+ long long mProtoToken;
+
+ void startNewProtoOutputStream(long long timestamp);
};
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
index d714179..cbae1d3 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -23,6 +23,7 @@
#include <limits.h>
#include <stdlib.h>
+using namespace android::util;
using android::util::ProtoOutputStream;
using std::map;
using std::string;
@@ -36,13 +37,13 @@
// for StatsLogReport
const int FIELD_ID_METRIC_ID = 1;
const int FIELD_ID_START_REPORT_NANOS = 2;
-const int FIELD_ID_END_REPORT_NANOS = 2;
+const int FIELD_ID_END_REPORT_NANOS = 3;
const int FIELD_ID_EVENT_METRICS = 4;
+// for EventMetricDataWrapper
+const int FIELD_ID_DATA = 1;
// for EventMetricData
const int FIELD_ID_TIMESTAMP_NANOS = 1;
const int FIELD_ID_STATS_EVENTS = 2;
-// for CountMetricDataWrapper
-const int FIELD_ID_DATA = 1;
EventMetricProducer::EventMetricProducer(const EventMetric& metric, const int conditionIndex,
const sp<ConditionWizard>& wizard)
@@ -69,9 +70,9 @@
mProto = std::make_unique<ProtoOutputStream>();
// TODO: We need to auto-generate the field IDs for StatsLogReport, EventMetricData,
// and StatsEvent.
- mProto->write(TYPE_INT32 + FIELD_ID_METRIC_ID, mMetric.metric_id());
- mProto->write(TYPE_INT64 + FIELD_ID_START_REPORT_NANOS, startTime);
- mProtoToken = mProto->start(TYPE_MESSAGE + FIELD_ID_EVENT_METRICS);
+ mProto->write(FIELD_TYPE_INT32 | FIELD_ID_METRIC_ID, mMetric.metric_id());
+ mProto->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, startTime);
+ mProtoToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_EVENT_METRICS);
}
void EventMetricProducer::finish() {
@@ -83,7 +84,7 @@
StatsLogReport EventMetricProducer::onDumpReport() {
long long endTime = time(nullptr) * NANO_SECONDS_IN_A_SECOND;
mProto->end(mProtoToken);
- mProto->write(TYPE_INT64 + FIELD_ID_END_REPORT_NANOS, endTime);
+ mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS, endTime);
size_t bufferSize = mProto->size();
VLOG("metric %lld dump report now... proto size: %zu ", mMetric.metric_id(), bufferSize);
@@ -118,9 +119,9 @@
return;
}
- long long wrapperToken = mProto->start(TYPE_MESSAGE + FIELD_ID_DATA);
- mProto->write(TYPE_INT64 + FIELD_ID_TIMESTAMP_NANOS, (long long)event.GetTimestampNs());
- long long eventToken = mProto->start(TYPE_MESSAGE + FIELD_ID_STATS_EVENTS);
+ long long wrapperToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_DATA);
+ mProto->write(FIELD_TYPE_INT64 | FIELD_ID_TIMESTAMP_NANOS, (long long)event.GetTimestampNs());
+ long long eventToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_STATS_EVENTS);
event.ToProto(*mProto);
mProto->end(eventToken);
mProto->end(wrapperToken);
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index cb6166d..ca33371 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -36,11 +36,11 @@
// ValueMetric has a minimum bucket size of 10min so that we don't pull too frequently
ValueMetricProducer::ValueMetricProducer(const ValueMetric& metric, const int conditionIndex,
- const sp<ConditionWizard>& wizard)
+ const sp<ConditionWizard>& wizard, const int pullTagId)
: MetricProducer((time(nullptr) / 600 * 600 * NANO_SECONDS_IN_A_SECOND), conditionIndex,
wizard),
mMetric(metric),
- mPullCode(mStatsPullerManager.GetPullCode(mMetric.what())) {
+ mPullTagId(pullTagId) {
// TODO: valuemetric for pushed events may need unlimited bucket length
mBucketSizeNs = mMetric.bucket().bucket_size_millis() * 1000 * 1000;
@@ -52,8 +52,8 @@
mConditionSliced = true;
}
- if (!metric.has_condition() && mPullCode != -1) {
- mStatsPullerManager.RegisterReceiver(mPullCode, this, metric.bucket().bucket_size_millis());
+ if (!metric.has_condition() && mPullTagId != -1) {
+ mStatsPullerManager.RegisterReceiver(mPullTagId, this, metric.bucket().bucket_size_millis());
}
VLOG("value metric %lld created. bucket size %lld start_time: %lld", metric.metric_id(),
@@ -120,27 +120,27 @@
void ValueMetricProducer::onConditionChanged(const bool condition, const uint64_t eventTime) {
mCondition = condition;
- if (mPullCode != -1) {
- vector<shared_ptr<LogEvent>> allData = mStatsPullerManager.Pull(mPullCode, eventTime);
+ if (mPullTagId != -1) {
if (mCondition == true) {
- mStatsPullerManager.RegisterReceiver(mPullCode, this,
+ mStatsPullerManager.RegisterReceiver(mPullTagId, this,
mMetric.bucket().bucket_size_millis());
} else if (mCondition == ConditionState::kFalse) {
- mStatsPullerManager.UnRegisterReceiver(mPullCode, this);
+ mStatsPullerManager.UnRegisterReceiver(mPullTagId, this);
}
- if (allData.size() == 0) {
- return;
+
+ vector<shared_ptr<LogEvent>> allData;
+ if (mStatsPullerManager.Pull(mPullTagId, &allData)) {
+ if (allData.size() == 0) {
+ return;
+ }
+ AutoMutex _l(mLock);
+ for (const auto& data : allData) {
+ onMatchedLogEvent(0, *data, false);
+ }
+ flush_if_needed(eventTime);
}
- AutoMutex _l(mLock);
- if (allData.size() == 0) {
- return;
- }
- for (const auto& data : allData) {
- onMatchedLogEvent(0, *data, false);
- }
- flush_if_needed(eventTime);
+ return;
}
- return;
}
void ValueMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& allData) {
@@ -188,7 +188,7 @@
}
}
}
- if (mPullCode == -1) {
+ if (mPullTagId == -1) {
flush_if_needed(eventTimeNs);
}
}
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index 4f17913..8653981 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -33,7 +33,7 @@
class ValueMetricProducer : public virtual MetricProducer, public virtual PullDataReceiver {
public:
ValueMetricProducer(const ValueMetric& valueMetric, const int conditionIndex,
- const sp<ConditionWizard>& wizard);
+ const sp<ConditionWizard>& wizard, const int pullTagId);
virtual ~ValueMetricProducer();
@@ -67,7 +67,8 @@
Mutex mLock;
- const int mPullCode;
+ // tagId for pulled data. -1 if this is not pulled
+ const int mPullTagId;
// internal state of a bucket.
typedef struct {
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index 3d4036e..3ff2a77 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -192,12 +192,12 @@
unordered_map<int, std::vector<int>>& trackerToMetricMap) {
sp<ConditionWizard> wizard = new ConditionWizard(allConditionTrackers);
const int allMetricsCount =
- config.count_metric_size() + config.duration_metric_size() + config.event_metric_size();
+ config.count_metric_size() + config.duration_metric_size() + config.event_metric_size() + config.value_metric_size();
allMetricProducers.reserve(allMetricsCount);
StatsPullerManager& statsPullerManager = StatsPullerManager::GetInstance();
// Build MetricProducers for each metric defined in config.
- // (1) build CountMetricProducer
+ // build CountMetricProducer
for (int i = 0; i < config.count_metric_size(); i++) {
const CountMetric& metric = config.count_metric(i);
if (!metric.has_what()) {
@@ -224,6 +224,7 @@
allMetricProducers.push_back(countProducer);
}
+ // build DurationMetricProducer
for (int i = 0; i < config.duration_metric_size(); i++) {
int metricIndex = allMetricProducers.size();
const DurationMetric& metric = config.duration_metric(i);
@@ -285,6 +286,7 @@
allMetricProducers.push_back(durationMetric);
}
+ // build EventMetricProducer
for (int i = 0; i < config.event_metric_size(); i++) {
int metricIndex = allMetricProducers.size();
const EventMetric& metric = config.event_metric(i);
@@ -310,7 +312,7 @@
allMetricProducers.push_back(eventMetric);
}
- // value metrics
+ // build ValueMetricProducer
for (int i = 0; i < config.value_metric_size(); i++) {
const ValueMetric& metric = config.value_metric(i);
if (!metric.has_what()) {
@@ -318,24 +320,35 @@
return false;
}
- int pullCode = statsPullerManager.GetPullCode(metric.what());
- if (pullCode == -1) {
- ALOGW("cannot find %s in pulled metrics", metric.what().c_str());
- return false;
- }
-
- sp<MetricProducer> valueProducer;
- auto condition_it = conditionTrackerMap.find(metric.condition());
- if (condition_it == conditionTrackerMap.end()) {
- ALOGW("cannot find the Condition %s in the config", metric.condition().c_str());
- return false;
- }
int metricIndex = allMetricProducers.size();
- valueProducer = new ValueMetricProducer(metric, condition_it->second, wizard);
- // will create new vector if not exist before.
- auto& metricList = conditionToMetricMap[condition_it->second];
- metricList.push_back(metricIndex);
+ int trackerIndex;
+ if (!handleMetricWithLogTrackers(metric.what(), metricIndex, metric.dimension_size() > 0,
+ allLogEntryMatchers, logTrackerMap, trackerToMetricMap,
+ trackerIndex)) {
+ return false;
+ }
+ sp<LogMatchingTracker> atomMatcher = allLogEntryMatchers.at(trackerIndex);
+ // If it is pulled atom, it should be simple matcher with one tagId.
+ int pullTagId = -1;
+ for (int tagId : atomMatcher->getTagIds()) {
+ if (statsPullerManager.PullerForMatcherExists(tagId)) {
+ if (atomMatcher->getTagIds().size() != 1) {
+ return false;
+ }
+ pullTagId = tagId;
+ }
+ }
+
+ int conditionIndex = -1;
+ if (metric.has_condition()) {
+ handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
+ metric.links(), allConditionTrackers, conditionIndex,
+ conditionToMetricMap);
+ }
+
+ sp<MetricProducer> valueProducer =
+ new ValueMetricProducer(metric, conditionIndex, wizard, pullTagId);
allMetricProducers.push_back(valueProducer);
}
return true;
diff --git a/cmds/statsd/src/stats_events.proto b/cmds/statsd/src/stats_events.proto
index 51244c6..82d9759 100644
--- a/cmds/statsd/src/stats_events.proto
+++ b/cmds/statsd/src/stats_events.proto
@@ -72,6 +72,7 @@
PhoneSignalStrengthChanged phone_signal_strength_changed = 40;
SettingChanged setting_changed = 41;
ActivityForegroundStateChanged activity_foreground_state_changed = 42;
+
// TODO: Reorder the numbering so that the most frequent occur events occur in the first 15.
}
@@ -81,7 +82,10 @@
WifiBytesTransferredByFgBg wifi_bytes_transferred_by_fg_bg = 1001;
MobileBytesTransferred mobile_bytes_transferred = 1002;
MobileBytesTransferredByFgBg mobile_bytes_transferred_by_fg_bg = 1003;
- KernelWakelocksReported kernel_wakelocks_reported = 1004;
+ KernelWakelockPulled kernel_wakelock_pulled = 1004;
+ PowerStatePlatformSleepStatePulled power_state_platform_sleep_state_pulled = 1005;
+ PowerStateVoterPulled power_state_voter_pulled = 1006;
+ PowerStateSubsystemSleepStatePulled power_state_subsystem_sleep_state_pulled = 1007;
}
}
@@ -794,7 +798,7 @@
* Pulled from:
* StatsCompanionService using KernelWakelockReader.
*/
-message KernelWakelocksReported {
+message KernelWakelockPulled {
optional string name = 1;
optional int32 count = 2;
@@ -803,3 +807,44 @@
optional int64 time = 4;
}
+
+/*
+ * Pulls PowerStatePlatformSleepState.
+ *
+ * Definition here:
+ * hardware/interfaces/power/1.0/types.hal
+ */
+message PowerStatePlatformSleepStatePulled {
+ optional string name = 1;
+ optional uint64 residency_in_msec_since_boot = 2;
+ optional uint64 total_transitions = 3;
+ optional bool supported_only_in_suspend = 4;
+}
+
+/**
+ * Pulls PowerStateVoter.
+ *
+ * Definition here:
+ * hardware/interfaces/power/1.0/types.hal
+ */
+message PowerStateVoterPulled {
+ optional string power_state_platform_sleep_state_name = 1;
+ optional string power_state_voter_name = 2;
+ optional uint64 total_time_in_msec_voted_for_since_boot = 3;
+ optional uint64 total_number_of_times_voted_since_boot = 4;
+}
+
+/**
+ * Pulls PowerStateSubsystemSleepState.
+ *
+ * Definition here:
+ * hardware/interfaces/power/1.1/types.hal
+ */
+message PowerStateSubsystemSleepStatePulled {
+ optional string power_state_subsystem_name = 1;
+ optional string power_state_subsystem_sleep_state_name = 2;
+ optional uint64 residency_in_msec_since_boot = 3;
+ optional uint64 total_transitions = 4;
+ optional uint64 last_entry_timestamp_ms = 5;
+ optional bool supported_only_in_suspend = 6;
+}
diff --git a/cmds/statsd/src/stats_util.h b/cmds/statsd/src/stats_util.h
index a428752..d3d7e37 100644
--- a/cmds/statsd/src/stats_util.h
+++ b/cmds/statsd/src/stats_util.h
@@ -30,14 +30,6 @@
#define MATCHER_NOT_FOUND -2
#define NANO_SECONDS_IN_A_SECOND (1000 * 1000 * 1000)
-// TODO: Remove the following constants once they are exposed in ProtOutputStream.h
-const uint64_t FIELD_TYPE_SHIFT = 32;
-const uint64_t TYPE_MESSAGE = 11ULL << FIELD_TYPE_SHIFT;
-const uint64_t TYPE_INT64 = 3ULL << FIELD_TYPE_SHIFT;
-const uint64_t TYPE_INT32 = 5ULL << FIELD_TYPE_SHIFT;
-const uint64_t TYPE_FLOAT = 2ULL << FIELD_TYPE_SHIFT;
-const uint64_t TYPE_STRING = 9ULL << FIELD_TYPE_SHIFT;
-
typedef std::string HashableDimensionKey;
typedef std::map<std::string, HashableDimensionKey> ConditionKey;
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 2305957..064e978 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -687,6 +687,7 @@
* in portrait mode or at the left half of the screen if in landscape mode.
* @hide
*/
+ @TestApi
public static final int SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT = 0;
/**
@@ -696,6 +697,7 @@
* in portrait mode or at the right half of the screen if in landscape mode.
* @hide
*/
+ @TestApi
public static final int SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT = 1;
/**
@@ -1926,6 +1928,33 @@
}
/**
+ * Moves the input task to the primary-split-screen stack.
+ * @param taskId Id of task to move.
+ * @param createMode The mode the primary split screen stack should be created in if it doesn't
+ * exist already. See
+ * {@link android.app.ActivityManager#SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT}
+ * and
+ * {@link android.app.ActivityManager
+ * #SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT}
+ * @param toTop If the task and stack should be moved to the top.
+ * @param animate Whether we should play an animation for the moving the task
+ * @param initialBounds If the primary stack gets created, it will use these bounds for the
+ * docked stack. Pass {@code null} to use default bounds.
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
+ public void setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode, boolean toTop,
+ boolean animate, Rect initialBounds) throws SecurityException {
+ try {
+ getService().setTaskWindowingModeSplitScreenPrimary(taskId, createMode, toTop, animate,
+ initialBounds);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Resizes the input stack id to the given bounds.
* @param stackId Id of the stack to resize.
* @param bounds Bounds to resize the stack to or {@code null} for fullscreen.
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 388459f..bbc90c8 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -232,7 +232,7 @@
boolean requireFull, in String name, in String callerPackage);
void addPackageDependency(in String packageName);
void killApplication(in String pkg, int appId, int userId, in String reason);
- oneway void closeSystemDialogs(in String reason);
+ void closeSystemDialogs(in String reason);
Debug.MemoryInfo[] getProcessMemoryInfo(in int[] pids);
void killApplicationProcess(in String processName, int uid);
int startActivityIntentSender(in IApplicationThread caller,
diff --git a/core/java/android/app/VrManager.java b/core/java/android/app/VrManager.java
index 5c6ffa3..392387a 100644
--- a/core/java/android/app/VrManager.java
+++ b/core/java/android/app/VrManager.java
@@ -198,4 +198,20 @@
e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Sets the current standby status of the VR device. Standby mode is only used on standalone vr
+ * devices. Standby mode is a deep sleep state where it's appropriate to turn off vr mode.
+ *
+ * @param standby True if the device is entering standby, false if it's exiting standby.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.ACCESS_VR_MANAGER)
+ public void setStandbyEnabled(boolean standby) {
+ try {
+ mService.setStandbyEnabled(standby);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index c827432..3a3e16e 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -261,7 +261,10 @@
/**
* @hide
+ * Changes the app standby state to the provided bucket.
*/
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.CHANGE_APP_IDLE_STATE)
public void setAppStandbyBucket(String packageName, @StandbyBuckets int bucket) {
try {
mService.setAppStandbyBucket(packageName, bucket, mContext.getUserId());
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index e47de75..dd729a3 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3444,11 +3444,12 @@
/**
* A broadcast action to trigger a factory reset.
*
- * <p> The sender must hold the {@link android.Manifest.permission#MASTER_CLEAR} permission.
+ * <p>The sender must hold the {@link android.Manifest.permission#MASTER_CLEAR} permission. The
+ * reason for the factory reset should be specified as {@link #EXTRA_REASON}.
*
* <p>Not for use by third-party applications.
*
- * @see #EXTRA_FORCE_MASTER_CLEAR
+ * @see #EXTRA_FORCE_FACTORY_RESET
*
* {@hide}
*/
@@ -4827,7 +4828,13 @@
/** @hide */
public static final int EXTRA_TIME_PREF_VALUE_USE_LOCALE_DEFAULT = 2;
- /** {@hide} */
+ /**
+ * Intent extra: the reason that the operation associated with this intent is being performed.
+ *
+ * <p>Type: String
+ * @hide
+ */
+ @SystemApi
public static final String EXTRA_REASON = "android.intent.extra.REASON";
/**
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index b94a410..05c5556 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -671,9 +671,13 @@
}
/**
- * Returns whether the caller can access the shortcut information.
+ * Returns whether the caller can access the shortcut information. Access is currently
+ * available to:
*
- * <p>Only the default launcher can access the shortcut information.
+ * <ul>
+ * <li>The current launcher (or default launcher if there is no set current launcher).</li>
+ * <li>The currently active voice interaction service.</li>
+ * </ul>
*
* <p>Note when this method returns {@code false}, it may be a temporary situation because
* the user is trying a new launcher application. The user may decide to change the default
diff --git a/core/java/android/content/pm/ShortcutServiceInternal.java b/core/java/android/content/pm/ShortcutServiceInternal.java
index 7fc25d8..dadfaa9 100644
--- a/core/java/android/content/pm/ShortcutServiceInternal.java
+++ b/core/java/android/content/pm/ShortcutServiceInternal.java
@@ -73,6 +73,9 @@
public abstract boolean hasShortcutHostPermission(int launcherUserId,
@NonNull String callingPackage, int callingPid, int callingUid);
+ public abstract void setShortcutHostPackage(@NonNull String type, @Nullable String packageName,
+ int userId);
+
public abstract boolean requestPinAppWidget(@NonNull String callingPackage,
@NonNull AppWidgetProviderInfo appWidget, @Nullable Bundle extras,
@Nullable IntentSender resultIntent, int userId);
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
index 7cbb436..2411727 100644
--- a/core/java/android/hardware/location/ContextHubManager.java
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -271,6 +271,59 @@
throw new UnsupportedOperationException("TODO: Implement this");
}
+ /*
+ * Helper function to generate a stub for a non-query transaction callback.
+ *
+ * @param transaction the transaction to unblock when complete
+ *
+ * @return the callback
+ *
+ * @hide
+ */
+ private IContextHubTransactionCallback createTransactionCallback(
+ ContextHubTransaction<Void> transaction) {
+ return new IContextHubTransactionCallback.Stub() {
+ @Override
+ public void onQueryResponse(int result, List<NanoAppState> nanoappList) {
+ Log.e(TAG, "Received a query callback on a non-query request");
+ transaction.setResponse(new ContextHubTransaction.Response<Void>(
+ ContextHubTransaction.TRANSACTION_FAILED_SERVICE_INTERNAL_FAILURE, null));
+ }
+
+ @Override
+ public void onTransactionComplete(int result) {
+ transaction.setResponse(new ContextHubTransaction.Response<Void>(result, null));
+ }
+ };
+ }
+
+ /*
+ * Helper function to generate a stub for a query transaction callback.
+ *
+ * @param transaction the transaction to unblock when complete
+ *
+ * @return the callback
+ *
+ * @hide
+ */
+ private IContextHubTransactionCallback createQueryCallback(
+ ContextHubTransaction<List<NanoAppState>> transaction) {
+ return new IContextHubTransactionCallback.Stub() {
+ @Override
+ public void onQueryResponse(int result, List<NanoAppState> nanoappList) {
+ transaction.setResponse(new ContextHubTransaction.Response<List<NanoAppState>>(
+ result, nanoappList));
+ }
+
+ @Override
+ public void onTransactionComplete(int result) {
+ Log.e(TAG, "Received a non-query callback on a query request");
+ transaction.setResponse(new ContextHubTransaction.Response<List<NanoAppState>>(
+ ContextHubTransaction.TRANSACTION_FAILED_SERVICE_INTERNAL_FAILURE, null));
+ }
+ };
+ }
+
/**
* Loads a nanoapp at the specified Context Hub.
*
@@ -411,7 +464,7 @@
*
* @param callback the notification callback to register
* @param hubInfo the hub to attach this client to
- * @param handler the handler to invoke the callback, if null uses the current thread Looper
+ * @param handler the handler to invoke the callback, if null uses the main thread's Looper
*
* @return the registered client object
*
diff --git a/core/java/android/hardware/location/ContextHubTransaction.java b/core/java/android/hardware/location/ContextHubTransaction.java
index 4877d38..a8569ef 100644
--- a/core/java/android/hardware/location/ContextHubTransaction.java
+++ b/core/java/android/hardware/location/ContextHubTransaction.java
@@ -16,11 +16,16 @@
package android.hardware.location;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.os.Handler;
+import android.os.Looper;
+import android.util.Log;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
/**
* A class describing a request sent to the Context Hub Service.
@@ -29,17 +34,15 @@
* through the ContextHubManager APIs. The caller can either retrieve the result
* synchronously through a blocking call ({@link #waitForResponse(long, TimeUnit)}) or
* asynchronously through a user-defined callback
- * ({@link #onComplete(ContextHubTransaction.Callback<T>, Handler)}).
- *
- * A transaction can be invalidated if the caller of the transaction is no longer active
- * and the reference to this object is lost, or if timeout period has passed in
- * {@link #waitForResponse(long, TimeUnit)}.
+ * ({@link #setCallbackOnComplete(ContextHubTransaction.Callback, Handler)}).
*
* @param <T> the type of the contents in the transaction response
*
* @hide
*/
public class ContextHubTransaction<T> {
+ private static final String TAG = "ContextHubTransaction";
+
/**
* Constants describing the type of a transaction through the Context Hub Service.
*/
@@ -68,7 +71,8 @@
TRANSACTION_FAILED_UNINITIALIZED,
TRANSACTION_FAILED_PENDING,
TRANSACTION_FAILED_AT_HUB,
- TRANSACTION_FAILED_TIMEOUT})
+ TRANSACTION_FAILED_TIMEOUT,
+ TRANSACTION_FAILED_SERVICE_INTERNAL_FAILURE})
public @interface Result {}
public static final int TRANSACTION_SUCCESS = 0;
/**
@@ -95,6 +99,10 @@
* Failure mode when the transaction has timed out.
*/
public static final int TRANSACTION_FAILED_TIMEOUT = 6;
+ /**
+ * Failure mode when the transaction has failed internally at the service.
+ */
+ public static final int TRANSACTION_FAILED_SERVICE_INTERNAL_FAILURE = 7;
/**
* A class describing the response for a ContextHubTransaction.
@@ -146,11 +154,6 @@
}
/*
- * The unique identifier representing the transaction.
- */
- private int mTransactionId;
-
- /*
* The type of the transaction.
*/
@Type
@@ -171,8 +174,17 @@
*/
private ContextHubTransaction.Callback<T> mCallback = null;
- ContextHubTransaction(int id, @Type int type) {
- mTransactionId = id;
+ /*
+ * Synchronization latch used to block on response.
+ */
+ private final CountDownLatch mDoneSignal = new CountDownLatch(1);
+
+ /*
+ * true if the response has been set throught setResponse, false otherwise.
+ */
+ private boolean mIsResponseSet = false;
+
+ ContextHubTransaction(@Type int type) {
mTransactionType = type;
}
@@ -191,17 +203,26 @@
* for the transaction represented by this object by the Context Hub, or a
* specified timeout period has elapsed.
*
- * If the specified timeout has passed, the transaction represented by this object
- * is invalidated by the Context Hub Service (resulting in a timeout failure in the
- * response).
+ * If the specified timeout has passed, a TimeoutException will be thrown and the caller may
+ * retry the invocation of this method at a later time.
*
* @param timeout the timeout duration
* @param unit the unit of the timeout
*
* @return the transaction response
+ *
+ * @throws InterruptedException if the current thread is interrupted while waiting for response
+ * @throws TimeoutException if the timeout period has passed
*/
- public ContextHubTransaction.Response<T> waitForResponse(long timeout, TimeUnit unit) {
- throw new UnsupportedOperationException("TODO: Implement this");
+ public ContextHubTransaction.Response<T> waitForResponse(
+ long timeout, TimeUnit unit) throws InterruptedException, TimeoutException {
+ boolean success = mDoneSignal.await(timeout, unit);
+
+ if (!success) {
+ throw new TimeoutException("Timed out while waiting for transaction");
+ }
+
+ return mResponse;
}
/**
@@ -215,15 +236,100 @@
* will be immediately posted by the handler. If the transaction has been invalidated,
* the callback will never be invoked.
*
+ * A transaction can be invalidated if the process owning the transaction is no longer active
+ * and the reference to this object is lost.
+ *
+ * This method or {@link #setCallbackOnCompletecan(ContextHubTransaction.Callback)} can only be
+ * invoked once, or an IllegalStateException will be thrown.
+ *
* @param callback the callback to be invoked upon completion
* @param handler the handler to post the callback
+ *
+ * @throws IllegalStateException if this method is called multiple times
+ * @throws NullPointerException if the callback or handler is null
*/
- public void onComplete(ContextHubTransaction.Callback<T> callback, Handler handler) {
- throw new UnsupportedOperationException("TODO: Implement this");
+ public void setCallbackOnComplete(
+ @NonNull ContextHubTransaction.Callback<T> callback, @NonNull Handler handler) {
+ synchronized (this) {
+ if (callback == null) {
+ throw new NullPointerException("Callback cannot be null");
+ }
+ if (handler == null) {
+ throw new NullPointerException("Handler cannot be null");
+ }
+ if (mCallback != null) {
+ throw new IllegalStateException(
+ "Cannot set ContextHubTransaction callback multiple times");
+ }
+
+ mCallback = callback;
+ mHandler = handler;
+
+ if (mDoneSignal.getCount() == 0) {
+ boolean callbackPosted = mHandler.post(() -> {
+ mCallback.onComplete(this, mResponse);
+ });
+
+ if (!callbackPosted) {
+ Log.e(TAG, "Failed to post callback to Handler");
+ }
+ }
+ }
}
- private void setResponse(ContextHubTransaction.Response<T> response) {
- mResponse = response;
- throw new UnsupportedOperationException("TODO: Unblock waitForResponse");
+ /**
+ * Sets a callback to be invoked when the transaction completes.
+ *
+ * Equivalent to {@link #setCallbackOnComplete(ContextHubTransaction.Callback, Handler)}
+ * with the handler being that of the main thread's Looper.
+ *
+ * This method or {@link #setCallbackOnComplete(ContextHubTransaction.Callback, Handler)}
+ * can only be invoked once, or an IllegalStateException will be thrown.
+ *
+ * @param callback the callback to be invoked upon completion
+ *
+ * @throws IllegalStateException if this method is called multiple times
+ * @throws NullPointerException if the callback is null
+ */
+ public void setCallbackOnComplete(@NonNull ContextHubTransaction.Callback<T> callback) {
+ setCallbackOnComplete(callback, new Handler(Looper.getMainLooper()));
+ }
+
+ /**
+ * Sets the response of the transaction.
+ *
+ * This method should only be invoked by ContextHubManager as a result of a callback from
+ * the Context Hub Service indicating the response from a transaction. This method should not be
+ * invoked more than once.
+ *
+ * @param response the response to set
+ *
+ * @throws IllegalStateException if this method is invoked multiple times
+ * @throws NullPointerException if the response is null
+ */
+ void setResponse(ContextHubTransaction.Response<T> response) {
+ synchronized (this) {
+ if (response == null) {
+ throw new NullPointerException("Response cannot be null");
+ }
+ if (mIsResponseSet) {
+ throw new IllegalStateException(
+ "Cannot set response of ContextHubTransaction multiple times");
+ }
+
+ mResponse = response;
+ mIsResponseSet = true;
+
+ mDoneSignal.countDown();
+ if (mCallback != null) {
+ boolean callbackPosted = mHandler.post(() -> {
+ mCallback.onComplete(this, mResponse);
+ });
+
+ if (!callbackPosted) {
+ Log.e(TAG, "Failed to post callback to Handler");
+ }
+ }
+ }
}
}
diff --git a/core/java/android/hardware/location/IContextHubTransactionCallback.aidl b/core/java/android/hardware/location/IContextHubTransactionCallback.aidl
new file mode 100644
index 0000000..5419cd7
--- /dev/null
+++ b/core/java/android/hardware/location/IContextHubTransactionCallback.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.location;
+
+import android.hardware.location.NanoAppState;
+
+/**
+ * An interface used by the Context Hub Service to invoke callbacks notifying the complete of a
+ * transaction. The callbacks are unique for each type of transaction, and the service is
+ * responsible for invoking the correct callback.
+ *
+ * @hide
+ */
+oneway interface IContextHubTransactionCallback {
+
+ // Callback to be invoked when a query request completes
+ void onQueryResponse(int result, in List<NanoAppState> nanoappList);
+
+ // Callback to be invoked when a non-query request completes
+ void onTransactionComplete(int result);
+}
diff --git a/core/java/android/hardware/location/NanoAppBinary.java b/core/java/android/hardware/location/NanoAppBinary.java
index 5454227..934e9e4 100644
--- a/core/java/android/hardware/location/NanoAppBinary.java
+++ b/core/java/android/hardware/location/NanoAppBinary.java
@@ -22,6 +22,7 @@
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
+import java.util.Arrays;
/**
* @hide
@@ -57,7 +58,7 @@
private static final int EXPECTED_HEADER_VERSION = 1;
/*
- * The magic value expected in the header.
+ * The magic value expected in the header as defined in context_hub.h.
*/
private static final int EXPECTED_MAGIC_VALUE =
(((int) 'N' << 0) | ((int) 'A' << 8) | ((int) 'N' << 16) | ((int) 'O' << 24));
@@ -67,6 +68,17 @@
*/
private static final ByteOrder HEADER_ORDER = ByteOrder.LITTLE_ENDIAN;
+ /*
+ * The size of the header in bytes as defined in context_hub.h.
+ */
+ private static final int HEADER_SIZE_BYTES = 40;
+
+ /*
+ * The bit fields for mFlags as defined in context_hub.h.
+ */
+ private static final int NANOAPP_SIGNED_FLAG_BIT = 0x1;
+ private static final int NANOAPP_ENCRYPTED_FLAG_BIT = 0x2;
+
public NanoAppBinary(byte[] appBinary) {
mNanoAppBinary = appBinary;
parseBinaryHeader();
@@ -111,11 +123,26 @@
/**
* @return the app binary byte array
*/
- public byte[] getNanoAppBinary() {
+ public byte[] getBinary() {
return mNanoAppBinary;
}
/**
+ * @return the app binary byte array without the leading header
+ *
+ * @throws IndexOutOfBoundsException if the nanoapp binary size is smaller than the header size
+ * @throws NullPointerException if the nanoapp binary is null
+ */
+ public byte[] getBinaryNoHeader() {
+ if (mNanoAppBinary.length < HEADER_SIZE_BYTES) {
+ throw new IndexOutOfBoundsException("NanoAppBinary binary byte size ("
+ + mNanoAppBinary.length + ") is less than header size (" + HEADER_SIZE_BYTES + ")");
+ }
+
+ return Arrays.copyOfRange(mNanoAppBinary, HEADER_SIZE_BYTES, mNanoAppBinary.length);
+ }
+
+ /**
* @return {@code true} if the header is valid, {@code false} otherwise
*/
public boolean hasValidHeader() {
@@ -164,6 +191,31 @@
return mTargetChreApiMinorVersion;
}
+ /**
+ * Returns the flags for the nanoapp as defined in context_hub.h.
+ *
+ * This method is meant to be used by the Context Hub Service.
+ *
+ * @return the flags for the nanoapp
+ */
+ public int getFlags() {
+ return mFlags;
+ }
+
+ /**
+ * @return {@code true} if the nanoapp binary is signed, {@code false} otherwise
+ */
+ public boolean isSigned() {
+ return (mFlags & NANOAPP_SIGNED_FLAG_BIT) != 0;
+ }
+
+ /**
+ * @return {@code true} if the nanoapp binary is encrypted, {@code false} otherwise
+ */
+ public boolean isEncrypted() {
+ return (mFlags & NANOAPP_ENCRYPTED_FLAG_BIT) != 0;
+ }
+
private NanoAppBinary(Parcel in) {
int binaryLength = in.readInt();
mNanoAppBinary = new byte[binaryLength];
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 7f4dee6..01b6535 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -513,6 +513,34 @@
*/
public static final int SHUTDOWN_REASON_BATTERY_THERMAL = 6;
+ /**
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({ServiceType.GPS,
+ ServiceType.VIBRATION,
+ ServiceType.ANIMATION,
+ ServiceType.FULL_BACKUP,
+ ServiceType.KEYVALUE_BACKUP,
+ ServiceType.NETWORK_FIREWALL,
+ ServiceType.SCREEN_BRIGHTNESS,
+ ServiceType.SOUND,
+ ServiceType.BATTERY_STATS,
+ ServiceType.DATA_SAVER})
+ public @interface ServiceType {
+ int NULL = 0;
+ int GPS = 1;
+ int VIBRATION = 2;
+ int ANIMATION = 3;
+ int FULL_BACKUP = 4;
+ int KEYVALUE_BACKUP = 5;
+ int NETWORK_FIREWALL = 6;
+ int SCREEN_BRIGHTNESS = 7;
+ int SOUND = 8;
+ int BATTERY_STATS = 9;
+ int DATA_SAVER = 10;
+ }
+
final Context mContext;
final IPowerManager mService;
final Handler mHandler;
@@ -1055,15 +1083,14 @@
/**
* Get data about the battery saver mode for a specific service
- * @param serviceType unique key for the service, one of
- * {@link com.android.server.power.BatterySaverPolicy.ServiceType}
+ * @param serviceType unique key for the service, one of {@link ServiceType}
* @return Battery saver state data.
*
* @hide
* @see com.android.server.power.BatterySaverPolicy
* @see PowerSaveState
*/
- public PowerSaveState getPowerSaveState(int serviceType) {
+ public PowerSaveState getPowerSaveState(@ServiceType int serviceType) {
try {
return mService.getPowerSaveState(serviceType);
} catch (RemoteException e) {
diff --git a/core/java/android/os/PowerSaveState.java b/core/java/android/os/PowerSaveState.java
index 7058a1d..de1128df 100644
--- a/core/java/android/os/PowerSaveState.java
+++ b/core/java/android/os/PowerSaveState.java
@@ -27,7 +27,7 @@
/**
* Whether we should enable battery saver for this service.
*
- * @see com.android.server.power.BatterySaverPolicy.ServiceType
+ * @see com.android.server.power.BatterySaverPolicy
*/
public final boolean batterySaverEnabled;
/**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 2d6a7b0..433878e 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -8012,28 +8012,40 @@
public static final String HDMI_SYSTEM_AUDIO_CONTROL_ENABLED =
"hdmi_system_audio_control_enabled";
- /**
- * Whether TV will automatically turn on upon reception of the CEC command
- * <Text View On> or <Image View On>. (0 = false, 1 = true)
- * @hide
- */
- public static final String HDMI_CONTROL_AUTO_WAKEUP_ENABLED =
- "hdmi_control_auto_wakeup_enabled";
+ /**
+ * Whether TV will automatically turn on upon reception of the CEC command
+ * <Text View On> or <Image View On>. (0 = false, 1 = true)
+ *
+ * @hide
+ */
+ public static final String HDMI_CONTROL_AUTO_WAKEUP_ENABLED =
+ "hdmi_control_auto_wakeup_enabled";
- /**
- * Whether TV will also turn off other CEC devices when it goes to standby mode.
- * (0 = false, 1 = true)
- * @hide
- */
- public static final String HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED =
- "hdmi_control_auto_device_off_enabled";
+ /**
+ * Whether TV will also turn off other CEC devices when it goes to standby mode.
+ * (0 = false, 1 = true)
+ *
+ * @hide
+ */
+ public static final String HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED =
+ "hdmi_control_auto_device_off_enabled";
- /**
- * The interval in milliseconds at which location requests will be throttled when they are
- * coming from the background.
- * @hide
- */
- public static final String LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS =
+ /**
+ * If <b>true</b>, enables out-of-the-box execution for priv apps.
+ * Default: false
+ * Values: 0 = false, 1 = true
+ *
+ * @hide
+ */
+ public static final String PRIV_APP_OOB_ENABLED = "priv_app_oob_enabled";
+
+ /**
+ * The interval in milliseconds at which location requests will be throttled when they are
+ * coming from the background.
+ *
+ * @hide
+ */
+ public static final String LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS =
"location_background_throttle_interval_ms";
/**
diff --git a/core/java/android/service/vr/IVrManager.aidl b/core/java/android/service/vr/IVrManager.aidl
index fef9223..7285fb4 100644
--- a/core/java/android/service/vr/IVrManager.aidl
+++ b/core/java/android/service/vr/IVrManager.aidl
@@ -101,5 +101,13 @@
* application's compositor process to bind to, or null to clear the current binding.
*/
void setAndBindCompositor(in String componentName);
+
+ /**
+ * Sets the current standby status of the VR device. Standby mode is only used on standalone vr
+ * devices. Standby mode is a deep sleep state where it's appropriate to turn off vr mode.
+ *
+ * @param standy True if the device is entering standby, false if it's exiting standby.
+ */
+ void setStandbyEnabled(boolean standby);
}
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
index a9ccae1..1808123 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
@@ -16,9 +16,6 @@
package android.util.apk;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.OsConstants;
import android.util.ArrayMap;
import android.util.Pair;
@@ -30,7 +27,6 @@
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
-import java.nio.DirectByteBuffer;
import java.security.DigestException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
@@ -122,40 +118,6 @@
}
/**
- * APK Signature Scheme v2 block and additional information relevant to verifying the signatures
- * contained in the block against the file.
- */
- private static class SignatureInfo {
- /** Contents of APK Signature Scheme v2 block. */
- private final ByteBuffer signatureBlock;
-
- /** Position of the APK Signing Block in the file. */
- private final long apkSigningBlockOffset;
-
- /** Position of the ZIP Central Directory in the file. */
- private final long centralDirOffset;
-
- /** Position of the ZIP End of Central Directory (EoCD) in the file. */
- private final long eocdOffset;
-
- /** Contents of ZIP End of Central Directory (EoCD) of the file. */
- private final ByteBuffer eocd;
-
- private SignatureInfo(
- ByteBuffer signatureBlock,
- long apkSigningBlockOffset,
- long centralDirOffset,
- long eocdOffset,
- ByteBuffer eocd) {
- this.signatureBlock = signatureBlock;
- this.apkSigningBlockOffset = apkSigningBlockOffset;
- this.centralDirOffset = centralDirOffset;
- this.eocdOffset = eocdOffset;
- this.eocd = eocd;
- }
- }
-
- /**
* Returns the APK Signature Scheme v2 block contained in the provided APK file and the
* additional information relevant for verifying the block against the file.
*
@@ -497,6 +459,7 @@
// TODO: Compute digests of chunks in parallel when beneficial. This requires some research
// into how to parallelize (if at all) based on the capabilities of the hardware on which
// this code is running and based on the size of input.
+ DataDigester digester = new MultipleDigestDataDigester(mds);
int dataSourceIndex = 0;
for (DataSource input : contents) {
long inputOffset = 0;
@@ -508,7 +471,7 @@
mds[i].update(chunkContentPrefix);
}
try {
- input.feedIntoMessageDigests(mds, inputOffset, chunkSize);
+ input.feedIntoDataDigester(digester, inputOffset, chunkSize);
} catch (IOException e) {
throw new DigestException(
"Failed to digest chunk #" + chunkIndex + " of section #"
@@ -967,155 +930,26 @@
}
/**
- * Source of data to be digested.
+ * {@link DataDigester} that updates multiple {@link MessageDigest}s whenever data is feeded.
*/
- private static interface DataSource {
+ private static class MultipleDigestDataDigester implements DataDigester {
+ private final MessageDigest[] mMds;
- /**
- * Returns the size (in bytes) of the data offered by this source.
- */
- long size();
-
- /**
- * Feeds the specified region of this source's data into the provided digests. Each digest
- * instance gets the same data.
- *
- * @param offset offset of the region inside this data source.
- * @param size size (in bytes) of the region.
- */
- void feedIntoMessageDigests(MessageDigest[] mds, long offset, int size) throws IOException;
- }
-
- /**
- * {@link DataSource} which provides data from a file descriptor by memory-mapping the sections
- * of the file requested by
- * {@link DataSource#feedIntoMessageDigests(MessageDigest[], long, int) feedIntoMessageDigests}.
- */
- private static final class MemoryMappedFileDataSource implements DataSource {
- private static final long MEMORY_PAGE_SIZE_BYTES = Os.sysconf(OsConstants._SC_PAGESIZE);
-
- private final FileDescriptor mFd;
- private final long mFilePosition;
- private final long mSize;
-
- /**
- * Constructs a new {@code MemoryMappedFileDataSource} for the specified region of the file.
- *
- * @param position start position of the region in the file.
- * @param size size (in bytes) of the region.
- */
- public MemoryMappedFileDataSource(FileDescriptor fd, long position, long size) {
- mFd = fd;
- mFilePosition = position;
- mSize = size;
+ MultipleDigestDataDigester(MessageDigest[] mds) {
+ mMds = mds;
}
@Override
- public long size() {
- return mSize;
- }
-
- @Override
- public void feedIntoMessageDigests(
- MessageDigest[] mds, long offset, int size) throws IOException {
- // IMPLEMENTATION NOTE: After a lot of experimentation, the implementation of this
- // method was settled on a straightforward mmap with prefaulting.
- //
- // This method is not using FileChannel.map API because that API does not offset a way
- // to "prefault" the resulting memory pages. Without prefaulting, performance is about
- // 10% slower on small to medium APKs, but is significantly worse for APKs in 500+ MB
- // range. FileChannel.load (which currently uses madvise) doesn't help. Finally,
- // invoking madvise (MADV_SEQUENTIAL) after mmap with prefaulting wastes quite a bit of
- // time, which is not compensated for by faster reads.
-
- // We mmap the smallest region of the file containing the requested data. mmap requires
- // that the start offset in the file must be a multiple of memory page size. We thus may
- // need to mmap from an offset less than the requested offset.
- long filePosition = mFilePosition + offset;
- long mmapFilePosition =
- (filePosition / MEMORY_PAGE_SIZE_BYTES) * MEMORY_PAGE_SIZE_BYTES;
- int dataStartOffsetInMmapRegion = (int) (filePosition - mmapFilePosition);
- long mmapRegionSize = size + dataStartOffsetInMmapRegion;
- long mmapPtr = 0;
- try {
- mmapPtr = Os.mmap(
- 0, // let the OS choose the start address of the region in memory
- mmapRegionSize,
- OsConstants.PROT_READ,
- OsConstants.MAP_SHARED | OsConstants.MAP_POPULATE, // "prefault" all pages
- mFd,
- mmapFilePosition);
- // Feeding a memory region into MessageDigest requires the region to be represented
- // as a direct ByteBuffer.
- ByteBuffer buf = new DirectByteBuffer(
- size,
- mmapPtr + dataStartOffsetInMmapRegion,
- mFd, // not really needed, but just in case
- null, // no need to clean up -- it's taken care of by the finally block
- true // read only buffer
- );
- for (MessageDigest md : mds) {
- buf.position(0);
- md.update(buf);
- }
- } catch (ErrnoException e) {
- throw new IOException("Failed to mmap " + mmapRegionSize + " bytes", e);
- } finally {
- if (mmapPtr != 0) {
- try {
- Os.munmap(mmapPtr, mmapRegionSize);
- } catch (ErrnoException ignored) {}
- }
+ public void consume(ByteBuffer buffer) {
+ buffer = buffer.slice();
+ for (MessageDigest md : mMds) {
+ buffer.position(0);
+ md.update(buffer);
}
}
- }
-
- /**
- * {@link DataSource} which provides data from a {@link ByteBuffer}.
- */
- private static final class ByteBufferDataSource implements DataSource {
- /**
- * Underlying buffer. The data is stored between position 0 and the buffer's capacity.
- * The buffer's position is 0 and limit is equal to capacity.
- */
- private final ByteBuffer mBuf;
-
- public ByteBufferDataSource(ByteBuffer buf) {
- // Defensive copy, to avoid changes to mBuf being visible in buf.
- mBuf = buf.slice();
- }
@Override
- public long size() {
- return mBuf.capacity();
- }
-
- @Override
- public void feedIntoMessageDigests(
- MessageDigest[] mds, long offset, int size) throws IOException {
- // There's no way to tell MessageDigest to read data from ByteBuffer from a position
- // other than the buffer's current position. We thus need to change the buffer's
- // position to match the requested offset.
- //
- // In the future, it may be necessary to compute digests of multiple regions in
- // parallel. Given that digest computation is a slow operation, we enable multiple
- // such requests to be fulfilled by this instance. This is achieved by serially
- // creating a new ByteBuffer corresponding to the requested data range and then,
- // potentially concurrently, feeding these buffers into MessageDigest instances.
- ByteBuffer region;
- synchronized (mBuf) {
- mBuf.position((int) offset);
- mBuf.limit((int) offset + size);
- region = mBuf.slice();
- }
-
- for (MessageDigest md : mds) {
- // Need to reset position to 0 at the start of each iteration because
- // MessageDigest.update below sets it to the buffer's limit.
- region.position(0);
- md.update(region);
- }
- }
+ public void finish() {}
}
/**
diff --git a/core/java/android/util/apk/ApkVerityBuilder.java b/core/java/android/util/apk/ApkVerityBuilder.java
new file mode 100644
index 0000000..0b9552e
--- /dev/null
+++ b/core/java/android/util/apk/ApkVerityBuilder.java
@@ -0,0 +1,347 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.apk;
+
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+
+/**
+ * ApkVerityBuilder builds the APK verity tree and the verity header, which will be used by the
+ * kernel to verity the APK content on access.
+ *
+ * <p>Unlike a regular Merkle tree, APK verity tree does not cover the content fully. Due to
+ * the existing APK format, it has to skip APK Signing Block and also has some special treatment for
+ * the "Central Directory offset" field of ZIP End of Central Directory.
+ *
+ * @hide
+ */
+abstract class ApkVerityBuilder {
+ private ApkVerityBuilder() {}
+
+ private static final int CHUNK_SIZE_BYTES = 4096; // Typical Linux block size
+ private static final int DIGEST_SIZE_BYTES = 32; // SHA-256 size
+ private static final int FSVERITY_HEADER_SIZE_BYTES = 64;
+ private static final int ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE = 4;
+ private static final int ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_OFFSET = 16;
+ private static final String JCA_DIGEST_ALGORITHM = "SHA-256";
+ private static final byte[] DEFAULT_SALT = new byte[8];
+
+ static class ApkVerityResult {
+ public final ByteBuffer fsverityData;
+ public final byte[] rootHash;
+
+ ApkVerityResult(ByteBuffer fsverityData, byte[] rootHash) {
+ this.fsverityData = fsverityData;
+ this.rootHash = rootHash;
+ }
+ }
+
+ /**
+ * Generates fsverity metadata and the Merkle tree into the {@link ByteBuffer} created by the
+ * {@link ByteBufferFactory}. The bytes layout in the buffer will be used by the kernel and is
+ * ready to be appended to the target file to set up fsverity. For fsverity to work, this data
+ * must be placed at the next page boundary, and the caller must add additional padding in that
+ * case.
+ *
+ * @return ApkVerityResult containing the fsverity data and the root hash of the Merkle tree.
+ */
+ static ApkVerityResult generateApkVerity(RandomAccessFile apk,
+ SignatureInfo signatureInfo, ByteBufferFactory bufferFactory)
+ throws IOException, SecurityException, NoSuchAlgorithmException {
+ assertSigningBlockAlignedAndHasFullPages(signatureInfo);
+
+ long signingBlockSize =
+ signatureInfo.centralDirOffset - signatureInfo.apkSigningBlockOffset;
+ long dataSize = apk.length() - signingBlockSize - ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE;
+ int[] levelOffset = calculateVerityLevelOffset(dataSize);
+ ByteBuffer output = bufferFactory.create(
+ CHUNK_SIZE_BYTES + // fsverity header + extensions + padding
+ levelOffset[levelOffset.length - 1] + // Merkle tree size
+ FSVERITY_HEADER_SIZE_BYTES); // second fsverity header (verbatim copy)
+
+ // Start generating the tree from the block boundary as the kernel will expect.
+ ByteBuffer treeOutput = slice(output, CHUNK_SIZE_BYTES,
+ output.limit() - FSVERITY_HEADER_SIZE_BYTES);
+ byte[] rootHash = generateApkVerityTree(apk, signatureInfo, DEFAULT_SALT, levelOffset,
+ treeOutput);
+
+ ByteBuffer integrityHeader = generateFsverityHeader(apk.length(), DEFAULT_SALT);
+ output.put(integrityHeader);
+ output.put(generateFsverityExtensions());
+
+ integrityHeader.rewind();
+ output.put(integrityHeader);
+ output.rewind();
+ return new ApkVerityResult(output, rootHash);
+ }
+
+ /**
+ * A helper class to consume and digest data by block continuously, and write into a buffer.
+ */
+ private static class BufferedDigester implements DataDigester {
+ /** Amount of the data to digest in each cycle before writting out the digest. */
+ private static final int BUFFER_SIZE = CHUNK_SIZE_BYTES;
+
+ /**
+ * Amount of data the {@link MessageDigest} has consumed since the last reset. This must be
+ * always less than BUFFER_SIZE since {@link MessageDigest} is reset whenever it has
+ * consumed BUFFER_SIZE of data.
+ */
+ private int mBytesDigestedSinceReset;
+
+ /** The final output {@link ByteBuffer} to write the digest to sequentially. */
+ private final ByteBuffer mOutput;
+
+ private final MessageDigest mMd;
+ private final byte[] mSalt;
+
+ private BufferedDigester(byte[] salt, ByteBuffer output) throws NoSuchAlgorithmException {
+ mSalt = salt;
+ mOutput = output.slice();
+ mMd = MessageDigest.getInstance(JCA_DIGEST_ALGORITHM);
+ mMd.update(mSalt);
+ mBytesDigestedSinceReset = 0;
+ }
+
+ /**
+ * Consumes and digests data up to BUFFER_SIZE (may continue from the previous remaining),
+ * then writes the final digest to the output buffer. Repeat until all data are consumed.
+ * If the last consumption is not enough for BUFFER_SIZE, the state will stay and future
+ * consumption will continuous from there.
+ */
+ @Override
+ public void consume(ByteBuffer buffer) {
+ int offset = buffer.position();
+ int remaining = buffer.remaining();
+ while (remaining > 0) {
+ int allowance = (int) Math.min(remaining, BUFFER_SIZE - mBytesDigestedSinceReset);
+ mMd.update(slice(buffer, offset, offset + allowance));
+ offset += allowance;
+ remaining -= allowance;
+ mBytesDigestedSinceReset += allowance;
+
+ if (mBytesDigestedSinceReset == BUFFER_SIZE) {
+ byte[] digest = mMd.digest();
+ mOutput.put(digest);
+
+ mMd.reset();
+ mMd.update(mSalt);
+ mBytesDigestedSinceReset = 0;
+ }
+ }
+ }
+
+ /** Finish the current digestion if any. */
+ @Override
+ public void finish() {
+ if (mBytesDigestedSinceReset == 0) {
+ return;
+ }
+ byte[] digest = mMd.digest();
+ mOutput.put(digest);
+ }
+
+ private void fillUpLastOutputChunk() {
+ int extra = (int) (BUFFER_SIZE - mOutput.position() % BUFFER_SIZE);
+ if (extra == 0) {
+ return;
+ }
+ mOutput.put(ByteBuffer.allocate(extra));
+ }
+ }
+
+ /**
+ * Digest the source by chunk in the given range. If the last chunk is not a full chunk,
+ * digest the remaining.
+ */
+ private static void consumeByChunk(DataDigester digester, DataSource source, int chunkSize)
+ throws IOException {
+ long inputRemaining = source.size();
+ long inputOffset = 0;
+ while (inputRemaining > 0) {
+ int size = (int) Math.min(inputRemaining, chunkSize);
+ source.feedIntoDataDigester(digester, inputOffset, size);
+ inputOffset += size;
+ inputRemaining -= size;
+ }
+ }
+
+ // Rationale: 1) 1 MB should fit in memory space on all devices. 2) It is not too granular
+ // thus the syscall overhead is not too big.
+ private static final int MMAP_REGION_SIZE_BYTES = 1024 * 1024;
+
+ private static void generateApkVerityDigestAtLeafLevel(RandomAccessFile apk,
+ SignatureInfo signatureInfo, byte[] salt, ByteBuffer output)
+ throws IOException, NoSuchAlgorithmException {
+ BufferedDigester digester = new BufferedDigester(salt, output);
+
+ // 1. Digest from the beginning of the file, until APK Signing Block is reached.
+ consumeByChunk(digester,
+ new MemoryMappedFileDataSource(apk.getFD(), 0, signatureInfo.apkSigningBlockOffset),
+ MMAP_REGION_SIZE_BYTES);
+
+ // 2. Skip APK Signing Block and continue digesting, until the Central Directory offset
+ // field in EoCD is reached.
+ long eocdCdOffsetFieldPosition =
+ signatureInfo.eocdOffset + ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_OFFSET;
+ consumeByChunk(digester,
+ new MemoryMappedFileDataSource(apk.getFD(), signatureInfo.centralDirOffset,
+ eocdCdOffsetFieldPosition - signatureInfo.centralDirOffset),
+ MMAP_REGION_SIZE_BYTES);
+
+ // 3. Fill up the rest of buffer with 0s.
+ ByteBuffer alternativeCentralDirOffset = ByteBuffer.allocate(
+ ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE).order(ByteOrder.LITTLE_ENDIAN);
+ alternativeCentralDirOffset.putInt(Math.toIntExact(signatureInfo.apkSigningBlockOffset));
+ alternativeCentralDirOffset.flip();
+ digester.consume(alternativeCentralDirOffset);
+
+ // 4. Read from end of the Central Directory offset field in EoCD to the end of the file.
+ long offsetAfterEocdCdOffsetField =
+ eocdCdOffsetFieldPosition + ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE;
+ consumeByChunk(digester,
+ new MemoryMappedFileDataSource(apk.getFD(), offsetAfterEocdCdOffsetField,
+ apk.length() - offsetAfterEocdCdOffsetField),
+ MMAP_REGION_SIZE_BYTES);
+ digester.finish();
+
+ // 5. Fill up the rest of buffer with 0s.
+ digester.fillUpLastOutputChunk();
+ }
+
+ private static byte[] generateApkVerityTree(RandomAccessFile apk, SignatureInfo signatureInfo,
+ byte[] salt, int[] levelOffset, ByteBuffer output)
+ throws IOException, NoSuchAlgorithmException {
+ // 1. Digest the apk to generate the leaf level hashes.
+ generateApkVerityDigestAtLeafLevel(apk, signatureInfo, salt, slice(output,
+ levelOffset[levelOffset.length - 2], levelOffset[levelOffset.length - 1]));
+
+ // 2. Digest the lower level hashes bottom up.
+ for (int level = levelOffset.length - 3; level >= 0; level--) {
+ ByteBuffer inputBuffer = slice(output, levelOffset[level + 1], levelOffset[level + 2]);
+ ByteBuffer outputBuffer = slice(output, levelOffset[level], levelOffset[level + 1]);
+
+ DataSource source = new ByteBufferDataSource(inputBuffer);
+ BufferedDigester digester = new BufferedDigester(salt, outputBuffer);
+ consumeByChunk(digester, source, CHUNK_SIZE_BYTES);
+ digester.finish();
+
+ digester.fillUpLastOutputChunk();
+ }
+
+ // 3. Digest the first block (i.e. first level) to generate the root hash.
+ byte[] rootHash = new byte[DIGEST_SIZE_BYTES];
+ BufferedDigester digester = new BufferedDigester(salt, ByteBuffer.wrap(rootHash));
+ digester.consume(slice(output, 0, CHUNK_SIZE_BYTES));
+ return rootHash;
+ }
+
+ private static ByteBuffer generateFsverityHeader(long fileSize, byte[] salt) {
+ if (salt.length != 8) {
+ throw new IllegalArgumentException("salt is not 8 bytes long");
+ }
+
+ ByteBuffer buffer = ByteBuffer.allocate(FSVERITY_HEADER_SIZE_BYTES);
+ buffer.order(ByteOrder.LITTLE_ENDIAN);
+
+ // TODO(b/30972906): insert a reference when there is a public one.
+ buffer.put("TrueBrew".getBytes()); // magic
+ buffer.put((byte) 1); // major version
+ buffer.put((byte) 0); // minor version
+ buffer.put((byte) 12); // log2(block-size) == log2(4096)
+ buffer.put((byte) 7); // log2(leaves-per-node) == log2(block-size / digest-size)
+ // == log2(4096 / 32)
+ buffer.putShort((short) 1); // meta algorithm, 1: SHA-256 FIXME finalize constant
+ buffer.putShort((short) 1); // data algorithm, 1: SHA-256 FIXME finalize constant
+ buffer.putInt(0x1); // flags, 0x1: has extension, FIXME also hide it
+ buffer.putInt(0); // reserved
+ buffer.putLong(fileSize); // original i_size
+ buffer.put(salt); // salt (8 bytes)
+
+ // TODO(b/30972906): Add extension.
+
+ buffer.rewind();
+ return buffer;
+ }
+
+ private static ByteBuffer generateFsverityExtensions() {
+ return ByteBuffer.allocate(64); // TODO(b/30972906): implement this.
+ }
+
+ /**
+ * Returns an array of summed area table of level size in the verity tree. In other words, the
+ * returned array is offset of each level in the verity tree file format, plus an additional
+ * offset of the next non-existing level (i.e. end of the last level + 1). Thus the array size
+ * is level + 1. Thus, the returned array is guarantee to have at least 2 elements.
+ */
+ private static int[] calculateVerityLevelOffset(long fileSize) {
+ ArrayList<Long> levelSize = new ArrayList<>();
+ while (true) {
+ long levelDigestSize = divideRoundup(fileSize, CHUNK_SIZE_BYTES) * DIGEST_SIZE_BYTES;
+ long chunksSize = CHUNK_SIZE_BYTES * divideRoundup(levelDigestSize, CHUNK_SIZE_BYTES);
+ levelSize.add(chunksSize);
+ if (levelDigestSize <= CHUNK_SIZE_BYTES) {
+ break;
+ }
+ fileSize = levelDigestSize;
+ }
+
+ // Reverse and convert to summed area table.
+ int[] levelOffset = new int[levelSize.size() + 1];
+ levelOffset[0] = 0;
+ for (int i = 0; i < levelSize.size(); i++) {
+ // We don't support verity tree if it is larger then Integer.MAX_VALUE.
+ levelOffset[i + 1] = levelOffset[i]
+ + Math.toIntExact(levelSize.get(levelSize.size() - i - 1));
+ }
+ return levelOffset;
+ }
+
+ private static void assertSigningBlockAlignedAndHasFullPages(SignatureInfo signatureInfo) {
+ if (signatureInfo.apkSigningBlockOffset % CHUNK_SIZE_BYTES != 0) {
+ throw new IllegalArgumentException(
+ "APK Signing Block does not start at the page boundary: "
+ + signatureInfo.apkSigningBlockOffset);
+ }
+
+ if ((signatureInfo.centralDirOffset - signatureInfo.apkSigningBlockOffset)
+ % CHUNK_SIZE_BYTES != 0) {
+ throw new IllegalArgumentException(
+ "Size of APK Signing Block is not a multiple of 4096: "
+ + (signatureInfo.centralDirOffset - signatureInfo.apkSigningBlockOffset));
+ }
+ }
+
+ /** Returns a slice of the buffer which shares content with the provided buffer. */
+ private static ByteBuffer slice(ByteBuffer buffer, int begin, int end) {
+ ByteBuffer b = buffer.duplicate();
+ b.position(0); // to ensure position <= limit invariant.
+ b.limit(end);
+ b.position(begin);
+ return b.slice();
+ }
+
+ /** Divides a number and round up to the closest integer. */
+ private static long divideRoundup(long dividend, long divisor) {
+ return (dividend + divisor - 1) / divisor;
+ }
+}
diff --git a/core/java/android/util/apk/ByteBufferDataSource.java b/core/java/android/util/apk/ByteBufferDataSource.java
new file mode 100644
index 0000000..c2b9eff
--- /dev/null
+++ b/core/java/android/util/apk/ByteBufferDataSource.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.apk;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * {@link DataSource} which provides data from a {@link ByteBuffer}.
+ */
+class ByteBufferDataSource implements DataSource {
+ /**
+ * Underlying buffer. The data is stored between position 0 and the buffer's capacity.
+ * The buffer's position is 0 and limit is equal to capacity.
+ */
+ private final ByteBuffer mBuf;
+
+ ByteBufferDataSource(ByteBuffer buf) {
+ // Defensive copy, to avoid changes to mBuf being visible in buf, and to ensure position is
+ // 0 and limit == capacity.
+ mBuf = buf.slice();
+ }
+
+ @Override
+ public long size() {
+ return mBuf.capacity();
+ }
+
+ @Override
+ public void feedIntoDataDigester(DataDigester md, long offset, int size)
+ throws IOException {
+ // There's no way to tell MessageDigest to read data from ByteBuffer from a position
+ // other than the buffer's current position. We thus need to change the buffer's
+ // position to match the requested offset.
+ //
+ // In the future, it may be necessary to compute digests of multiple regions in
+ // parallel. Given that digest computation is a slow operation, we enable multiple
+ // such requests to be fulfilled by this instance. This is achieved by serially
+ // creating a new ByteBuffer corresponding to the requested data range and then,
+ // potentially concurrently, feeding these buffers into MessageDigest instances.
+ ByteBuffer region;
+ synchronized (mBuf) {
+ mBuf.position(0);
+ mBuf.limit((int) offset + size);
+ mBuf.position((int) offset);
+ region = mBuf.slice();
+ }
+
+ md.consume(region);
+ }
+}
diff --git a/core/java/android/util/apk/ByteBufferFactory.java b/core/java/android/util/apk/ByteBufferFactory.java
new file mode 100644
index 0000000..7a99882
--- /dev/null
+++ b/core/java/android/util/apk/ByteBufferFactory.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.apk;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Provider of {@link ByteBuffer} instances.
+ * @hide
+ */
+public interface ByteBufferFactory {
+ /** Initiates a {@link ByteBuffer} with the given size. */
+ ByteBuffer create(int capacity);
+}
diff --git a/core/java/android/util/apk/DataDigester.java b/core/java/android/util/apk/DataDigester.java
new file mode 100644
index 0000000..74dce7e
--- /dev/null
+++ b/core/java/android/util/apk/DataDigester.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.apk;
+
+import java.nio.ByteBuffer;
+
+interface DataDigester {
+ /** Consumes the {@link ByteBuffer}. */
+ void consume(ByteBuffer buffer);
+
+ /** Finishes the digestion. Must be called after the last {@link #consume(ByteBuffer)}. */
+ void finish();
+}
diff --git a/core/java/android/util/apk/DataSource.java b/core/java/android/util/apk/DataSource.java
new file mode 100644
index 0000000..2b39f49
--- /dev/null
+++ b/core/java/android/util/apk/DataSource.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.apk;
+
+import java.io.IOException;
+
+/** Source of data to be digested. */
+interface DataSource {
+
+ /**
+ * Returns the size (in bytes) of the data offered by this source.
+ */
+ long size();
+
+ /**
+ * Feeds the specified region of this source's data into the provided digester.
+ *
+ * @param offset offset of the region inside this data source.
+ * @param size size (in bytes) of the region.
+ */
+ void feedIntoDataDigester(DataDigester md, long offset, int size) throws IOException;
+}
diff --git a/core/java/android/util/apk/MemoryMappedFileDataSource.java b/core/java/android/util/apk/MemoryMappedFileDataSource.java
new file mode 100644
index 0000000..04a1c6b
--- /dev/null
+++ b/core/java/android/util/apk/MemoryMappedFileDataSource.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.apk;
+
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.DirectByteBuffer;
+
+/**
+ * {@link DataSource} which provides data from a file descriptor by memory-mapping the sections
+ * of the file.
+ */
+class MemoryMappedFileDataSource implements DataSource {
+ private static final long MEMORY_PAGE_SIZE_BYTES = Os.sysconf(OsConstants._SC_PAGESIZE);
+
+ private final FileDescriptor mFd;
+ private final long mFilePosition;
+ private final long mSize;
+
+ /**
+ * Constructs a new {@code MemoryMappedFileDataSource} for the specified region of the file.
+ *
+ * @param position start position of the region in the file.
+ * @param size size (in bytes) of the region.
+ */
+ MemoryMappedFileDataSource(FileDescriptor fd, long position, long size) {
+ mFd = fd;
+ mFilePosition = position;
+ mSize = size;
+ }
+
+ @Override
+ public long size() {
+ return mSize;
+ }
+
+ @Override
+ public void feedIntoDataDigester(DataDigester md, long offset, int size)
+ throws IOException {
+ // IMPLEMENTATION NOTE: After a lot of experimentation, the implementation of this
+ // method was settled on a straightforward mmap with prefaulting.
+ //
+ // This method is not using FileChannel.map API because that API does not offset a way
+ // to "prefault" the resulting memory pages. Without prefaulting, performance is about
+ // 10% slower on small to medium APKs, but is significantly worse for APKs in 500+ MB
+ // range. FileChannel.load (which currently uses madvise) doesn't help. Finally,
+ // invoking madvise (MADV_SEQUENTIAL) after mmap with prefaulting wastes quite a bit of
+ // time, which is not compensated for by faster reads.
+
+ // We mmap the smallest region of the file containing the requested data. mmap requires
+ // that the start offset in the file must be a multiple of memory page size. We thus may
+ // need to mmap from an offset less than the requested offset.
+ long filePosition = mFilePosition + offset;
+ long mmapFilePosition =
+ (filePosition / MEMORY_PAGE_SIZE_BYTES) * MEMORY_PAGE_SIZE_BYTES;
+ int dataStartOffsetInMmapRegion = (int) (filePosition - mmapFilePosition);
+ long mmapRegionSize = size + dataStartOffsetInMmapRegion;
+ long mmapPtr = 0;
+ try {
+ mmapPtr = Os.mmap(
+ 0, // let the OS choose the start address of the region in memory
+ mmapRegionSize,
+ OsConstants.PROT_READ,
+ OsConstants.MAP_SHARED | OsConstants.MAP_POPULATE, // "prefault" all pages
+ mFd,
+ mmapFilePosition);
+ ByteBuffer buf = new DirectByteBuffer(
+ size,
+ mmapPtr + dataStartOffsetInMmapRegion,
+ mFd, // not really needed, but just in case
+ null, // no need to clean up -- it's taken care of by the finally block
+ true // read only buffer
+ );
+ md.consume(buf);
+ } catch (ErrnoException e) {
+ throw new IOException("Failed to mmap " + mmapRegionSize + " bytes", e);
+ } finally {
+ if (mmapPtr != 0) {
+ try {
+ Os.munmap(mmapPtr, mmapRegionSize);
+ } catch (ErrnoException ignored) { }
+ }
+ }
+ }
+}
diff --git a/core/java/android/util/apk/SignatureInfo.java b/core/java/android/util/apk/SignatureInfo.java
new file mode 100644
index 0000000..8e1233a
--- /dev/null
+++ b/core/java/android/util/apk/SignatureInfo.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.apk;
+
+import java.nio.ByteBuffer;
+
+/**
+ * APK Signature Scheme v2 block and additional information relevant to verifying the signatures
+ * contained in the block against the file.
+ */
+class SignatureInfo {
+ /** Contents of APK Signature Scheme v2 block. */
+ public final ByteBuffer signatureBlock;
+
+ /** Position of the APK Signing Block in the file. */
+ public final long apkSigningBlockOffset;
+
+ /** Position of the ZIP Central Directory in the file. */
+ public final long centralDirOffset;
+
+ /** Position of the ZIP End of Central Directory (EoCD) in the file. */
+ public final long eocdOffset;
+
+ /** Contents of ZIP End of Central Directory (EoCD) of the file. */
+ public final ByteBuffer eocd;
+
+ SignatureInfo(ByteBuffer signatureBlock, long apkSigningBlockOffset, long centralDirOffset,
+ long eocdOffset, ByteBuffer eocd) {
+ this.signatureBlock = signatureBlock;
+ this.apkSigningBlockOffset = apkSigningBlockOffset;
+ this.centralDirOffset = centralDirOffset;
+ this.eocdOffset = eocdOffset;
+ this.eocd = eocd;
+ }
+}
diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java
index 5804560..ab0b3ee 100644
--- a/core/java/android/view/NotificationHeaderView.java
+++ b/core/java/android/view/NotificationHeaderView.java
@@ -20,6 +20,7 @@
import android.app.Notification;
import android.content.Context;
import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Outline;
import android.graphics.Rect;
@@ -43,6 +44,7 @@
public static final int NO_COLOR = Notification.COLOR_INVALID;
private final int mChildMinWidth;
private final int mContentEndMargin;
+ private final int mGravity;
private View mAppName;
private View mHeaderText;
private OnClickListener mExpandClickListener;
@@ -50,7 +52,6 @@
private ImageView mExpandButton;
private CachingIconView mIcon;
private View mProfileBadge;
- private View mInfo;
private int mIconColor;
private int mOriginalNotificationColor;
private boolean mExpanded;
@@ -61,6 +62,7 @@
private boolean mEntireHeaderClickable;
private boolean mExpandOnlyOnButton;
private boolean mAcceptAllTouches;
+ private int mTotalWidth;
ViewOutlineProvider mProvider = new ViewOutlineProvider() {
@Override
@@ -92,6 +94,11 @@
mHeaderBackgroundHeight = res.getDimensionPixelSize(
R.dimen.notification_header_background_height);
mEntireHeaderClickable = res.getBoolean(R.bool.config_notificationHeaderClickableForExpand);
+
+ int[] attrIds = { android.R.attr.gravity };
+ TypedArray ta = context.obtainStyledAttributes(attrs, attrIds, defStyleAttr, defStyleRes);
+ mGravity = ta.getInt(0, 0);
+ ta.recycle();
}
@Override
@@ -146,6 +153,7 @@
mHeaderText.measure(childWidthSpec, wrapContentHeightSpec);
}
}
+ mTotalWidth = Math.min(totalWidth, givenWidth);
setMeasuredDimension(givenWidth, givenHeight);
}
@@ -153,6 +161,10 @@
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int left = getPaddingStart();
int end = getMeasuredWidth();
+ final boolean centerAligned = (mGravity & Gravity.CENTER_HORIZONTAL) != 0;
+ if (centerAligned) {
+ left += getMeasuredWidth() / 2 - mTotalWidth / 2;
+ }
int childCount = getChildCount();
int ownHeight = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
for (int i = 0; i < childCount; i++) {
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 6f8315a..cd84147 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -1206,56 +1206,65 @@
}
public Transaction show(SurfaceControl sc) {
+ sc.checkNotReleased();
nativeSetFlags(mNativeObject, sc.mNativeObject, 0, SURFACE_HIDDEN);
return this;
}
public Transaction hide(SurfaceControl sc) {
+ sc.checkNotReleased();
nativeSetFlags(mNativeObject, sc.mNativeObject, SURFACE_HIDDEN, SURFACE_HIDDEN);
return this;
}
public Transaction setPosition(SurfaceControl sc, float x, float y) {
+ sc.checkNotReleased();
nativeSetPosition(mNativeObject, sc.mNativeObject, x, y);
return this;
}
public Transaction setSize(SurfaceControl sc, int w, int h) {
- nativeSetSize(mNativeObject, sc.mNativeObject,
- w, h);
+ sc.checkNotReleased();
+ nativeSetSize(mNativeObject, sc.mNativeObject, w, h);
return this;
}
public Transaction setLayer(SurfaceControl sc, int z) {
+ sc.checkNotReleased();
nativeSetLayer(mNativeObject, sc.mNativeObject, z);
return this;
}
public Transaction setRelativeLayer(SurfaceControl sc, SurfaceControl relativeTo, int z) {
+ sc.checkNotReleased();
nativeSetRelativeLayer(mNativeObject, sc.mNativeObject,
relativeTo.getHandle(), z);
return this;
}
public Transaction setTransparentRegionHint(SurfaceControl sc, Region transparentRegion) {
+ sc.checkNotReleased();
nativeSetTransparentRegionHint(mNativeObject,
sc.mNativeObject, transparentRegion);
return this;
}
public Transaction setAlpha(SurfaceControl sc, float alpha) {
+ sc.checkNotReleased();
nativeSetAlpha(mNativeObject, sc.mNativeObject, alpha);
return this;
}
public Transaction setMatrix(SurfaceControl sc,
float dsdx, float dtdx, float dtdy, float dsdy) {
+ sc.checkNotReleased();
nativeSetMatrix(mNativeObject, sc.mNativeObject,
dsdx, dtdx, dtdy, dsdy);
return this;
}
public Transaction setWindowCrop(SurfaceControl sc, Rect crop) {
+ sc.checkNotReleased();
if (crop != null) {
nativeSetWindowCrop(mNativeObject, sc.mNativeObject,
crop.left, crop.top, crop.right, crop.bottom);
@@ -1267,6 +1276,7 @@
}
public Transaction setFinalCrop(SurfaceControl sc, Rect crop) {
+ sc.checkNotReleased();
if (crop != null) {
nativeSetFinalCrop(mNativeObject, sc.mNativeObject,
crop.left, crop.top, crop.right, crop.bottom);
@@ -1278,40 +1288,48 @@
}
public Transaction setLayerStack(SurfaceControl sc, int layerStack) {
+ sc.checkNotReleased();
nativeSetLayerStack(mNativeObject, sc.mNativeObject, layerStack);
return this;
}
- public Transaction deferTransactionUntil(SurfaceControl sc, IBinder handle, long frameNumber) {
+ public Transaction deferTransactionUntil(SurfaceControl sc, IBinder handle,
+ long frameNumber) {
+ sc.checkNotReleased();
nativeDeferTransactionUntil(mNativeObject, sc.mNativeObject, handle, frameNumber);
return this;
}
public Transaction deferTransactionUntilSurface(SurfaceControl sc, Surface barrierSurface,
long frameNumber) {
+ sc.checkNotReleased();
nativeDeferTransactionUntilSurface(mNativeObject, sc.mNativeObject,
barrierSurface.mNativeObject, frameNumber);
return this;
}
public Transaction reparentChildren(SurfaceControl sc, IBinder newParentHandle) {
+ sc.checkNotReleased();
nativeReparentChildren(mNativeObject, sc.mNativeObject, newParentHandle);
return this;
}
/** Re-parents a specific child layer to a new parent */
public Transaction reparent(SurfaceControl sc, IBinder newParentHandle) {
+ sc.checkNotReleased();
nativeReparent(mNativeObject, sc.mNativeObject,
newParentHandle);
return this;
}
public Transaction detachChildren(SurfaceControl sc) {
+ sc.checkNotReleased();
nativeSeverChildren(mNativeObject, sc.mNativeObject);
return this;
}
public Transaction setOverrideScalingMode(SurfaceControl sc, int overrideScalingMode) {
+ sc.checkNotReleased();
nativeSetOverrideScalingMode(mNativeObject, sc.mNativeObject,
overrideScalingMode);
return this;
@@ -1322,6 +1340,7 @@
* @param color A float array with three values to represent r, g, b in range [0..1]
*/
public Transaction setColor(SurfaceControl sc, @Size(3) float[] color) {
+ sc.checkNotReleased();
nativeSetColor(mNativeObject, sc.mNativeObject, color);
return this;
}
@@ -1334,6 +1353,7 @@
* (at which point the geometry influencing aspects of this transaction will then occur)
*/
public Transaction setGeometryAppliesWithResize(SurfaceControl sc) {
+ sc.checkNotReleased();
nativeSetGeometryAppliesWithResize(mNativeObject, sc.mNativeObject);
return this;
}
@@ -1343,6 +1363,7 @@
* Surface with the {@link #SECURE} flag.
*/
Transaction setSecure(SurfaceControl sc, boolean isSecure) {
+ sc.checkNotReleased();
if (isSecure) {
nativeSetFlags(mNativeObject, sc.mNativeObject, SECURE, SECURE);
} else {
@@ -1356,6 +1377,7 @@
* Surface with the {@link #OPAQUE} flag.
*/
public Transaction setOpaque(SurfaceControl sc, boolean isOpaque) {
+ sc.checkNotReleased();
if (isOpaque) {
nativeSetFlags(mNativeObject, sc.mNativeObject, SURFACE_OPAQUE, SURFACE_OPAQUE);
} else {
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index 19213ca..c3d6c69 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -187,8 +187,11 @@
Log.i(LOG_TAG, "Window cache miss");
}
final long identityToken = Binder.clearCallingIdentity();
- window = connection.getWindow(accessibilityWindowId);
- Binder.restoreCallingIdentity(identityToken);
+ try {
+ window = connection.getWindow(accessibilityWindowId);
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
if (window != null) {
sAccessibilityCache.addWindow(window);
return window;
@@ -225,8 +228,11 @@
Log.i(LOG_TAG, "Windows cache miss");
}
final long identityToken = Binder.clearCallingIdentity();
- windows = connection.getWindows();
- Binder.restoreCallingIdentity(identityToken);
+ try {
+ windows = connection.getWindows();
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
if (windows != null) {
sAccessibilityCache.setWindows(windows);
return windows;
@@ -283,10 +289,14 @@
}
final int interactionId = mInteractionIdCounter.getAndIncrement();
final long identityToken = Binder.clearCallingIdentity();
- final boolean success = connection.findAccessibilityNodeInfoByAccessibilityId(
- accessibilityWindowId, accessibilityNodeId, interactionId, this,
- prefetchFlags, Thread.currentThread().getId(), arguments);
- Binder.restoreCallingIdentity(identityToken);
+ final boolean success;
+ try {
+ success = connection.findAccessibilityNodeInfoByAccessibilityId(
+ accessibilityWindowId, accessibilityNodeId, interactionId, this,
+ prefetchFlags, Thread.currentThread().getId(), arguments);
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
if (success) {
List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
interactionId);
@@ -333,10 +343,15 @@
if (connection != null) {
final int interactionId = mInteractionIdCounter.getAndIncrement();
final long identityToken = Binder.clearCallingIdentity();
- final boolean success = connection.findAccessibilityNodeInfosByViewId(
- accessibilityWindowId, accessibilityNodeId, viewId, interactionId, this,
- Thread.currentThread().getId());
- Binder.restoreCallingIdentity(identityToken);
+ final boolean success;
+ try {
+ success = connection.findAccessibilityNodeInfosByViewId(
+ accessibilityWindowId, accessibilityNodeId, viewId, interactionId, this,
+ Thread.currentThread().getId());
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
+
if (success) {
List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
interactionId);
@@ -381,10 +396,15 @@
if (connection != null) {
final int interactionId = mInteractionIdCounter.getAndIncrement();
final long identityToken = Binder.clearCallingIdentity();
- final boolean success = connection.findAccessibilityNodeInfosByText(
- accessibilityWindowId, accessibilityNodeId, text, interactionId, this,
- Thread.currentThread().getId());
- Binder.restoreCallingIdentity(identityToken);
+ final boolean success;
+ try {
+ success = connection.findAccessibilityNodeInfosByText(
+ accessibilityWindowId, accessibilityNodeId, text, interactionId, this,
+ Thread.currentThread().getId());
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
+
if (success) {
List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
interactionId);
@@ -428,10 +448,15 @@
if (connection != null) {
final int interactionId = mInteractionIdCounter.getAndIncrement();
final long identityToken = Binder.clearCallingIdentity();
- final boolean success = connection.findFocus(accessibilityWindowId,
- accessibilityNodeId, focusType, interactionId, this,
- Thread.currentThread().getId());
- Binder.restoreCallingIdentity(identityToken);
+ final boolean success;
+ try {
+ success = connection.findFocus(accessibilityWindowId,
+ accessibilityNodeId, focusType, interactionId, this,
+ Thread.currentThread().getId());
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
+
if (success) {
AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(
interactionId);
@@ -472,10 +497,15 @@
if (connection != null) {
final int interactionId = mInteractionIdCounter.getAndIncrement();
final long identityToken = Binder.clearCallingIdentity();
- final boolean success = connection.focusSearch(accessibilityWindowId,
- accessibilityNodeId, direction, interactionId, this,
- Thread.currentThread().getId());
- Binder.restoreCallingIdentity(identityToken);
+ final boolean success;
+ try {
+ success = connection.focusSearch(accessibilityWindowId,
+ accessibilityNodeId, direction, interactionId, this,
+ Thread.currentThread().getId());
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
+
if (success) {
AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(
interactionId);
@@ -515,10 +545,15 @@
if (connection != null) {
final int interactionId = mInteractionIdCounter.getAndIncrement();
final long identityToken = Binder.clearCallingIdentity();
- final boolean success = connection.performAccessibilityAction(
- accessibilityWindowId, accessibilityNodeId, action, arguments,
- interactionId, this, Thread.currentThread().getId());
- Binder.restoreCallingIdentity(identityToken);
+ final boolean success;
+ try {
+ success = connection.performAccessibilityAction(
+ accessibilityWindowId, accessibilityNodeId, action, arguments,
+ interactionId, this, Thread.currentThread().getId());
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
+
if (success) {
return getPerformAccessibilityActionResultAndClear(interactionId);
}
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 0b9bc57..35f6acb 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -436,8 +436,11 @@
// client using it is called through Binder from another process. Example: MMS
// app adds a SMS notification and the NotificationManagerService calls this method
long identityToken = Binder.clearCallingIdentity();
- service.sendAccessibilityEvent(event, userId);
- Binder.restoreCallingIdentity(identityToken);
+ try {
+ service.sendAccessibilityEvent(event, userId);
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
if (DEBUG) {
Log.i(LOG_TAG, event + " sent");
}
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 6a0669b..a56f86d 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -1897,7 +1897,7 @@
public abstract static class AutofillCallback {
/** @hide */
- @IntDef({EVENT_INPUT_SHOWN, EVENT_INPUT_HIDDEN})
+ @IntDef({EVENT_INPUT_SHOWN, EVENT_INPUT_HIDDEN, EVENT_INPUT_UNAVAILABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface AutofillEventType {}
diff --git a/core/java/com/android/internal/colorextraction/types/Tonal.java b/core/java/com/android/internal/colorextraction/types/Tonal.java
index e6ef10b..71baaf1 100644
--- a/core/java/com/android/internal/colorextraction/types/Tonal.java
+++ b/core/java/com/android/internal/colorextraction/types/Tonal.java
@@ -51,9 +51,11 @@
private static final boolean DEBUG = true;
+ public static final int THRESHOLD_COLOR_LIGHT = 0xffe0e0e0;
public static final int MAIN_COLOR_LIGHT = 0xffe0e0e0;
public static final int SECONDARY_COLOR_LIGHT = 0xff9e9e9e;
- public static final int MAIN_COLOR_DARK = 0xff212121;
+ public static final int THRESHOLD_COLOR_DARK = 0xff212121;
+ public static final int MAIN_COLOR_DARK = 0xff000000;
public static final int SECONDARY_COLOR_DARK = 0xff000000;
private final TonalPalette mGreyPalette;
@@ -197,12 +199,12 @@
// light fallback or darker than our dark fallback.
ColorUtils.colorToHSL(mainColor, mTmpHSL);
final float mainLuminosity = mTmpHSL[2];
- ColorUtils.colorToHSL(MAIN_COLOR_LIGHT, mTmpHSL);
+ ColorUtils.colorToHSL(THRESHOLD_COLOR_LIGHT, mTmpHSL);
final float lightLuminosity = mTmpHSL[2];
if (mainLuminosity > lightLuminosity) {
return false;
}
- ColorUtils.colorToHSL(MAIN_COLOR_DARK, mTmpHSL);
+ ColorUtils.colorToHSL(THRESHOLD_COLOR_DARK, mTmpHSL);
final float darkLuminosity = mTmpHSL[2];
if (mainLuminosity < darkLuminosity) {
return false;
diff --git a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
index fb6b8b0..3af3e2a 100644
--- a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
+++ b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
@@ -16,6 +16,10 @@
package com.android.internal.policy;
+import static android.view.WindowManager.DOCKED_INVALID;
+import static android.view.WindowManager.DOCKED_LEFT;
+import static android.view.WindowManager.DOCKED_RIGHT;
+
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -99,11 +103,12 @@
public DividerSnapAlgorithm(Resources res, int displayWidth, int displayHeight, int dividerSize,
boolean isHorizontalDivision, Rect insets) {
- this(res, displayWidth, displayHeight, dividerSize, isHorizontalDivision, insets, false);
+ this(res, displayWidth, displayHeight, dividerSize, isHorizontalDivision, insets,
+ DOCKED_INVALID, false);
}
public DividerSnapAlgorithm(Resources res, int displayWidth, int displayHeight, int dividerSize,
- boolean isHorizontalDivision, Rect insets, boolean isMinimizedMode) {
+ boolean isHorizontalDivision, Rect insets, int dockSide, boolean isMinimizedMode) {
mMinFlingVelocityPxPerSecond =
MIN_FLING_VELOCITY_DP_PER_SECOND * res.getDisplayMetrics().density;
mMinDismissVelocityPxPerSecond =
@@ -121,7 +126,7 @@
com.android.internal.R.dimen.default_minimal_size_resizable_task);
mTaskHeightInMinimizedMode = res.getDimensionPixelSize(
com.android.internal.R.dimen.task_height_of_minimized_mode);
- calculateTargets(isHorizontalDivision);
+ calculateTargets(isHorizontalDivision, dockSide);
mFirstSplitTarget = mTargets.get(1);
mLastSplitTarget = mTargets.get(mTargets.size() - 2);
mDismissStartTarget = mTargets.get(0);
@@ -254,7 +259,7 @@
return mTargets.get(minIndex);
}
- private void calculateTargets(boolean isHorizontalDivision) {
+ private void calculateTargets(boolean isHorizontalDivision, int dockedSide) {
mTargets.clear();
int dividerMax = isHorizontalDivision
? mDisplayHeight
@@ -273,7 +278,7 @@
addMiddleTarget(isHorizontalDivision);
break;
case SNAP_MODE_MINIMIZED:
- addMinimizedTarget(isHorizontalDivision);
+ addMinimizedTarget(isHorizontalDivision, dockedSide);
break;
}
mTargets.add(new SnapTarget(dividerMax - navBarSize, dividerMax,
@@ -331,12 +336,16 @@
mTargets.add(new SnapTarget(position, position, SnapTarget.FLAG_NONE));
}
- private void addMinimizedTarget(boolean isHorizontalDivision) {
+ private void addMinimizedTarget(boolean isHorizontalDivision, int dockedSide) {
// In portrait offset the position by the statusbar height, in landscape add the statusbar
// height as well to match portrait offset
int position = mTaskHeightInMinimizedMode + mInsets.top;
if (!isHorizontalDivision) {
- position += mInsets.left;
+ if (dockedSide == DOCKED_LEFT) {
+ position += mInsets.left;
+ } else if (dockedSide == DOCKED_RIGHT) {
+ position = mDisplayWidth - position - mInsets.right;
+ }
}
mTargets.add(new SnapTarget(position, position, SnapTarget.FLAG_NONE));
}
diff --git a/core/java/com/android/internal/widget/NotificationActionListLayout.java b/core/java/com/android/internal/widget/NotificationActionListLayout.java
index 073aac5..26023b4 100644
--- a/core/java/com/android/internal/widget/NotificationActionListLayout.java
+++ b/core/java/com/android/internal/widget/NotificationActionListLayout.java
@@ -16,7 +16,10 @@
package com.android.internal.widget;
+import android.annotation.Nullable;
import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Pair;
@@ -37,6 +40,7 @@
@RemoteViews.RemoteView
public class NotificationActionListLayout extends LinearLayout {
+ private final int mGravity;
private int mTotalWidth = 0;
private ArrayList<Pair<Integer, TextView>> mMeasureOrderTextViews = new ArrayList<>();
private ArrayList<View> mMeasureOrderOther = new ArrayList<>();
@@ -45,7 +49,20 @@
private Drawable mDefaultBackground;
public NotificationActionListLayout(Context context, AttributeSet attrs) {
- super(context, attrs);
+ this(context, attrs, 0);
+ }
+
+ public NotificationActionListLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public NotificationActionListLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+
+ int[] attrIds = { android.R.attr.gravity };
+ TypedArray ta = context.obtainStyledAttributes(attrs, attrIds, defStyleAttr, defStyleRes);
+ mGravity = ta.getInt(0, 0);
+ ta.recycle();
}
@Override
@@ -95,6 +112,7 @@
final boolean constrained =
MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED;
+ final boolean centerAligned = (mGravity & Gravity.CENTER_HORIZONTAL) != 0;
final int innerWidth = MeasureSpec.getSize(widthMeasureSpec) - mPaddingLeft - mPaddingRight;
final int otherSize = mMeasureOrderOther.size();
@@ -137,7 +155,7 @@
// Make sure to measure the last child full-width if we didn't use up the entire width,
// or we didn't measure yet because there's just one child.
- if (lastNotGoneChild != null && (constrained && usedWidth < innerWidth
+ if (lastNotGoneChild != null && !centerAligned && (constrained && usedWidth < innerWidth
|| notGoneChildren == 1)) {
MarginLayoutParams lp = (MarginLayoutParams) lastNotGoneChild.getLayoutParams();
if (notGoneChildren > 1) {
@@ -201,9 +219,10 @@
}
final boolean isLayoutRtl = isLayoutRtl();
final int paddingTop = mPaddingTop;
+ final boolean centerAligned = (mGravity & Gravity.CENTER_HORIZONTAL) != 0;
int childTop;
- int childLeft;
+ int childLeft = centerAligned ? left + (right - left) / 2 - mTotalWidth / 2 : 0;
// Where bottom of child should go
final int height = bottom - top;
@@ -216,13 +235,12 @@
final int layoutDirection = getLayoutDirection();
switch (Gravity.getAbsoluteGravity(Gravity.START, layoutDirection)) {
case Gravity.RIGHT:
- // mTotalWidth contains the padding already
- childLeft = mPaddingLeft + right - left - mTotalWidth;
+ childLeft += mPaddingLeft + right - left - mTotalWidth;
break;
case Gravity.LEFT:
default:
- childLeft = mPaddingLeft;
+ childLeft += mPaddingLeft;
break;
}
diff --git a/core/jni/android_os_HwBlob.cpp b/core/jni/android_os_HwBlob.cpp
index 737ec47..bb916d2 100644
--- a/core/jni/android_os_HwBlob.cpp
+++ b/core/jni/android_os_HwBlob.cpp
@@ -26,6 +26,7 @@
#include <android_runtime/AndroidRuntime.h>
#include <hidl/Status.h>
#include <nativehelper/ScopedLocalRef.h>
+#include <nativehelper/ScopedPrimitiveArray.h>
#include "core_jni_helpers.h"
@@ -349,6 +350,13 @@
static_cast<const uint8_t *>(blob->data()) + offset)); \
}
+DEFINE_BLOB_ARRAY_COPIER(Int8,jbyte,Byte)
+DEFINE_BLOB_ARRAY_COPIER(Int16,jshort,Short)
+DEFINE_BLOB_ARRAY_COPIER(Int32,jint,Int)
+DEFINE_BLOB_ARRAY_COPIER(Int64,jlong,Long)
+DEFINE_BLOB_ARRAY_COPIER(Float,jfloat,Float)
+DEFINE_BLOB_ARRAY_COPIER(Double,jdouble,Double)
+
static void JHwBlob_native_copyToBoolArray(
JNIEnv *env,
jobject thiz,
@@ -386,13 +394,6 @@
dst = nullptr;
}
-DEFINE_BLOB_ARRAY_COPIER(Int8,jbyte,Byte)
-DEFINE_BLOB_ARRAY_COPIER(Int16,jshort,Short)
-DEFINE_BLOB_ARRAY_COPIER(Int32,jint,Int)
-DEFINE_BLOB_ARRAY_COPIER(Int64,jlong,Long)
-DEFINE_BLOB_ARRAY_COPIER(Float,jfloat,Float)
-DEFINE_BLOB_ARRAY_COPIER(Double,jdouble,Double)
-
#define DEFINE_BLOB_PUTTER(Suffix,Type) \
static void JHwBlob_native_put ## Suffix( \
JNIEnv *env, jobject thiz, jlong offset, Type x) { \
@@ -458,23 +459,17 @@
#define DEFINE_BLOB_ARRAY_PUTTER(Suffix,Type,NewType) \
static void JHwBlob_native_put ## Suffix ## Array( \
JNIEnv *env, jobject thiz, jlong offset, Type ## Array array) { \
+ Scoped ## NewType ## ArrayRO autoArray(env, array); \
\
if (array == nullptr) { \
- jniThrowException(env, "java/lang/NullPointerException", nullptr); \
+ /* NullpointerException already pending */ \
return; \
} \
\
sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz); \
\
- jsize len = env->GetArrayLength(array); \
- \
- Type *src = \
- env->Get ## NewType ## ArrayElements(array, nullptr /* isCopy */); \
- \
- status_t err = blob->write(offset, src, len * sizeof(Type)); \
- \
- env->Release ## NewType ## ArrayElements(array, src, 0 /* mode */); \
- src = nullptr; \
+ status_t err = blob->write( \
+ offset, autoArray.get(), autoArray.size() * sizeof(Type)); \
\
if (err != OK) { \
signalExceptionForError(env, err); \
@@ -490,35 +485,28 @@
static void JHwBlob_native_putBoolArray(
JNIEnv *env, jobject thiz, jlong offset, jbooleanArray array) {
+ ScopedBooleanArrayRO autoArray(env, array);
if (array == nullptr) {
- jniThrowException(env, "java/lang/NullPointerException", nullptr);
+ /* NullpointerException already pending */
return;
}
sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);
- jsize len = env->GetArrayLength(array);
-
- if ((offset + len * sizeof(bool)) > blob->size()) {
+ if ((offset + autoArray.size() * sizeof(bool)) > blob->size()) {
signalExceptionForError(env, -ERANGE);
return;
}
- const jboolean *src =
- env->GetBooleanArrayElements(array, nullptr /* isCopy */);
+ const jboolean *src = autoArray.get();
bool *dst = reinterpret_cast<bool *>(
static_cast<uint8_t *>(blob->data()) + offset);
- for (jsize i = 0; i < len; ++i) {
+ for (size_t i = 0; i < autoArray.size(); ++i) {
dst[i] = src[i];
}
-
- env->ReleaseBooleanArrayElements(
- array, const_cast<jboolean *>(src), 0 /* mode */);
-
- src = nullptr;
}
static void JHwBlob_native_putBlob(
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index dea38e8..1350f3f 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -171,6 +171,7 @@
// Garbage collect if we've allocated at least GC_INTERVAL refs since the last time.
// TODO: Consider removing this completely. We should no longer be generating GlobalRefs
// that are reclaimed as a result of GC action.
+__attribute__((no_sanitize("unsigned-integer-overflow")))
static void gcIfManyNewRefs(JNIEnv* env)
{
uint32_t totalRefs = gNumLocalRefsCreated.load(std::memory_order_relaxed)
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 77bfec3..4a4de24 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3062,10 +3062,10 @@
android:protectionLevel="signature|privileged|development|appop" />
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
- <!-- @hide Allows an application to change the app idle state of an app.
+ <!-- @hide @SystemApi Allows an application to change the app idle state of an app.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.CHANGE_APP_IDLE_STATE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature|privileged" />
<!-- @hide @SystemApi Allows an application to temporarily whitelist an inactive app to
access the network and acquire wakelocks.
diff --git a/core/res/res/drawable/dialog_background_material.xml b/core/res/res/drawable/dialog_background_material.xml
index 2f8d1fa..e017d3c 100644
--- a/core/res/res/drawable/dialog_background_material.xml
+++ b/core/res/res/drawable/dialog_background_material.xml
@@ -17,7 +17,7 @@
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:inset="16dp">
<shape android:shape="rectangle">
- <corners android:radius="2dp" />
+ <corners android:radius="?attr/dialogCornerRadius" />
<solid android:color="?attr/colorBackground" />
</shape>
</inset>
diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml
index f0c980c..3a28f4d 100644
--- a/core/res/res/layout/notification_template_header.xml
+++ b/core/res/res/layout/notification_template_header.xml
@@ -37,6 +37,7 @@
android:textAppearance="?attr/notificationHeaderTextAppearance"
android:layout_marginStart="@dimen/notification_header_app_name_margin_start"
android:layout_marginEnd="@dimen/notification_header_separating_margin"
+ android:visibility="?attr/notificationHeaderAppNameVisibility"
android:singleLine="true"
/>
<TextView
diff --git a/core/res/res/layout/notification_template_material_ambient.xml b/core/res/res/layout/notification_template_material_ambient.xml
index ee5c758..865685f 100644
--- a/core/res/res/layout/notification_template_material_ambient.xml
+++ b/core/res/res/layout/notification_template_material_ambient.xml
@@ -23,8 +23,8 @@
android:paddingStart="@dimen/notification_extra_margin_ambient"
android:paddingEnd="@dimen/notification_extra_margin_ambient"
>
- <include layout="@layout/notification_template_header"
- android:theme="@style/Theme.Material.Notification.Ambient" />
+ <include layout="@layout/notification_template_ambient_header"
+ android:theme="@style/Theme.Material.Notification.Ambient" />
<LinearLayout
android:id="@+id/notification_action_list_margin_target"
@@ -53,6 +53,7 @@
android:textAppearance="@style/TextAppearance.Material.Notification.Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:gravity="top|center_horizontal"
android:singleLine="true"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
@@ -65,7 +66,7 @@
android:textAppearance="@style/TextAppearance.Material.Notification"
android:singleLine="false"
android:layout_weight="1"
- android:gravity="top"
+ android:gravity="top|center_horizontal"
android:visibility="gone"
android:textSize="16sp"
android:textColor="#eeffffff"
@@ -75,5 +76,19 @@
/>
</LinearLayout>
</LinearLayout>
- <include layout="@layout/notification_material_action_list" />
+ <FrameLayout android:id="@+id/actions_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom">
+ <com.android.internal.widget.NotificationActionListLayout
+ android:id="@+id/actions"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/notification_action_list_height"
+ android:paddingEnd="4dp"
+ android:orientation="horizontal"
+ android:gravity="center"
+ android:visibility="gone"
+ android:background="@color/notification_action_list"
+ />
+ </FrameLayout>
</FrameLayout>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index db4dcd2..0eefec9 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -984,6 +984,8 @@
<attr name="dialogTitleDecorLayout" format="reference" />
<!-- Preferred padding for dialog content. -->
<attr name="dialogPreferredPadding" format="dimension" />
+ <!-- Corner radius of dialogs. -->
+ <attr name="dialogCornerRadius" format="dimension" />
<!-- Theme to use for alert dialogs spawned from this theme. -->
<attr name="alertDialogTheme" format="reference" />
@@ -8713,6 +8715,14 @@
<attr name="notificationHeaderStyle" format="reference" />
<attr name="notificationHeaderTextAppearance" format="reference" />
<attr name="notificationHeaderIconSize" format="dimension" />
+ <attr name="notificationHeaderAppNameVisibility" format="enum">
+ <!-- Visible on screen; the default value. -->
+ <enum name="visible" value="0" />
+ <!-- Not displayed, but taken into account during layout (space is left for it). -->
+ <enum name="invisible" value="1" />
+ <!-- Completely hidden, as if the view had not been added. -->
+ <enum name="gone" value="2" />
+ </attr>
</declare-styleable>
<attr name="lockPatternStyle" format="reference" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index bce950d..1c2e5a4 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2524,7 +2524,13 @@
<bool name="config_networkSamplingWakesDevice">true</bool>
- <string-array translatable="false" name="config_cdma_home_system" />
+ <!-- Home (non-roaming) values for CDMA roaming indicator.
+ Carriers can override this table by resource overlay. If not,
+ the default values come from 3GPP2 C.R1001 table
+ 8.1-1. Enhanced Roaming Indicator Number Assignments -->
+ <string-array translatable="false" name="config_cdma_home_system">
+ <item>1</item>
+ </string-array>
<!--From SmsMessage-->
<!--Support decoding the user data payload as pack GSM 8-bit (a GSM alphabet
@@ -3152,4 +3158,7 @@
<!-- Component name of media projection permission dialog -->
<string name="config_mediaProjectionPermissionDialogComponent" translateable="false">com.android.systemui/com.android.systemui.media.MediaProjectionPermissionActivity</string>
+
+ <!-- Corner radius of system dialogs -->
+ <dimen name="config_dialogCornerRadius">2dp</dimen>
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index dc75ba6..947fcf1 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -624,4 +624,7 @@
<dimen name="slice_icon_size">24dp</dimen>
<!-- Standard padding used in a slice view -->
<dimen name="slice_padding">16dp</dimen>
+
+ <!-- Default dialog corner radius -->
+ <dimen name="dialog_corner_radius">2dp</dimen>
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 083bf90..fdd56c4 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2847,6 +2847,7 @@
<public name="cantSaveState" />
<public name="ttcIndex" />
<public name="fontVariationSettings" />
+ <public name="dialogCornerRadius" />
</public-group>
<public-group type="style" first-id="0x010302e0">
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 470ac52..cddf99a 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -1296,6 +1296,11 @@
<item name="layout_marginBottom">@dimen/notification_header_margin_bottom</item>
<item name="paddingStart">@dimen/notification_content_margin_start</item>
<item name="paddingEnd">16dp</item>
+ <item name="gravity">top</item>
+ </style>
+
+ <style name="Notification.Header.Ambient">
+ <item name="gravity">top|center_horizontal</item>
</style>
</resources>
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index bf0c906..68d5523 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -88,6 +88,7 @@
<!-- Dialog attributes -->
<item name="dialogTheme">@style/Theme.DeviceDefault.Dialog</item>
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<!-- AlertDialog attributes -->
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
@@ -214,6 +215,10 @@
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar. This theme
@@ -223,6 +228,10 @@
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar and
@@ -234,6 +243,10 @@
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault} that has no title bar and translucent
@@ -244,6 +257,10 @@
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
</style>
<!-- DeviceDefault theme for dialog windows and activities. This changes the window to be
@@ -263,6 +280,10 @@
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Dialog} that has a nice minimum width for a
@@ -272,6 +293,10 @@
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Dialog} without an action bar -->
@@ -280,6 +305,10 @@
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Dialog_NoActionBar} that has a nice minimum width
@@ -289,6 +318,10 @@
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
</style>
<!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. -->
@@ -314,6 +347,10 @@
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
</style>
<!-- DeviceDefault theme for a window without an action bar that will be displayed either
@@ -324,6 +361,10 @@
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
</style>
<!-- DeviceDefault theme for a presentation window on a secondary display. -->
@@ -332,6 +373,10 @@
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
</style>
<!-- DeviceDefault theme for panel windows. This removes all extraneous window
@@ -342,6 +387,10 @@
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
</style>
<!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
@@ -351,6 +400,10 @@
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
</style>
<!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
@@ -360,6 +413,10 @@
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
</style>
<!-- DeviceDefault style for input methods, which is used by the
@@ -369,6 +426,10 @@
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<!-- DeviceDefault style for input methods, which is used by the
@@ -378,11 +439,19 @@
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Material.Dialog.Alert">
<item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault</item>
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
+
<!-- Color palette -->
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
@@ -394,6 +463,10 @@
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
</style>
<style name="Theme.DeviceDefault.Dialog.NoFrame" parent="Theme.Material.Dialog.NoFrame">
@@ -401,6 +474,10 @@
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault} with a light-colored style -->
@@ -441,6 +518,7 @@
<!-- Dialog attributes -->
<item name="dialogTheme">@style/Theme.DeviceDefault.Light.Dialog</item>
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<!-- AlertDialog attributes -->
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
@@ -562,6 +640,10 @@
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar -->
@@ -570,6 +652,10 @@
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar.
@@ -579,6 +665,10 @@
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar
@@ -590,6 +680,10 @@
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light} that has no title bar and translucent
@@ -600,6 +694,10 @@
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<!-- DeviceDefault light theme for dialog windows and activities. This changes the window to be
@@ -609,6 +707,10 @@
<item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault.Light</item>
<item name="windowAnimationStyle">@style/Animation.DeviceDefault.Dialog</item>
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
+
<item name="buttonBarStyle">@style/DeviceDefault.Light.ButtonBar.AlertDialog</item>
<item name="borderlessButtonStyle">@style/Widget.DeviceDefault.Light.Button.Borderless.Small</item>
@@ -628,6 +730,10 @@
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} without an action bar -->
@@ -636,6 +742,10 @@
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog_NoActionBar} that has a nice minimum
@@ -645,6 +755,10 @@
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. -->
@@ -680,6 +794,10 @@
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<!-- DeviceDefault light theme for a window without an action bar that will be displayed either
@@ -690,6 +808,10 @@
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<!-- DeviceDefault light theme for a presentation window on a secondary display. -->
@@ -698,6 +820,10 @@
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<!-- DeviceDefault light theme for panel windows. This removes all extraneous window
@@ -708,6 +834,10 @@
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Material.Light.Dialog.Alert">
@@ -717,6 +847,10 @@
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<style name="Theme.DeviceDefault.Light.SearchBar" parent="Theme.Material.Light.SearchBar">
@@ -724,6 +858,10 @@
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<style name="Theme.DeviceDefault.Light.Voice" parent="Theme.Material.Light.Voice">
@@ -731,6 +869,10 @@
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<!-- DeviceDefault theme for a window that should look like the Settings app. -->
@@ -750,6 +892,10 @@
<item name="navigationBarDividerColor">#1f000000</item>
<item name="navigationBarColor">@android:color/white</item>
<item name="windowLightNavigationBar">true</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<!-- @hide DeviceDefault theme for a window that should use Settings theme colors
@@ -761,6 +907,7 @@
<item name="colorSecondary">@color/secondary_device_default_settings_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
<item name="colorControlNormal">?attr/textColorPrimary</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<style name="Theme.DeviceDefault.QuickSettings.Dialog" parent="Theme.DeviceDefault.Light.Dialog">
@@ -769,6 +916,7 @@
<item name="colorPrimaryDark">@color/primary_dark_device_default_settings_light</item>
<item name="colorSecondary">@color/secondary_device_default_settings_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Settings_Dark} with no action bar -->
@@ -778,6 +926,10 @@
<item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
<item name="colorSecondary">@color/secondary_device_default_settings</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
</style>
<style name="Theme.DeviceDefault.Settings.Dialog" parent="Theme.Material.Settings.Dialog">
@@ -786,6 +938,10 @@
<item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
<item name="colorSecondary">@color/secondary_device_default_settings</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<style name="Theme.DeviceDefault.Settings.DialogWhenLarge" parent="Theme.Material.Settings.DialogWhenLarge">
@@ -794,6 +950,10 @@
<item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
<item name="colorSecondary">@color/secondary_device_default_settings</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<style name="Theme.DeviceDefault.Settings.Dialog.Alert" parent="Theme.Material.Settings.Dialog.Alert">
@@ -802,9 +962,13 @@
<item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
<item name="colorSecondary">@color/secondary_device_default_settings</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
- <style name="Theme.DeviceDefault.Settings.Dialog.NoActionBar" parent="Theme.DeviceDefault.Light.Dialog.NoActionBar"/>
+ <style name="Theme.DeviceDefault.Settings.Dialog.NoActionBar" parent="Theme.DeviceDefault.Light.Dialog.NoActionBar" />
<!-- Theme used for the intent picker activity. -->
<style name="Theme.DeviceDefault.Resolver" parent="Theme.Material.Light">
@@ -820,6 +984,10 @@
<item name="listPreferredItemPaddingStart">?attr/dialogPreferredPadding</item>
<item name="listPreferredItemPaddingEnd">?attr/dialogPreferredPadding</item>
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
+
<!-- Color palette -->
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
@@ -831,7 +999,7 @@
<style name="ThemeOverlay.DeviceDefault" />
- <!-- @hide Theme overlay that inherits from material actionbar, and use accent color for
+ <!-- @hide Theme overlay that inherits from material actionbar, and use accent color for
primary text -->
<style name="ThemeOverlay.DeviceDefault.ActionBar.Accent" parent="ThemeOverlay.Material.ActionBar">
<item name="textColorPrimary">@color/btn_colored_borderless_text_material</item>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 9bea3ee..c317121 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -186,6 +186,7 @@
<item name="dialogCustomTitleDecorLayout">@layout/dialog_custom_title_material</item>
<item name="dialogTitleDecorLayout">@layout/dialog_title_material</item>
<item name="dialogPreferredPadding">@dimen/dialog_padding_material</item>
+ <item name="dialogCornerRadius">@dimen/dialog_corner_radius</item>
<!-- AlertDialog attributes -->
<item name="alertDialogTheme">@style/ThemeOverlay.Material.Dialog.Alert</item>
@@ -554,6 +555,7 @@
<item name="dialogCustomTitleDecorLayout">@layout/dialog_custom_title_material</item>
<item name="dialogTitleDecorLayout">@layout/dialog_title_material</item>
<item name="dialogPreferredPadding">@dimen/dialog_padding_material</item>
+ <item name="dialogCornerRadius">@dimen/dialog_corner_radius</item>
<!-- AlertDialog attributes -->
<item name="alertDialogTheme">@style/ThemeOverlay.Material.Dialog.Alert</item>
@@ -1325,12 +1327,15 @@
<style name="Theme.Material.Notification" parent="">
<item name="notificationHeaderStyle">@style/Notification.Header</item>
<item name="notificationHeaderTextAppearance">@style/TextAppearance.Material.Notification.Info</item>
+ <item name="notificationHeaderAppNameVisibility">visible</item>
<item name="notificationHeaderIconSize">@dimen/notification_header_icon_size</item>
</style>
<!-- Theme for inflating ambient notification -->
<style name="Theme.Material.Notification.Ambient">
+ <item name="notificationHeaderStyle">@style/Notification.Header.Ambient</item>
<item name="notificationHeaderTextAppearance">@style/TextAppearance.Material.Notification.Info.Ambient</item>
+ <item name="notificationHeaderAppNameVisibility">gone</item>
<item name="notificationHeaderIconSize">@dimen/notification_header_icon_size_ambient</item>
</style>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 2f9ae57..82aa803 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -232,6 +232,7 @@
<permission name="android.permission.BACKUP"/>
<permission name="android.permission.BATTERY_STATS"/>
<permission name="android.permission.BLUETOOTH_PRIVILEGED"/>
+ <permission name="android.permission.CHANGE_APP_IDLE_STATE"/>
<permission name="android.permission.CHANGE_CONFIGURATION"/>
<permission name="android.permission.DELETE_PACKAGES"/>
<permission name="android.permission.FORCE_STOP_PACKAGES"/>
@@ -266,6 +267,7 @@
<permission name="android.permission.BACKUP"/>
<permission name="android.permission.BATTERY_STATS"/>
<permission name="android.permission.BIND_APPWIDGET"/>
+ <permission name="android.permission.CHANGE_APP_IDLE_STATE"/>
<permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
<permission name="android.permission.CHANGE_CONFIGURATION"/>
<permission name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST" />
diff --git a/data/keyboards/Vendor_045e_Product_02e0.kl b/data/keyboards/Vendor_045e_Product_02e0.kl
new file mode 100644
index 0000000..1012fb1
--- /dev/null
+++ b/data/keyboards/Vendor_045e_Product_02e0.kl
@@ -0,0 +1,59 @@
+# 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.
+
+#
+# Xbox Wireless Controller
+#
+
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 0x132 BUTTON_X
+key 0x130 BUTTON_A
+key 0x131 BUTTON_B
+key 0x133 BUTTON_Y
+
+key 0x134 BUTTON_L1
+key 0x135 BUTTON_R1
+
+# LT axis
+axis 0x02 LTRIGGER
+# RT axis
+axis 0x05 RTRIGGER
+
+
+# Left Analog Stick
+axis 0x00 X
+axis 0x01 Y
+# Right Analog Stick
+axis 0x03 Z
+axis 0x04 RZ
+
+# Left stick click
+key 0x138 BUTTON_THUMBL
+# Right stick click
+key 0x139 BUTTON_THUMBR
+
+# Hat
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 0x136 BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 0x137 BUTTON_START
+
+# Xbox key
+key 0x8b HOME
\ No newline at end of file
diff --git a/libs/androidfw/ZipUtils.cpp b/libs/androidfw/ZipUtils.cpp
index 5abfc8e..5d243da 100644
--- a/libs/androidfw/ZipUtils.cpp
+++ b/libs/androidfw/ZipUtils.cpp
@@ -20,10 +20,11 @@
#define LOG_TAG "ziputil"
+#include "android-base/file.h"
#include <androidfw/ZipUtils.h>
-#include <androidfw/ZipFileRO.h>
#include <utils/Log.h>
#include <utils/Compat.h>
+#include <ziparchive/zip_archive.h>
#include <stdlib.h>
#include <string.h>
@@ -33,211 +34,121 @@
using namespace android;
-static inline unsigned long get4LE(const unsigned char* buf) {
- return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
-}
-
-
-static const unsigned long kReadBufSize = 32768;
-
-/*
- * Utility function that expands zip/gzip "deflate" compressed data
- * into a buffer.
- *
- * (This is a clone of the previous function, but it takes a FILE* instead
- * of an fd. We could pass fileno(fd) to the above, but we can run into
- * trouble when "fp" has a different notion of what fd's file position is.)
- *
- * "fp" is an open file positioned at the start of the "deflate" data
- * "buf" must hold at least "uncompressedLen" bytes.
- */
-/*static*/ template<typename T> bool inflateToBuffer(T& reader, void* buf,
- long uncompressedLen, long compressedLen)
-{
- bool result = false;
-
- z_stream zstream;
- int zerr;
- unsigned long compRemaining;
-
- assert(uncompressedLen >= 0);
- assert(compressedLen >= 0);
-
- compRemaining = compressedLen;
-
- /*
- * Initialize the zlib stream.
- */
- memset(&zstream, 0, sizeof(zstream));
- zstream.zalloc = Z_NULL;
- zstream.zfree = Z_NULL;
- zstream.opaque = Z_NULL;
- zstream.next_in = NULL;
- zstream.avail_in = 0;
- zstream.next_out = (Bytef*) buf;
- zstream.avail_out = uncompressedLen;
- zstream.data_type = Z_UNKNOWN;
-
- /*
- * Use the undocumented "negative window bits" feature to tell zlib
- * that there's no zlib header waiting for it.
- */
- zerr = inflateInit2(&zstream, -MAX_WBITS);
- if (zerr != Z_OK) {
- if (zerr == Z_VERSION_ERROR) {
- ALOGE("Installed zlib is not compatible with linked version (%s)\n",
- ZLIB_VERSION);
- } else {
- ALOGE("Call to inflateInit2 failed (zerr=%d)\n", zerr);
- }
- goto bail;
+// TODO: This can go away once the only remaining usage in aapt goes away.
+class FileReader : public zip_archive::Reader {
+ public:
+ FileReader(FILE* fp) : Reader(), mFp(fp), mCurrentOffset(0) {
}
- /*
- * Loop while we have data.
- */
- do {
- unsigned long getSize;
-
- /* read as much as we can */
- if (zstream.avail_in == 0) {
- getSize = (compRemaining > kReadBufSize) ?
- kReadBufSize : compRemaining;
- ALOGV("+++ reading %ld bytes (%ld left)\n",
- getSize, compRemaining);
-
- unsigned char* nextBuffer = NULL;
- const unsigned long nextSize = reader.read(&nextBuffer, getSize);
-
- if (nextSize < getSize || nextBuffer == NULL) {
- ALOGD("inflate read failed (%ld vs %ld)\n", nextSize, getSize);
- goto z_bail;
+ bool ReadAtOffset(uint8_t* buf, size_t len, uint32_t offset) const {
+ // Data is usually requested sequentially, so this helps avoid pointless
+ // fseeks every time we perform a read. There's an impedence mismatch
+ // here because the original API was designed around pread and pwrite.
+ if (offset != mCurrentOffset) {
+ if (fseek(mFp, offset, SEEK_SET) != 0) {
+ return false;
}
- compRemaining -= nextSize;
-
- zstream.next_in = nextBuffer;
- zstream.avail_in = nextSize;
+ mCurrentOffset = offset;
}
- /* uncompress the data */
- zerr = inflate(&zstream, Z_NO_FLUSH);
- if (zerr != Z_OK && zerr != Z_STREAM_END) {
- ALOGD("zlib inflate call failed (zerr=%d)\n", zerr);
- goto z_bail;
+ size_t read = fread(buf, 1, len, mFp);
+ if (read != len) {
+ return false;
}
- /* output buffer holds all, so no need to write the output */
- } while (zerr == Z_OK);
-
- assert(zerr == Z_STREAM_END); /* other errors should've been caught */
-
- if ((long) zstream.total_out != uncompressedLen) {
- ALOGW("Size mismatch on inflated file (%ld vs %ld)\n",
- zstream.total_out, uncompressedLen);
- goto z_bail;
+ mCurrentOffset += read;
+ return true;
}
- // success!
- result = true;
-
-z_bail:
- inflateEnd(&zstream); /* free up any allocated structures */
-
-bail:
- return result;
-}
-
-class FileReader {
-public:
- explicit FileReader(FILE* fp) :
- mFp(fp), mReadBuf(new unsigned char[kReadBufSize])
- {
- }
-
- ~FileReader() {
- delete[] mReadBuf;
- }
-
- long read(unsigned char** nextBuffer, long readSize) const {
- *nextBuffer = mReadBuf;
- return fread(mReadBuf, 1, readSize, mFp);
- }
-
- FILE* mFp;
- unsigned char* mReadBuf;
+ private:
+ FILE* mFp;
+ mutable uint32_t mCurrentOffset;
};
-class FdReader {
-public:
- explicit FdReader(int fd) :
- mFd(fd), mReadBuf(new unsigned char[kReadBufSize])
- {
- }
+class FdReader : public zip_archive::Reader {
+ public:
+ explicit FdReader(int fd) : mFd(fd) {
+ }
- ~FdReader() {
- delete[] mReadBuf;
- }
+ bool ReadAtOffset(uint8_t* buf, size_t len, uint32_t offset) const {
+ return android::base::ReadFullyAtOffset(mFd, buf, len, static_cast<off_t>(offset));
+ }
- long read(unsigned char** nextBuffer, long readSize) const {
- *nextBuffer = mReadBuf;
- return TEMP_FAILURE_RETRY(::read(mFd, mReadBuf, readSize));
- }
-
- int mFd;
- unsigned char* mReadBuf;
+ private:
+ const int mFd;
};
-class BufferReader {
-public:
- BufferReader(void* input, size_t inputSize) :
- mInput(reinterpret_cast<unsigned char*>(input)),
- mInputSize(inputSize),
- mBufferReturned(false)
- {
+class BufferReader : public zip_archive::Reader {
+ public:
+ BufferReader(const void* input, size_t inputSize) : Reader(),
+ mInput(reinterpret_cast<const uint8_t*>(input)),
+ mInputSize(inputSize) {
}
- long read(unsigned char** nextBuffer, long /*readSize*/) {
- if (!mBufferReturned) {
- mBufferReturned = true;
- *nextBuffer = mInput;
- return mInputSize;
+ bool ReadAtOffset(uint8_t* buf, size_t len, uint32_t offset) const {
+ if (offset + len > mInputSize) {
+ return false;
}
- *nextBuffer = NULL;
- return 0;
+ memcpy(buf, mInput + offset, len);
+ return true;
}
- unsigned char* mInput;
+ private:
+ const uint8_t* mInput;
const size_t mInputSize;
- bool mBufferReturned;
+};
+
+class BufferWriter : public zip_archive::Writer {
+ public:
+ BufferWriter(void* output, size_t outputSize) : Writer(),
+ mOutput(reinterpret_cast<uint8_t*>(output)), mOutputSize(outputSize), mBytesWritten(0) {
+ }
+
+ bool Append(uint8_t* buf, size_t bufSize) override {
+ if (mBytesWritten + bufSize > mOutputSize) {
+ return false;
+ }
+
+ memcpy(mOutput + mBytesWritten, buf, bufSize);
+ mBytesWritten += bufSize;
+ return true;
+ }
+
+ private:
+ uint8_t* const mOutput;
+ const size_t mOutputSize;
+ size_t mBytesWritten;
};
/*static*/ bool ZipUtils::inflateToBuffer(FILE* fp, void* buf,
long uncompressedLen, long compressedLen)
{
FileReader reader(fp);
- return ::inflateToBuffer<FileReader>(reader, buf,
- uncompressedLen, compressedLen);
+ BufferWriter writer(buf, uncompressedLen);
+ return (zip_archive::Inflate(reader, compressedLen, uncompressedLen, &writer, nullptr) == 0);
}
/*static*/ bool ZipUtils::inflateToBuffer(int fd, void* buf,
long uncompressedLen, long compressedLen)
{
FdReader reader(fd);
- return ::inflateToBuffer<FdReader>(reader, buf,
- uncompressedLen, compressedLen);
+ BufferWriter writer(buf, uncompressedLen);
+ return (zip_archive::Inflate(reader, compressedLen, uncompressedLen, &writer, nullptr) == 0);
}
-/*static*/ bool ZipUtils::inflateToBuffer(void* in, void* buf,
+/*static*/ bool ZipUtils::inflateToBuffer(const void* in, void* buf,
long uncompressedLen, long compressedLen)
{
BufferReader reader(in, compressedLen);
- return ::inflateToBuffer<BufferReader>(reader, buf,
- uncompressedLen, compressedLen);
+ BufferWriter writer(buf, uncompressedLen);
+ return (zip_archive::Inflate(reader, compressedLen, uncompressedLen, &writer, nullptr) == 0);
}
-
+static inline unsigned long get4LE(const unsigned char* buf) {
+ return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
+}
/*
* Look at the contents of a gzip archive. We want to know where the
@@ -275,7 +186,7 @@
/* quick sanity checks */
if (method == EOF || flags == EOF)
return false;
- if (method != ZipFileRO::kCompressDeflated)
+ if (method != kCompressDeflated)
return false;
/* skip over 4 bytes of mod time, 1 byte XFL, 1 byte OS */
diff --git a/libs/androidfw/include/androidfw/ZipUtils.h b/libs/androidfw/include/androidfw/ZipUtils.h
index 55575d7..4d35e99 100644
--- a/libs/androidfw/include/androidfw/ZipUtils.h
+++ b/libs/androidfw/include/androidfw/ZipUtils.h
@@ -40,7 +40,7 @@
long compressedLen);
static bool inflateToBuffer(int fd, void* buf, long uncompressedLen,
long compressedLen);
- static bool inflateToBuffer(void *in, void* buf, long uncompressedLen,
+ static bool inflateToBuffer(const void *in, void* buf, long uncompressedLen,
long compressedLen);
/*
diff --git a/libs/hwui/hwui/MinikinSkia.cpp b/libs/hwui/hwui/MinikinSkia.cpp
index a5b4c42..8e7b6b6 100644
--- a/libs/hwui/hwui/MinikinSkia.cpp
+++ b/libs/hwui/hwui/MinikinSkia.cpp
@@ -31,22 +31,23 @@
}
static void MinikinFontSkia_SetSkiaPaint(const minikin::MinikinFont* font, SkPaint* skPaint,
- const minikin::MinikinPaint& paint) {
+ const minikin::MinikinPaint& paint, const minikin::FontFakery& fakery) {
skPaint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
skPaint->setTextSize(paint.size);
skPaint->setTextScaleX(paint.scaleX);
skPaint->setTextSkewX(paint.skewX);
MinikinFontSkia::unpackPaintFlags(skPaint, paint.paintFlags);
// Apply font fakery on top of user-supplied flags.
- MinikinFontSkia::populateSkPaint(skPaint, font, paint.fakery);
+ MinikinFontSkia::populateSkPaint(skPaint, font, fakery);
}
float MinikinFontSkia::GetHorizontalAdvance(uint32_t glyph_id,
- const minikin::MinikinPaint &paint) const {
+ const minikin::MinikinPaint &paint,
+ const minikin::FontFakery& fakery) const {
SkPaint skPaint;
uint16_t glyph16 = glyph_id;
SkScalar skWidth;
- MinikinFontSkia_SetSkiaPaint(this, &skPaint, paint);
+ MinikinFontSkia_SetSkiaPaint(this, &skPaint, paint, fakery);
skPaint.getTextWidths(&glyph16, sizeof(glyph16), &skWidth, NULL);
#ifdef VERBOSE
ALOGD("width for typeface %d glyph %d = %f", mTypeface->uniqueID(), glyph_id, skWidth);
@@ -55,11 +56,12 @@
}
void MinikinFontSkia::GetBounds(minikin::MinikinRect* bounds, uint32_t glyph_id,
- const minikin::MinikinPaint& paint) const {
+ const minikin::MinikinPaint& paint,
+ const minikin::FontFakery& fakery) const {
SkPaint skPaint;
uint16_t glyph16 = glyph_id;
SkRect skBounds;
- MinikinFontSkia_SetSkiaPaint(this, &skPaint, paint);
+ MinikinFontSkia_SetSkiaPaint(this, &skPaint, paint, fakery);
skPaint.getTextWidths(&glyph16, sizeof(glyph16), NULL, &skBounds);
bounds->mLeft = skBounds.fLeft;
bounds->mTop = skBounds.fTop;
@@ -68,9 +70,10 @@
}
void MinikinFontSkia::GetFontExtent(minikin::MinikinExtent* extent,
- const minikin::MinikinPaint& paint) const {
+ const minikin::MinikinPaint& paint,
+ const minikin::FontFakery& fakery) const {
SkPaint skPaint;
- MinikinFontSkia_SetSkiaPaint(this, &skPaint, paint);
+ MinikinFontSkia_SetSkiaPaint(this, &skPaint, paint, fakery);
SkPaint::FontMetrics metrics;
skPaint.getFontMetrics(&metrics);
extent->ascent = metrics.fAscent;
diff --git a/libs/hwui/hwui/MinikinSkia.h b/libs/hwui/hwui/MinikinSkia.h
index a19f4a7..30fd500 100644
--- a/libs/hwui/hwui/MinikinSkia.h
+++ b/libs/hwui/hwui/MinikinSkia.h
@@ -32,13 +32,16 @@
int ttcIndex, const std::vector<minikin::FontVariation>& axes);
float GetHorizontalAdvance(uint32_t glyph_id,
- const minikin::MinikinPaint &paint) const;
+ const minikin::MinikinPaint& paint,
+ const minikin::FontFakery& fakery) const override;
void GetBounds(minikin::MinikinRect* bounds, uint32_t glyph_id,
- const minikin::MinikinPaint &paint) const;
+ const minikin::MinikinPaint& paint,
+ const minikin::FontFakery& fakery) const override;
void GetFontExtent(minikin::MinikinExtent* extent,
- const minikin::MinikinPaint &paint) const;
+ const minikin::MinikinPaint& paint,
+ const minikin::FontFakery& fakery) const override;
SkTypeface* GetSkTypeface() const;
sk_sp<SkTypeface> RefSkTypeface() const;
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 88b1c5f..1feea89 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -994,7 +994,6 @@
* {@link #PROPERTY_VENDOR}, {@link #PROPERTY_VERSION},
* {@link #PROPERTY_DESCRIPTION}, {@link #PROPERTY_ALGORITHMS}
*/
- /* FIXME this throws IllegalStateException for invalid property names */
@NonNull
public native String getPropertyString(@NonNull @StringProperty String propertyName);
@@ -1002,7 +1001,6 @@
* Byte array property name: the device unique identifier is established during
* device provisioning and provides a means of uniquely identifying each device.
*/
- /* FIXME this throws IllegalStateException for invalid property names */
public static final String PROPERTY_DEVICE_UNIQUE_ID = "deviceUniqueId";
/** @hide */
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index d0c2aea..51c9e5f 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -282,7 +282,7 @@
drmMessage = "Decrypt error";
break;
case ERROR_DRM_CANNOT_HANDLE:
- drmMessage = "Unsupported scheme or data format";
+ drmMessage = "Invalid parameter or data format";
break;
case ERROR_DRM_TAMPER_DETECTED:
drmMessage = "Invalid state";
@@ -297,7 +297,7 @@
drmMessage = vendorMessage.string();
}
- if (err == BAD_VALUE) {
+ if (err == BAD_VALUE || err == ERROR_DRM_CANNOT_HANDLE) {
jniThrowException(env, "java/lang/IllegalArgumentException", msg);
return true;
} else if (err == ERROR_DRM_NOT_PROVISIONED) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
index 32e6389..c3a36e9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
@@ -28,6 +28,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.graphics.drawable.Drawable;
import android.os.RemoteException;
@@ -343,7 +344,8 @@
}
DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
Context.DEVICE_POLICY_SERVICE);
- if (dpm == null) {
+ PackageManager pm = context.getPackageManager();
+ if (!pm.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN) || dpm == null) {
return null;
}
boolean isAccountTypeDisabled = false;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
index ca366ea..64de635 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
@@ -33,6 +33,7 @@
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.os.UserManager;
@@ -56,6 +57,8 @@
private DevicePolicyManager mDevicePolicyManager;
@Mock
private UserManager mUserManager;
+ @Mock
+ private PackageManager mPackageManager;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private RestrictedLockUtils.Proxy mProxy;
@@ -72,11 +75,32 @@
.thenReturn(mDevicePolicyManager);
when(mContext.getSystemService(Context.USER_SERVICE))
.thenReturn(mUserManager);
+ when(mContext.getPackageManager())
+ .thenReturn(mPackageManager);
RestrictedLockUtils.sProxy = mProxy;
}
@Test
+ public void checkIfDevicePolicyServiceDisabled_noEnforceAdminForManagedProfile() {
+ when(mContext.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn(null);
+ final EnforcedAdmin enforcedAdmin = RestrictedLockUtils.checkIfAccountManagementDisabled(
+ mContext, "account_type", mUserId);
+
+ assertThat(enforcedAdmin).isEqualTo(null);
+ }
+
+ @Test
+ public void checkIfDeviceAdminFeatureDisabled_noEnforceAdminForManagedProfile() {
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN))
+ .thenReturn(false);
+ final EnforcedAdmin enforcedAdmin = RestrictedLockUtils.checkIfAccountManagementDisabled(
+ mContext, "account_type", mUserId);
+
+ assertThat(enforcedAdmin).isEqualTo(null);
+ }
+
+ @Test
public void checkIfKeyguardFeaturesDisabled_noEnforcedAdminForManagedProfile() {
setUpManagedProfile(mUserId, new ComponentName[] {mAdmin1, mAdmin2});
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoadPlan.java
index 806a073..f92509d 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoadPlan.java
@@ -70,21 +70,6 @@
}
/**
- * An optimization to preload the raw list of tasks. The raw tasks are saved in least-recent
- * to most-recent order.
- *
- * Note: Do not lock, callers should synchronize on the loader before making this call.
- */
- void preloadRawTasks() {
- int currentUserId = ActivityManagerWrapper.getInstance().getCurrentUserId();
- mRawTasks = ActivityManagerWrapper.getInstance().getRecentTasks(
- ActivityManager.getMaxRecentTasksStatic(), currentUserId);
-
- // Since the raw tasks are given in most-recent to least-recent order, we need to reverse it
- Collections.reverse(mRawTasks);
- }
-
- /**
* Preloads the list of recent tasks from the system. After this call, the TaskStack will
* have a list of all the recent tasks with their metadata, not including icons or
* thumbnails which were not cached and have to be loaded.
@@ -95,11 +80,15 @@
* Note: Do not lock, since this can be calling back to the loader, which separately also drives
* this call (callers should synchronize on the loader before making this call).
*/
- void preloadPlan(RecentsTaskLoader loader, int runningTaskId) {
+ public void preloadPlan(RecentsTaskLoader loader, int runningTaskId, int currentUserId) {
Resources res = mContext.getResources();
ArrayList<Task> allTasks = new ArrayList<>();
if (mRawTasks == null) {
- preloadRawTasks();
+ mRawTasks = ActivityManagerWrapper.getInstance().getRecentTasks(
+ ActivityManager.getMaxRecentTasksStatic(), currentUserId);
+
+ // Since the raw tasks are given in most-recent to least-recent order, we need to reverse it
+ Collections.reverse(mRawTasks);
}
int taskCount = mRawTasks.size();
@@ -160,7 +149,7 @@
* Note: Do not lock, since this can be calling back to the loader, which separately also drives
* this call (callers should synchronize on the loader before making this call).
*/
- void executePlan(Options opts, RecentsTaskLoader loader) {
+ public void executePlan(Options opts, RecentsTaskLoader loader) {
Resources res = mContext.getResources();
// Iterate through each of the tasks and load them according to the load conditions.
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java
index de4c72c..9a991cf 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java
@@ -147,9 +147,15 @@
/** Preloads recents tasks using the specified plan to store the output. */
public synchronized void preloadTasks(RecentsTaskLoadPlan plan, int runningTaskId) {
+ preloadTasks(plan, runningTaskId, ActivityManagerWrapper.getInstance().getCurrentUserId());
+ }
+
+ /** Preloads recents tasks using the specified plan to store the output. */
+ public synchronized void preloadTasks(RecentsTaskLoadPlan plan, int runningTaskId,
+ int currentUserId) {
try {
Trace.beginSection("preloadPlan");
- plan.preloadPlan(this, runningTaskId);
+ plan.preloadPlan(this, runningTaskId, currentUserId);
} finally {
Trace.endSection();
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskFilter.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskFilter.java
index 9a1ff54..5f3dcd1 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskFilter.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskFilter.java
@@ -21,7 +21,7 @@
/**
* An interface for a task filter to query whether a particular task should show in a stack.
*/
-interface TaskFilter {
+public interface TaskFilter {
/** Returns whether the filter accepts the specified task */
boolean acceptTask(SparseArray<Task> taskIdMap, Task t, int index);
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index 090617d..db1583a 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -17,10 +17,17 @@
package com.android.systemui.shared.system;
import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.ActivityManager.RecentTaskInfo;
+import android.app.ActivityOptions;
import android.app.AppGlobals;
import android.content.Context;
import android.content.pm.ActivityInfo;
@@ -32,15 +39,19 @@
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
+import android.os.Handler;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.IconDrawableFactory;
import android.util.Log;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.model.Task.TaskKey;
import com.android.systemui.shared.recents.model.ThumbnailData;
import java.util.ArrayList;
import java.util.List;
+import java.util.function.Consumer;
public class ActivityManagerWrapper {
@@ -77,6 +88,25 @@
}
/**
+ * @return the top running task (can be {@code null}).
+ */
+ public ActivityManager.RunningTaskInfo getRunningTask() {
+ // Note: The set of running tasks from the system is ordered by recency
+ try {
+ List<ActivityManager.RunningTaskInfo> tasks =
+ ActivityManager.getService().getFilteredTasks(1,
+ ACTIVITY_TYPE_RECENTS /* ignoreActivityType */,
+ WINDOWING_MODE_PINNED /* ignoreWindowingMode */);
+ if (tasks.isEmpty()) {
+ return null;
+ }
+ return tasks.get(0);
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
* @return a list of the recents tasks.
*/
public List<RecentTaskInfo> getRecentTasks(int numTasks, int userId) {
@@ -202,6 +232,60 @@
}
/**
+ * Starts a task from Recents.
+ *
+ * @see {@link #startActivityFromRecents(TaskKey, ActivityOptions, int, int, Consumer, Handler)}
+ */
+ public void startActivityFromRecents(Task.TaskKey taskKey, ActivityOptions options,
+ Consumer<Boolean> resultCallback, Handler resultCallbackHandler) {
+ startActivityFromRecents(taskKey, options, WINDOWING_MODE_UNDEFINED,
+ ACTIVITY_TYPE_UNDEFINED, resultCallback, resultCallbackHandler);
+ }
+
+ /**
+ * Starts a task from Recents.
+ *
+ * @param resultCallback The result success callback
+ * @param resultCallbackHandler The handler to receive the result callback
+ */
+ public void startActivityFromRecents(Task.TaskKey taskKey, ActivityOptions options,
+ int windowingMode, int activityType, Consumer<Boolean> resultCallback,
+ Handler resultCallbackHandler) {
+ if (taskKey.windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
+ // We show non-visible docked tasks in Recents, but we always want to launch
+ // them in the fullscreen stack.
+ if (options == null) {
+ options = ActivityOptions.makeBasic();
+ }
+ options.setLaunchWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+ } else if (windowingMode != WINDOWING_MODE_UNDEFINED
+ || activityType != ACTIVITY_TYPE_UNDEFINED) {
+ if (options == null) {
+ options = ActivityOptions.makeBasic();
+ }
+ options.setLaunchWindowingMode(windowingMode);
+ options.setLaunchActivityType(activityType);
+ }
+ final ActivityOptions finalOptions = options;
+
+ // Execute this from another thread such that we can do other things (like caching the
+ // bitmap for the thumbnail) while AM is busy starting our activity.
+ mBackgroundExecutor.submit(() -> {
+ try {
+ ActivityManager.getService().startActivityFromRecents(taskKey.id,
+ finalOptions == null ? null : finalOptions.toBundle());
+ if (resultCallback != null) {
+ resultCallbackHandler.post(() -> resultCallback.accept(true));
+ }
+ } catch (Exception e) {
+ if (resultCallback != null) {
+ resultCallbackHandler.post(() -> resultCallback.accept(false));
+ }
+ }
+ });
+ }
+
+ /**
* Requests that the system close any open system windows (including other SystemUI).
*/
public void closeSystemWindows(String reason) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 61c5167..5b62c7d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -411,12 +411,12 @@
}
int currentUser = sSystemServicesProxy.getCurrentUser();
- SystemServicesProxy ssp = Recents.getSystemServices();
- ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask();
+ ActivityManager.RunningTaskInfo runningTask =
+ ActivityManagerWrapper.getInstance().getRunningTask();
final int activityType = runningTask != null
? runningTask.configuration.windowConfiguration.getActivityType()
: ACTIVITY_TYPE_UNDEFINED;
- boolean screenPinningActive = ssp.isScreenPinningActive();
+ boolean screenPinningActive = sSystemServicesProxy.isScreenPinningActive();
boolean isRunningTaskInHomeOrRecentsStack =
activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS;
if (runningTask != null && !isRunningTaskInHomeOrRecentsStack && !screenPinningActive) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 96fae35..0b816b5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -138,8 +138,8 @@
}
// Load the next task only if we aren't svelte
- SystemServicesProxy ssp = Recents.getSystemServices();
- ActivityManager.RunningTaskInfo runningTaskInfo = ssp.getRunningTask();
+ ActivityManager.RunningTaskInfo runningTaskInfo =
+ ActivityManagerWrapper.getInstance().getRunningTask();
RecentsTaskLoader loader = Recents.getTaskLoader();
RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(mContext);
loader.preloadTasks(plan, -1);
@@ -353,7 +353,8 @@
boolean forceVisible = launchedWhileDockingTask || draggingInRecents;
MutableBoolean isHomeStackVisible = new MutableBoolean(forceVisible);
if (forceVisible || !ssp.isRecentsActivityVisible(isHomeStackVisible)) {
- ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask();
+ ActivityManager.RunningTaskInfo runningTask =
+ ActivityManagerWrapper.getInstance().getRunningTask();
startRecentsActivity(runningTask, isHomeStackVisible.value || fromHome, animate,
growTarget);
}
@@ -444,7 +445,8 @@
}
// Otherwise, start the recents activity
- ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask();
+ ActivityManager.RunningTaskInfo runningTask =
+ ActivityManagerWrapper.getInstance().getRunningTask();
startRecentsActivity(runningTask, isHomeStackVisible.value, true /* animate */,
growTarget);
@@ -470,7 +472,8 @@
// don't block the touch feedback on the nav bar button which triggers this.
mHandler.post(() -> {
if (!ssp.isRecentsActivityVisible(null)) {
- ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask();
+ ActivityManager.RunningTaskInfo runningTask =
+ ActivityManagerWrapper.getInstance().getRunningTask();
if (runningTask == null) {
return;
}
@@ -524,7 +527,8 @@
if (focusedStack == null || focusedStack.getTaskCount() == 0) return;
// Return early if there is no running task
- ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask();
+ ActivityManager.RunningTaskInfo runningTask =
+ ActivityManagerWrapper.getInstance().getRunningTask();
if (runningTask == null) return;
// Find the task in the recents list
@@ -561,8 +565,8 @@
}
// Launch the task
- ssp.startActivityFromRecents(
- mContext, toTask.key, toTask.title, launchOpts, null /* resultListener */);
+ ActivityManagerWrapper.getInstance().startActivityFromRecents(toTask.key, launchOpts,
+ null /* resultCallback */, null /* resultCallbackHandler */);
}
/**
@@ -579,7 +583,8 @@
if (focusedStack == null || focusedStack.getTaskCount() == 0) return;
// Return early if there is no running task (can't determine affiliated tasks in this case)
- ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask();
+ ActivityManager.RunningTaskInfo runningTask =
+ ActivityManagerWrapper.getInstance().getRunningTask();
final int activityType = runningTask.configuration.windowConfiguration.getActivityType();
if (runningTask == null) return;
// Return early if the running task is in the home/recents stack (optimization)
@@ -630,8 +635,8 @@
MetricsLogger.count(mContext, "overview_affiliated_task_launch", 1);
// Launch the task
- ssp.startActivityFromRecents(
- mContext, toTask.key, toTask.title, launchOpts, null /* resultListener */);
+ ActivityManagerWrapper.getInstance().startActivityFromRecents(toTask.key, launchOpts,
+ null /* resultListener */, null /* resultCallbackHandler */);
}
public void showNextAffiliatedTask() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 14b91f7..a436e17 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -83,6 +83,7 @@
import com.android.systemui.statusbar.policy.UserInfoController;
import java.util.List;
+import java.util.function.Consumer;
/**
* Acts as a shim around the real system services that we need to access data from, and provides
@@ -123,7 +124,6 @@
Paint mBgProtectionPaint;
Canvas mBgProtectionCanvas;
- private final Handler mHandler = new Handler();
private final Runnable mGcRunnable = new Runnable() {
@Override
public void run() {
@@ -197,24 +197,6 @@
}
/**
- * Returns the top running task.
- */
- public ActivityManager.RunningTaskInfo getRunningTask() {
- // Note: The set of running tasks from the system is ordered by recency
- try {
- List<ActivityManager.RunningTaskInfo> tasks = mIam.getFilteredTasks(1,
- ACTIVITY_TYPE_RECENTS /* ignoreActivityType */,
- WINDOWING_MODE_PINNED /* ignoreWindowingMode */);
- if (tasks.isEmpty()) {
- return null;
- }
- return tasks.get(0);
- } catch (RemoteException e) {
- return null;
- }
- }
-
- /**
* Returns whether the recents activity is currently visible.
*/
public boolean isRecentsActivityVisible() {
@@ -376,28 +358,6 @@
}
}
- /** Removes the task */
- public void removeTask(final int taskId) {
- if (mAm == null) return;
-
- // Remove the task.
- mUiOffloadThread.submit(() -> {
- try {
- mIam.removeTask(taskId);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- });
- }
-
- public ActivityManager.TaskDescription getTaskDescription(int taskId) {
- try {
- return mIam.getTaskDescription(taskId);
- } catch (RemoteException e) {
- return null;
- }
- }
-
/**
* Returns whether the provided {@param userId} represents the system user.
*/
@@ -520,56 +480,6 @@
opts != null ? opts.toBundle() : null, UserHandle.CURRENT));
}
- public void startActivityFromRecents(Context context, Task.TaskKey taskKey, String taskName,
- ActivityOptions options,
- @Nullable final StartActivityFromRecentsResultListener resultListener) {
- startActivityFromRecents(context, taskKey, taskName, options,
- WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_UNDEFINED, resultListener);
- }
-
- /** Starts an activity from recents. */
- public void startActivityFromRecents(Context context, Task.TaskKey taskKey, String taskName,
- ActivityOptions options, int windowingMode, int activityType,
- @Nullable final StartActivityFromRecentsResultListener resultListener) {
- if (mIam == null) {
- return;
- }
- if (taskKey.windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
- // We show non-visible docked tasks in Recents, but we always want to launch
- // them in the fullscreen stack.
- if (options == null) {
- options = ActivityOptions.makeBasic();
- }
- options.setLaunchWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
- } else if (windowingMode != WINDOWING_MODE_UNDEFINED
- || activityType != ACTIVITY_TYPE_UNDEFINED) {
- if (options == null) {
- options = ActivityOptions.makeBasic();
- }
- options.setLaunchWindowingMode(windowingMode);
- options.setLaunchActivityType(activityType);
- }
- final ActivityOptions finalOptions = options;
-
- // Execute this from another thread such that we can do other things (like caching the
- // bitmap for the thumbnail) while AM is busy starting our activity.
- mUiOffloadThread.submit(() -> {
- try {
- mIam.startActivityFromRecents(
- taskKey.id, finalOptions == null ? null : finalOptions.toBundle());
- if (resultListener != null) {
- mHandler.post(() -> resultListener.onStartActivityResult(true));
- }
- } catch (Exception e) {
- Log.e(TAG, context.getString(
- R.string.recents_launch_error_message, taskName), e);
- if (resultListener != null) {
- mHandler.post(() -> resultListener.onStartActivityResult(false));
- }
- }
- });
- }
-
/** Starts an in-place animation on the front most application windows. */
public void startInPlaceAnimationOnFrontMostApplication(ActivityOptions opts) {
if (mIam == null) return;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index f4973d0..b82f15e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -36,6 +36,7 @@
import android.os.Handler;
import android.util.ArraySet;
import android.util.AttributeSet;
+import android.util.Log;
import android.util.MathUtils;
import android.view.AppTransitionAnimationSpec;
import android.view.LayoutInflater;
@@ -1026,29 +1027,30 @@
private void startTaskActivity(TaskStack stack, Task task, @Nullable TaskView taskView,
ActivityOptions opts, AppTransitionAnimationSpecsFuture transitionFuture,
int windowingMode, int activityType) {
- SystemServicesProxy ssp = Recents.getSystemServices();
- ssp.startActivityFromRecents(mContext, task.key, task.title, opts, windowingMode,
- activityType,
- succeeded -> {
- if (succeeded) {
- // Keep track of the index of the task launch
- int taskIndexFromFront = 0;
- int taskIndex = stack.indexOfStackTask(task);
- if (taskIndex > -1) {
- taskIndexFromFront = stack.getTaskCount() - taskIndex - 1;
- }
- EventBus.getDefault().send(new LaunchTaskSucceededEvent(
- taskIndexFromFront));
- } else {
- // Dismiss the task if we fail to launch it
- if (taskView != null) {
- taskView.dismissTask();
- }
+ ActivityManagerWrapper.getInstance().startActivityFromRecents(task.key, opts, windowingMode,
+ activityType, succeeded -> {
+ if (succeeded) {
+ // Keep track of the index of the task launch
+ int taskIndexFromFront = 0;
+ int taskIndex = stack.indexOfStackTask(task);
+ if (taskIndex > -1) {
+ taskIndexFromFront = stack.getTaskCount() - taskIndex - 1;
+ }
+ EventBus.getDefault().send(new LaunchTaskSucceededEvent(
+ taskIndexFromFront));
+ } else {
+ Log.e(TAG, mContext.getString(R.string.recents_launch_error_message,
+ task.title));
- // Keep track of failed launches
- EventBus.getDefault().send(new LaunchTaskFailedEvent());
- }
- });
+ // Dismiss the task if we fail to launch it
+ if (taskView != null) {
+ taskView.dismissTask();
+ }
+
+ // Keep track of failed launches
+ EventBus.getDefault().send(new LaunchTaskFailedEvent());
+ }
+ }, getHandler());
if (transitionFuture != null) {
mHandler.post(transitionFuture::composeSpecsSynchronous);
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 7bcef57..1596d12 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -439,7 +439,7 @@
if (mMinimizedSnapAlgorithm == null) {
mMinimizedSnapAlgorithm = new DividerSnapAlgorithm(getContext().getResources(),
mDisplayWidth, mDisplayHeight, mDividerSize, isHorizontalDivision(),
- mStableInsets, mDockedStackMinimized && mHomeStackResizable);
+ mStableInsets, mDockSide, mDockedStackMinimized && mHomeStackResizable);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 7022c47..41cae6b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -47,6 +47,7 @@
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.StatusBarState;
@@ -311,8 +312,8 @@
private class TaskStackListenerImpl extends SysUiTaskStackChangeListener {
@Override
public void onTaskStackChanged() {
- SystemServicesProxy ssp = Recents.getSystemServices();
- ActivityManager.RunningTaskInfo runningTaskInfo = ssp.getRunningTask();
+ ActivityManager.RunningTaskInfo runningTaskInfo =
+ ActivityManagerWrapper.getInstance().getRunningTask();
if (runningTaskInfo != null && runningTaskInfo.baseActivity != null) {
mController.taskChanged(runningTaskInfo.baseActivity.getPackageName(),
runningTaskInfo);
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 d8a9c12..fa34d4a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -5266,7 +5266,8 @@
boolean isCameraAllowedByAdmin() {
if (mDevicePolicyManager.getCameraDisabled(null, mCurrentUserId)) {
return false;
- } else if (isKeyguardShowing() && isKeyguardSecure()) {
+ } else if (mStatusBarKeyguardViewManager == null ||
+ (isKeyguardShowing() && isKeyguardSecure())) {
// Check if the admin has disabled the camera specifically for the keyguard
return (mDevicePolicyManager.getKeyguardDisabledFeatures(null, mCurrentUserId)
& DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) == 0;
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 507852e..faad49e 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -2799,420 +2799,316 @@
// OS: O
TEXT_LONGPRESS = 629;
- // ACTION: An app requested an unknown permission
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_UNKNOWN = 630;
- // ACTION: An app was granted an unknown permission
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_UNKNOWN = 631;
- // ACTION: An app requested an unknown permission and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_UNKNOWN = 632;
- // ACTION: An unknown permission was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_UNKNOWN = 633;
- // ACTION: An app requested the permission READ_CALENDAR
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_READ_CALENDAR = 634;
- // ACTION: An app was granted the permission READ_CALENDAR
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_READ_CALENDAR = 635;
- // ACTION: An app requested the permission READ_CALENDAR and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_READ_CALENDAR = 636;
- // ACTION: The permission READ_CALENDAR was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_READ_CALENDAR = 637;
- // ACTION: An app requested the permission WRITE_CALENDAR
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_WRITE_CALENDAR = 638;
- // ACTION: An app was granted the permission WRITE_CALENDAR
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_WRITE_CALENDAR = 639;
- // ACTION: An app requested the permission WRITE_CALENDAR and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_WRITE_CALENDAR = 640;
- // ACTION: The permission WRITE_CALENDAR was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_WRITE_CALENDAR = 641;
- // ACTION: An app requested the permission CAMERA
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_CAMERA = 642;
- // ACTION: An app was granted the permission CAMERA
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_CAMERA = 643;
- // ACTION: An app requested the permission CAMERA and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_CAMERA = 644;
- // ACTION: The permission CAMERA was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_CAMERA = 645;
- // ACTION: An app requested the permission READ_CONTACTS
- // PACKAGE: The package name of the app requesting the permission
+ // AOBSOLETE
ACTION_PERMISSION_REQUEST_READ_CONTACTS = 646;
- // ACTION: An app was granted the permission READ_CONTACTS
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_READ_CONTACTS = 647;
- // ACTION: An app requested the permission READ_CONTACTS and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_READ_CONTACTS = 648;
- // ACTION: The permission READ_CONTACTS was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_READ_CONTACTS = 649;
- // ACTION: An app requested the permission WRITE_CONTACTS
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_WRITE_CONTACTS = 650;
- // ACTION: An app was granted the permission WRITE_CONTACTS
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_WRITE_CONTACTS = 651;
- // ACTION: An app requested the permission WRITE_CONTACTS and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_WRITE_CONTACTS = 652;
- // ACTION: The permission WRITE_CONTACTS was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_WRITE_CONTACTS = 653;
- // ACTION: An app requested the permission GET_ACCOUNTS
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_GET_ACCOUNTS = 654;
- // ACTION: An app was granted the permission GET_ACCOUNTS
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_GET_ACCOUNTS = 655;
- // ACTION: An app requested the permission GET_ACCOUNTS and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_GET_ACCOUNTS = 656;
- // ACTION: The permission GET_ACCOUNTS was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_GET_ACCOUNTS = 657;
- // ACTION: An app requested the permission ACCESS_FINE_LOCATION
- // PACKAGE: The package name of the app requesting the permission
+ // AOBSOLETE
ACTION_PERMISSION_REQUEST_ACCESS_FINE_LOCATION = 658;
- // ACTION: An app was granted the permission ACCESS_FINE_LOCATION
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_ACCESS_FINE_LOCATION = 659;
- // ACTION: An app requested the permission ACCESS_FINE_LOCATION and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_ACCESS_FINE_LOCATION = 660;
- // ACTION: The permission ACCESS_FINE_LOCATION was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_ACCESS_FINE_LOCATION = 661;
- // ACTION: An app requested the permission ACCESS_COARSE_LOCATION
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_ACCESS_COARSE_LOCATION = 662;
- // ACTION: An app was granted the permission ACCESS_COARSE_LOCATION
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_ACCESS_COARSE_LOCATION = 663;
- // ACTION: An app requested the permission ACCESS_COARSE_LOCATION and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_ACCESS_COARSE_LOCATION = 664;
- // ACTION: The permission ACCESS_COARSE_LOCATION was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_ACCESS_COARSE_LOCATION = 665;
- // ACTION: An app requested the permission RECORD_AUDIO
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_RECORD_AUDIO = 666;
- // ACTION: An app was granted the permission RECORD_AUDIO
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_RECORD_AUDIO = 667;
- // ACTION: An app requested the permission RECORD_AUDIO and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_RECORD_AUDIO = 668;
- // ACTION: The permission RECORD_AUDIO was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_RECORD_AUDIO = 669;
- // ACTION: An app requested the permission READ_PHONE_STATE
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_READ_PHONE_STATE = 670;
- // ACTION: An app was granted the permission READ_PHONE_STATE
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_READ_PHONE_STATE = 671;
- // ACTION: An app requested the permission READ_PHONE_STATE and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_READ_PHONE_STATE = 672;
- // ACTION: The permission READ_PHONE_STATE was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_READ_PHONE_STATE = 673;
- // ACTION: An app requested the permission CALL_PHONE
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_CALL_PHONE = 674;
- // ACTION: An app was granted the permission CALL_PHONE
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_CALL_PHONE = 675;
- // ACTION: An app requested the permission CALL_PHONE and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_CALL_PHONE = 676;
- // ACTION: The permission CALL_PHONE was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_CALL_PHONE = 677;
- // ACTION: An app requested the permission READ_CALL_LOG
- // PACKAGE: The package name of the app requesting the permission
+ // AOBSOLETE
ACTION_PERMISSION_REQUEST_READ_CALL_LOG = 678;
- // ACTION: An app was granted the permission READ_CALL_LOG
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_READ_CALL_LOG = 679;
- // ACTION: An app requested the permission READ_CALL_LOG and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_READ_CALL_LOG = 680;
- // ACTION: The permission READ_CALL_LOG was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_READ_CALL_LOG = 681;
- // ACTION: An app requested the permission WRITE_CALL_LOG
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_WRITE_CALL_LOG = 682;
- // ACTION: An app was granted the permission WRITE_CALL_LOG
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_WRITE_CALL_LOG = 683;
- // ACTION: An app requested the permission WRITE_CALL_LOG and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_WRITE_CALL_LOG = 684;
- // ACTION: The permission WRITE_CALL_LOG was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_WRITE_CALL_LOG = 685;
- // ACTION: An app requested the permission ADD_VOICEMAIL
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_ADD_VOICEMAIL = 686;
- // ACTION: An app was granted the permission ADD_VOICEMAIL
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_ADD_VOICEMAIL = 687;
- // ACTION: An app requested the permission ADD_VOICEMAIL and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_ADD_VOICEMAIL = 688;
- // ACTION: The permission ADD_VOICEMAIL was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_ADD_VOICEMAIL = 689;
- // ACTION: An app requested the permission USE_SIP
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_USE_SIP = 690;
- // ACTION: An app was granted the permission USE_SIP
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_USE_SIP = 691;
- // ACTION: An app requested the permission USE_SIP and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_USE_SIP = 692;
- // ACTION: The permission USE_SIP was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_USE_SIP = 693;
- // ACTION: An app requested the permission PROCESS_OUTGOING_CALLS
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_PROCESS_OUTGOING_CALLS = 694;
- // ACTION: An app was granted the permission PROCESS_OUTGOING_CALLS
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_PROCESS_OUTGOING_CALLS = 695;
- // ACTION: An app requested the permission PROCESS_OUTGOING_CALLS and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_PROCESS_OUTGOING_CALLS = 696;
- // ACTION: The permission PROCESS_OUTGOING_CALLS was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_PROCESS_OUTGOING_CALLS = 697;
- // ACTION: An app requested the permission READ_CELL_BROADCASTS
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_READ_CELL_BROADCASTS = 698;
- // ACTION: An app was granted the permission READ_CELL_BROADCASTS
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_READ_CELL_BROADCASTS = 699;
- // ACTION: An app requested the permission READ_CELL_BROADCASTS and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_READ_CELL_BROADCASTS = 700;
- // ACTION: The permission READ_CELL_BROADCASTS was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_READ_CELL_BROADCASTS = 701;
- // ACTION: An app requested the permission BODY_SENSORS
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_BODY_SENSORS = 702;
- // ACTION: An app was granted the permission BODY_SENSORS
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_BODY_SENSORS = 703;
- // ACTION: An app requested the permission BODY_SENSORS and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_BODY_SENSORS = 704;
- // ACTION: The permission BODY_SENSORS was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_BODY_SENSORS = 705;
- // ACTION: An app requested the permission SEND_SMS
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_SEND_SMS = 706;
- // ACTION: An app was granted the permission SEND_SMS
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_SEND_SMS = 707;
- // ACTION: An app requested the permission SEND_SMS and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_SEND_SMS = 708;
- // ACTION: The permission SEND_SMS was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_SEND_SMS = 709;
- // ACTION: An app requested the permission RECEIVE_SMS
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_RECEIVE_SMS = 710;
- // ACTION: An app was granted the permission RECEIVE_SMS
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_RECEIVE_SMS = 711;
- // ACTION: An app requested the permission RECEIVE_SMS and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_RECEIVE_SMS = 712;
- // ACTION: The permission RECEIVE_SMS was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_RECEIVE_SMS = 713;
- // ACTION: An app requested the permission READ_SMS
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_READ_SMS = 714;
- // ACTION: An app was granted the permission READ_SMS
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_READ_SMS = 715;
- // ACTION: An app requested the permission READ_SMS and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_READ_SMS = 716;
- // ACTION: The permission READ_SMS was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_READ_SMS = 717;
- // ACTION: An app requested the permission RECEIVE_WAP_PUSH
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_RECEIVE_WAP_PUSH = 718;
- // ACTION: An app was granted the permission RECEIVE_WAP_PUSH
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_RECEIVE_WAP_PUSH = 719;
- // ACTION: An app requested the permission RECEIVE_WAP_PUSH and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_RECEIVE_WAP_PUSH = 720;
- // ACTION: The permission RECEIVE_WAP_PUSH was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_RECEIVE_WAP_PUSH = 721;
- // ACTION: An app requested the permission RECEIVE_MMS
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_RECEIVE_MMS = 722;
- // ACTION: An app was granted the permission RECEIVE_MMS
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_RECEIVE_MMS = 723;
- // ACTION: An app requested the permission RECEIVE_MMS and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_RECEIVE_MMS = 724;
- // ACTION: The permission RECEIVE_MMS was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_RECEIVE_MMS = 725;
- // ACTION: An app requested the permission READ_EXTERNAL_STORAGE
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_READ_EXTERNAL_STORAGE = 726;
- // ACTION: An app was granted the permission READ_EXTERNAL_STORAGE
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_READ_EXTERNAL_STORAGE = 727;
- // ACTION: An app requested the permission READ_EXTERNAL_STORAGE and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_READ_EXTERNAL_STORAGE = 728;
- // ACTION: The permission READ_EXTERNAL_STORAGE was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_READ_EXTERNAL_STORAGE = 729;
- // ACTION: An app requested the permission WRITE_EXTERNAL_STORAGE
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE = 730;
- // ACTION: An app was granted the permission WRITE_EXTERNAL_STORAGE
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_WRITE_EXTERNAL_STORAGE = 731;
- // ACTION: An app requested the permission WRITE_EXTERNAL_STORAGE and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_WRITE_EXTERNAL_STORAGE = 732;
- // ACTION: The permission WRITE_EXTERNAL_STORAGE was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_WRITE_EXTERNAL_STORAGE = 733;
// ACTION: Logged when a provisioning session has started
@@ -3221,20 +3117,16 @@
// ACTION: Logged when a provisioning session has completed
PROVISIONING_SESSION_COMPLETED = 735;
- // ACTION: An app requested the permission READ_PHONE_NUMBERS
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_READ_PHONE_NUMBERS = 736;
- // ACTION: An app was granted the permission READ_PHONE_NUMBERS
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_READ_PHONE_NUMBERS = 737;
- // ACTION: An app requested the permission READ_PHONE_NUMBERS and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_READ_PHONE_NUMBERS = 738;
- // ACTION: The permission READ_PHONE_NUMBERS was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_READ_PHONE_NUMBERS = 739;
// ACTION: QS Brightness Slider (with auto brightness disabled, and VR enabled)
@@ -3726,68 +3618,52 @@
// CATEGORY: SETTINGS
SETTINGS_LOCK_SCREEN_PREFERENCES = 882;
- // ACTION: An app requested the app-op permission ACCESS_NOTIFICATIONS
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_APPOP_REQUEST_ACCESS_NOTIFICATIONS = 883;
- // ACTION: An app was granted the app-op permission ACCESS_NOTIFICATIONS
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_APPOP_GRANT_ACCESS_NOTIFICATIONS = 884;
- // ACTION: An app requested the app-op permission ACCESS_NOTIFICATIONS and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_APPOP_DENIED_ACCESS_NOTIFICATIONS = 885;
- // ACTION: The app-op permission ACCESS_NOTIFICATIONS was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_APPOP_REVOKE_ACCESS_NOTIFICATIONS = 886;
- // ACTION: An app requested the app-op permission SYSTEM_ALERT_WINDOW
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_APPOP_REQUEST_SYSTEM_ALERT_WINDOW = 887;
- // ACTION: An app was granted the app-op permission SYSTEM_ALERT_WINDOW
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_APPOP_GRANT_SYSTEM_ALERT_WINDOW = 888;
- // ACTION: An app requested the app-op permission SYSTEM_ALERT_WINDOW and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_APPOP_DENIED_SYSTEM_ALERT_WINDOW = 889;
- // ACTION: The app-op permission SYSTEM_ALERT_WINDOW was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_APPOP_REVOKE_SYSTEM_ALERT_WINDOW = 890;
- // ACTION: An app requested the app-op permission REQUEST_WRITE_SETTINGS
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_APPOP_REQUEST_WRITE_SETTINGS = 891;
- // ACTION: An app was granted the app-op permission REQUEST_WRITE_SETTINGS
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_APPOP_GRANT_WRITE_SETTINGS = 892;
- // ACTION: An app requested the app-op permission REQUEST_WRITE_SETTINGS and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_APPOP_DENIED_WRITE_SETTINGS = 893;
- // ACTION: The app-op permission REQUEST_WRITE_SETTINGS was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_APPOP_REVOKE_WRITE_SETTINGS = 894;
- // ACTION: An app requested the app-op permission REQUEST_INSTALL_PACKAGES
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_APPOP_REQUEST_REQUEST_INSTALL_PACKAGES = 895;
- // ACTION: An app was granted the app-op permission REQUEST_INSTALL_PACKAGES
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_APPOP_GRANT_REQUEST_INSTALL_PACKAGES = 896;
- // ACTION: An app requested the app-op permission REQUEST_INSTALL_PACKAGES and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_APPOP_DENIED_REQUEST_INSTALL_PACKAGES = 897;
- // ACTION: The app-op permission REQUEST_INSTALL_PACKAGES was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_APPOP_REVOKE_REQUEST_INSTALL_PACKAGES = 898;
// ACTION: Phase 1 of instant application resolution occurred
@@ -4759,6 +4635,37 @@
// OS: P
ACTION_WIFI_AUTO_SIGN_IN = 1239;
+ // Open: Settings > System > About phone > IMEI
+ // CATEGORY: SETTINGS
+ // OS: P
+ DIALOG_IMEI_INFO = 1240;
+
+ // In permission action fields tagged like this reference the permission affected
+ FIELD_PERMISSION = 1241;
+
+ // ACTION: An app requested a permission and we asked to user to approve the request
+ // PACKAGE: The package name of the app requesting the permission
+ // Tag FIELD_PERMISSION: Name of the permission requested
+ ACTION_PERMISSION_REQUESTED = 1242;
+
+ // ACTION: An app was granted the a permission. This can happen after a user approved a request
+ // or automatically. In the second case there will not be an
+ // ACTION_PERMISSION_REQUESTED.
+ // PACKAGE: The package name of the app that was granted the permission
+ // Tag FIELD_PERMISSION: Name of the permission granted
+ ACTION_PERMISSION_GRANTED = 1243;
+
+ // ACTION: An app requested the a permission and the request was denied by the user or a device
+ // policy
+ // PACKAGE: The package name of the app requesting the permission
+ // Tag FIELD_PERMISSION: Name of the permission denied
+ ACTION_PERMISSION_DENIED = 1244;
+
+ // ACTION: A permission was revoked
+ // PACKAGE: The package name of the app the permission was revoked for
+ // Tag FIELD_PERMISSION: Name of the permission revoked
+ ACTION_PERMISSION_REVOKED = 1245;
+
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
}
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 622b8423..e92a564 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -80,6 +80,7 @@
import android.content.pm.Signature;
import android.database.ContentObserver;
import android.net.Uri;
+import android.os.PowerManager.ServiceType;
import android.os.PowerSaveState;
import android.os.Binder;
import android.os.Build;
@@ -126,7 +127,6 @@
import com.android.server.SystemConfig;
import com.android.server.SystemService;
import com.android.server.backup.PackageManagerBackupAgent.Metadata;
-import com.android.server.power.BatterySaverPolicy.ServiceType;
import libcore.io.IoUtils;
diff --git a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
index 20f2369..a45a4f0 100644
--- a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
@@ -71,6 +71,7 @@
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.PowerManager;
+import android.os.PowerManager.ServiceType;
import android.os.PowerSaveState;
import android.os.Process;
import android.os.RemoteException;
@@ -120,7 +121,6 @@
import com.android.server.backup.utils.BackupManagerMonitorUtils;
import com.android.server.backup.utils.BackupObserverUtils;
import com.android.server.backup.utils.SparseArrayUtils;
-import com.android.server.power.BatterySaverPolicy.ServiceType;
import com.google.android.collect.Sets;
diff --git a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
index 8d8a013..a08c19e 100644
--- a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
+++ b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
@@ -158,16 +158,19 @@
MSG_RESTORE_SESSION_TIMEOUT);
long oldId = Binder.clearCallingIdentity();
- backupManagerService.getWakelock().acquire();
- if (MORE_DEBUG) {
- Slog.d(TAG, "restoreAll() kicking off");
+ try {
+ backupManagerService.getWakelock().acquire();
+ if (MORE_DEBUG) {
+ Slog.d(TAG, "restoreAll() kicking off");
+ }
+ Message msg = backupManagerService.getBackupHandler().obtainMessage(
+ MSG_RUN_RESTORE);
+ msg.obj = new RestoreParams(mRestoreTransport, dirName,
+ observer, monitor, token);
+ backupManagerService.getBackupHandler().sendMessage(msg);
+ } finally {
+ Binder.restoreCallingIdentity(oldId);
}
- Message msg = backupManagerService.getBackupHandler().obtainMessage(
- MSG_RUN_RESTORE);
- msg.obj = new RestoreParams(mRestoreTransport, dirName,
- observer, monitor, token);
- backupManagerService.getBackupHandler().sendMessage(msg);
- Binder.restoreCallingIdentity(oldId);
return 0;
}
}
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 8b79b9d..0e51fda 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -27,6 +27,7 @@
import android.hardware.input.InputManager;
import android.hardware.vibrator.V1_0.Constants.EffectStrength;
import android.media.AudioManager;
+import android.os.PowerManager.ServiceType;
import android.os.PowerSaveState;
import android.os.BatteryStats;
import android.os.Handler;
@@ -56,7 +57,6 @@
import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IBatteryStats;
import com.android.internal.util.DumpUtils;
-import com.android.server.power.BatterySaverPolicy.ServiceType;
import java.io.FileDescriptor;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 52f9702..a035bd0 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -21,6 +21,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.net.wifi.WifiActivityEnergyInfo;
+import android.os.PowerManager.ServiceType;
import android.os.PowerSaveState;
import android.os.BatteryStats;
import android.os.BatteryStatsInternal;
@@ -53,7 +54,6 @@
import com.android.internal.os.RpmStats;
import com.android.internal.util.DumpUtils;
import com.android.server.LocalServices;
-import com.android.server.power.BatterySaverPolicy.ServiceType;
import android.util.StatsLog;
import java.io.File;
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 660659f..beb7486 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -48,6 +48,7 @@
import android.net.NetworkRequest;
import android.net.Uri;
import android.os.AsyncTask;
+import android.os.PowerManager.ServiceType;
import android.os.PowerSaveState;
import android.os.BatteryStats;
import android.os.Binder;
@@ -84,7 +85,6 @@
import com.android.internal.location.ProviderRequest;
import com.android.server.power.BatterySaverPolicy;
-import com.android.server.power.BatterySaverPolicy.ServiceType;
import libcore.io.IoUtils;
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index b4056b3..551cb10 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -142,6 +142,7 @@
import android.os.MessageQueue.IdleHandler;
import android.os.PersistableBundle;
import android.os.PowerManager;
+import android.os.PowerManager.ServiceType;
import android.os.PowerManagerInternal;
import android.os.PowerSaveState;
import android.os.Process;
@@ -192,7 +193,6 @@
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemConfig;
-import com.android.server.power.BatterySaverPolicy.ServiceType;
import libcore.io.IoUtils;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 7837b02..6c42f4f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -574,37 +574,6 @@
public static final int REASON_LAST = REASON_SHARED;
- /** All dangerous permission names in the same order as the events in MetricsEvent */
- private static final List<String> ALL_DANGEROUS_PERMISSIONS = Arrays.asList(
- Manifest.permission.READ_CALENDAR,
- Manifest.permission.WRITE_CALENDAR,
- Manifest.permission.CAMERA,
- Manifest.permission.READ_CONTACTS,
- Manifest.permission.WRITE_CONTACTS,
- Manifest.permission.GET_ACCOUNTS,
- Manifest.permission.ACCESS_FINE_LOCATION,
- Manifest.permission.ACCESS_COARSE_LOCATION,
- Manifest.permission.RECORD_AUDIO,
- Manifest.permission.READ_PHONE_STATE,
- Manifest.permission.CALL_PHONE,
- Manifest.permission.READ_CALL_LOG,
- Manifest.permission.WRITE_CALL_LOG,
- Manifest.permission.ADD_VOICEMAIL,
- Manifest.permission.USE_SIP,
- Manifest.permission.PROCESS_OUTGOING_CALLS,
- Manifest.permission.READ_CELL_BROADCASTS,
- Manifest.permission.BODY_SENSORS,
- Manifest.permission.SEND_SMS,
- Manifest.permission.RECEIVE_SMS,
- Manifest.permission.READ_SMS,
- Manifest.permission.RECEIVE_WAP_PUSH,
- Manifest.permission.RECEIVE_MMS,
- Manifest.permission.READ_EXTERNAL_STORAGE,
- Manifest.permission.WRITE_EXTERNAL_STORAGE,
- Manifest.permission.READ_PHONE_NUMBERS,
- Manifest.permission.ANSWER_PHONE_CALLS);
-
-
/**
* Version number for the package parser cache. Increment this whenever the format or
* extent of cached data changes. See {@code PackageParser#setCacheDir}.
@@ -5176,66 +5145,6 @@
getCallingUid(), userId, mPermissionCallback);
}
- /**
- * Get the first event id for the permission.
- *
- * <p>There are four events for each permission: <ul>
- * <li>Request permission: first id + 0</li>
- * <li>Grant permission: first id + 1</li>
- * <li>Request for permission denied: first id + 2</li>
- * <li>Revoke permission: first id + 3</li>
- * </ul></p>
- *
- * @param name name of the permission
- *
- * @return The first event id for the permission
- */
- private static int getBaseEventId(@NonNull String name) {
- int eventIdIndex = ALL_DANGEROUS_PERMISSIONS.indexOf(name);
-
- if (eventIdIndex == -1) {
- if (AppOpsManager.permissionToOpCode(name) == AppOpsManager.OP_NONE
- || Build.IS_USER) {
- Log.i(TAG, "Unknown permission " + name);
-
- return MetricsEvent.ACTION_PERMISSION_REQUEST_UNKNOWN;
- } else {
- // Most likely #ALL_DANGEROUS_PERMISSIONS needs to be updated.
- //
- // Also update
- // - EventLogger#ALL_DANGEROUS_PERMISSIONS
- // - metrics_constants.proto
- throw new IllegalStateException("Unknown permission " + name);
- }
- }
-
- return MetricsEvent.ACTION_PERMISSION_REQUEST_READ_CALENDAR + eventIdIndex * 4;
- }
-
- /**
- * Log that a permission was revoked.
- *
- * @param context Context of the caller
- * @param name name of the permission
- * @param packageName package permission if for
- */
- private static void logPermissionRevoked(@NonNull Context context, @NonNull String name,
- @NonNull String packageName) {
- MetricsLogger.action(context, getBaseEventId(name) + 3, packageName);
- }
-
- /**
- * Log that a permission request was granted.
- *
- * @param context Context of the caller
- * @param name name of the permission
- * @param packageName package permission if for
- */
- private static void logPermissionGranted(@NonNull Context context, @NonNull String name,
- @NonNull String packageName) {
- MetricsLogger.action(context, getBaseEventId(name) + 1, packageName);
- }
-
@Override
public void resetRuntimePermissions() {
mContext.enforceCallingOrSelfPermission(
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
index cf9e6f3..781216c 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
@@ -59,6 +59,8 @@
// vendor.
if ("pm.dexopt.inactive".equals(sysPropName)) {
sysPropValue = "verify";
+ } else if ("pm.dexopt.shared".equals(sysPropName)) {
+ sysPropValue = "speed";
} else {
sysPropValue = SystemProperties.get(sysPropName);
}
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 1c002aa..25e9239 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -2262,6 +2262,10 @@
final ShortcutUser user = getUserShortcutsLocked(userId);
+ if (user.hasHostPackage(packageName)) {
+ return true;
+ }
+
// Always trust the cached component.
final ComponentName cached = user.getCachedLauncher();
if (cached != null) {
@@ -2361,6 +2365,16 @@
}
}
+ public void setShortcutHostPackage(@NonNull String type, @Nullable String packageName,
+ int userId) {
+ synchronized (mLock) {
+ throwIfUserLockedL(userId);
+
+ final ShortcutUser user = getUserShortcutsLocked(userId);
+ user.setShortcutHostPackage(type, packageName);
+ }
+ }
+
// === House keeping ===
private void cleanUpPackageForAllLoadedUsers(String packageName, @UserIdInt int packageUserId,
@@ -2697,6 +2711,12 @@
}
@Override
+ public void setShortcutHostPackage(@NonNull String type, @Nullable String packageName,
+ int userId) {
+ ShortcutService.this.setShortcutHostPackage(type, packageName, userId);
+ }
+
+ @Override
public boolean requestPinAppWidget(@NonNull String callingPackage,
@NonNull AppWidgetProviderInfo appWidget, @Nullable Bundle extras,
@Nullable IntentSender resultIntent, int userId) {
diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java
index 48eccd0..1efd765 100644
--- a/services/core/java/com/android/server/pm/ShortcutUser.java
+++ b/services/core/java/com/android/server/pm/ShortcutUser.java
@@ -23,6 +23,7 @@
import android.text.TextUtils;
import android.text.format.Formatter;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
@@ -123,6 +124,20 @@
/** In-memory-cached default launcher. */
private ComponentName mCachedLauncher;
+ /**
+ * Keep track of additional packages that other parts of the system have said are
+ * allowed to access shortcuts. The key is the part of the system it came from,
+ * the value is the package name that has access. We don't persist these because
+ * at boot all relevant system services will push this data back to us they do their
+ * normal evaluation of the state of the world.
+ */
+ private final ArrayMap<String, String> mHostPackages = new ArrayMap<>();
+
+ /**
+ * Set of package name values from above.
+ */
+ private final ArraySet<String> mHostPackageSet = new ArraySet<>();
+
private String mKnownLocales;
private long mLastAppScanTime;
@@ -467,6 +482,23 @@
return mCachedLauncher;
}
+ public void setShortcutHostPackage(@NonNull String type, @Nullable String packageName) {
+ if (packageName != null) {
+ mHostPackages.put(type, packageName);
+ } else {
+ mHostPackages.remove(type);
+ }
+
+ mHostPackageSet.clear();
+ for (int i = 0; i < mHostPackages.size(); i++) {
+ mHostPackageSet.add(mHostPackages.valueAt(i));
+ }
+ }
+
+ public boolean hasHostPackage(@NonNull String packageName) {
+ return mHostPackageSet.contains(packageName);
+ }
+
public void resetThrottling() {
for (int i = mPackages.size() - 1; i >= 0; i--) {
mPackages.valueAt(i).resetThrottling();
@@ -555,6 +587,18 @@
pw.print("Last known launcher: ");
pw.print(mLastKnownLauncher);
pw.println();
+
+ if (mHostPackages.size() > 0) {
+ pw.print(prefix);
+ pw.println("Host packages:");
+ for (int i = 0; i < mHostPackages.size(); i++) {
+ pw.print(prefix);
+ pw.print(" ");
+ pw.print(mHostPackages.keyAt(i));
+ pw.print(": ");
+ pw.println(mHostPackages.valueAt(i));
+ }
+ }
}
for (int i = 0; i < mLaunchers.size(); i++) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 76805ce..6d2051f 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -37,6 +37,7 @@
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.content.pm.PackageParser.Package;
+import android.metrics.LogMaker;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
@@ -92,36 +93,6 @@
public class PermissionManagerService {
private static final String TAG = "PackageManager";
- /** All dangerous permission names in the same order as the events in MetricsEvent */
- private static final List<String> ALL_DANGEROUS_PERMISSIONS = Arrays.asList(
- Manifest.permission.READ_CALENDAR,
- Manifest.permission.WRITE_CALENDAR,
- Manifest.permission.CAMERA,
- Manifest.permission.READ_CONTACTS,
- Manifest.permission.WRITE_CONTACTS,
- Manifest.permission.GET_ACCOUNTS,
- Manifest.permission.ACCESS_FINE_LOCATION,
- Manifest.permission.ACCESS_COARSE_LOCATION,
- Manifest.permission.RECORD_AUDIO,
- Manifest.permission.READ_PHONE_STATE,
- Manifest.permission.CALL_PHONE,
- Manifest.permission.READ_CALL_LOG,
- Manifest.permission.WRITE_CALL_LOG,
- Manifest.permission.ADD_VOICEMAIL,
- Manifest.permission.USE_SIP,
- Manifest.permission.PROCESS_OUTGOING_CALLS,
- Manifest.permission.READ_CELL_BROADCASTS,
- Manifest.permission.BODY_SENSORS,
- Manifest.permission.SEND_SMS,
- Manifest.permission.RECEIVE_SMS,
- Manifest.permission.READ_SMS,
- Manifest.permission.RECEIVE_WAP_PUSH,
- Manifest.permission.RECEIVE_MMS,
- Manifest.permission.READ_EXTERNAL_STORAGE,
- Manifest.permission.WRITE_EXTERNAL_STORAGE,
- Manifest.permission.READ_PHONE_NUMBERS,
- Manifest.permission.ANSWER_PHONE_CALLS);
-
/** Permission grant: not grant the permission. */
private static final int GRANT_DENIED = 1;
/** Permission grant: grant the permission as an install permission. */
@@ -160,6 +131,7 @@
private final HandlerThread mHandlerThread;
private final Handler mHandler;
private final Context mContext;
+ private final MetricsLogger mMetricsLogger = new MetricsLogger();
/** Internal storage for permissions and related settings */
@GuardedBy("mLock")
@@ -1386,7 +1358,7 @@
}
if (bp.isRuntime()) {
- logPermissionGranted(mContext, permName, packageName);
+ logPermission(MetricsEvent.ACTION_PERMISSION_GRANTED, permName, packageName);
}
if (callback != null) {
@@ -1484,7 +1456,7 @@
}
if (bp.isRuntime()) {
- logPermissionRevoked(mContext, permName, packageName);
+ logPermission(MetricsEvent.ACTION_PERMISSION_REVOKED, permName, packageName);
}
if (callback != null) {
@@ -1938,63 +1910,18 @@
}
/**
- * Get the first event id for the permission.
+ * Log that a permission request was granted/revoked.
*
- * <p>There are four events for each permission: <ul>
- * <li>Request permission: first id + 0</li>
- * <li>Grant permission: first id + 1</li>
- * <li>Request for permission denied: first id + 2</li>
- * <li>Revoke permission: first id + 3</li>
- * </ul></p>
- *
+ * @param action the action performed
* @param name name of the permission
- *
- * @return The first event id for the permission
+ * @param packageName package permission is for
*/
- private static int getBaseEventId(@NonNull String name) {
- int eventIdIndex = ALL_DANGEROUS_PERMISSIONS.indexOf(name);
+ private void logPermission(int action, @NonNull String name, @NonNull String packageName) {
+ final LogMaker log = new LogMaker(action);
+ log.setPackageName(packageName);
+ log.addTaggedData(MetricsEvent.FIELD_PERMISSION, name);
- if (eventIdIndex == -1) {
- if (AppOpsManager.permissionToOpCode(name) == AppOpsManager.OP_NONE
- || Build.IS_USER) {
- Log.i(TAG, "Unknown permission " + name);
-
- return MetricsEvent.ACTION_PERMISSION_REQUEST_UNKNOWN;
- } else {
- // Most likely #ALL_DANGEROUS_PERMISSIONS needs to be updated.
- //
- // Also update
- // - EventLogger#ALL_DANGEROUS_PERMISSIONS
- // - metrics_constants.proto
- throw new IllegalStateException("Unknown permission " + name);
- }
- }
-
- return MetricsEvent.ACTION_PERMISSION_REQUEST_READ_CALENDAR + eventIdIndex * 4;
- }
-
- /**
- * Log that a permission was revoked.
- *
- * @param context Context of the caller
- * @param name name of the permission
- * @param packageName package permission if for
- */
- private static void logPermissionRevoked(@NonNull Context context, @NonNull String name,
- @NonNull String packageName) {
- MetricsLogger.action(context, getBaseEventId(name) + 3, packageName);
- }
-
- /**
- * Log that a permission request was granted.
- *
- * @param context Context of the caller
- * @param name name of the permission
- * @param packageName package permission if for
- */
- private static void logPermissionGranted(@NonNull Context context, @NonNull String name,
- @NonNull String packageName) {
- MetricsLogger.action(context, getBaseEventId(name) + 1, packageName);
+ mMetricsLogger.write(log);
}
private class PermissionManagerInternalImpl extends PermissionManagerInternal {
diff --git a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
index edd2fdb..c6ec287 100644
--- a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
+++ b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
@@ -52,6 +52,7 @@
import android.widget.FrameLayout;
import com.android.internal.R;
+import com.android.server.vr.VrManagerService;
/**
* Helper to manage showing/hiding a confirmation prompt when the navigation bar is hidden
@@ -147,7 +148,6 @@
&& userSetupComplete
&& !mVrModeEnabled
&& !navBarEmpty
- && !isLockTaskModeLocked()
&& !UserManager.isDeviceInDemoMode(mContext)) {
mHandler.sendEmptyMessageDelayed(H.SHOW, mShowDelayMs);
}
@@ -156,20 +156,6 @@
}
}
- /**
- * @return {@code true} if and only if the device is currently in LockTask mode managed by
- * {@link android.app.admin.DevicePolicyManager}. Note that this differs from the screen pinning
- * mode which is initiated by the user.
- */
- private boolean isLockTaskModeLocked() {
- try {
- return ActivityManager.getService().getLockTaskModeState()
- == ActivityManager.LOCK_TASK_MODE_LOCKED;
- } catch (RemoteException e) {
- return false;
- }
- }
-
public boolean onPowerKeyDown(boolean isScreenOn, long time, boolean inImmersiveMode,
boolean navBarEmpty) {
if (!isScreenOn && (time - mPanicTime < mPanicThresholdMs)) {
diff --git a/services/core/java/com/android/server/power/BatterySaverPolicy.java b/services/core/java/com/android/server/power/BatterySaverPolicy.java
index 1781d8c..273b945 100644
--- a/services/core/java/com/android/server/power/BatterySaverPolicy.java
+++ b/services/core/java/com/android/server/power/BatterySaverPolicy.java
@@ -20,6 +20,8 @@
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
+import android.os.PowerManager;
+import android.os.PowerManager.ServiceType;
import android.provider.Settings;
import android.util.KeyValueListParser;
import android.util.Slog;
@@ -34,31 +36,6 @@
* Class to decide whether to turn on battery saver mode for specific service
*/
public class BatterySaverPolicy extends ContentObserver {
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({ServiceType.GPS,
- ServiceType.VIBRATION,
- ServiceType.ANIMATION,
- ServiceType.FULL_BACKUP,
- ServiceType.KEYVALUE_BACKUP,
- ServiceType.NETWORK_FIREWALL,
- ServiceType.SCREEN_BRIGHTNESS,
- ServiceType.SOUND,
- ServiceType.BATTERY_STATS,
- ServiceType.DATA_SAVER})
- public @interface ServiceType {
- int NULL = 0;
- int GPS = 1;
- int VIBRATION = 2;
- int ANIMATION = 3;
- int FULL_BACKUP = 4;
- int KEYVALUE_BACKUP = 5;
- int NETWORK_FIREWALL = 6;
- int SCREEN_BRIGHTNESS = 7;
- int SOUND = 8;
- int BATTERY_STATS = 9;
- int DATA_SAVER = 10;
- }
-
private static final String TAG = "BatterySaverPolicy";
// Value of batterySaverGpsMode such that GPS isn't affected by battery saver mode.
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 2494bde..8f23cf8 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -43,6 +43,7 @@
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
+import android.os.PowerManager.ServiceType;
import android.os.PowerManagerInternal;
import android.os.PowerSaveState;
import android.os.Process;
@@ -89,7 +90,6 @@
import com.android.server.am.BatteryStatsService;
import com.android.server.lights.Light;
import com.android.server.lights.LightsManager;
-import com.android.server.power.BatterySaverPolicy.ServiceType;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 41534cb..2488723 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -286,10 +286,6 @@
}
}
- // These values must be kept in sync with cmd/statsd/StatsPullerManager.h.
- // TODO: pull the constant from stats_events.proto instead
- private static final int PULL_CODE_KERNEL_WAKELOCKS = 20;
-
private final KernelWakelockReader mKernelWakelockReader = new KernelWakelockReader();
private final KernelWakelockStats mTmpWakelockStats = new KernelWakelockStats();
@@ -347,12 +343,12 @@
}
@Override // Binder call
- public StatsLogEventWrapper[] pullData(int pullCode) {
+ public StatsLogEventWrapper[] pullData(int tagId) {
enforceCallingPermission();
if (DEBUG)
- Slog.d(TAG, "Pulling " + pullCode);
+ Slog.d(TAG, "Pulling " + tagId);
- switch (pullCode) {
+ switch (tagId) {
case StatsLog.WIFI_BYTES_TRANSFERRED: {
long token = Binder.clearCallingIdentity();
try {
@@ -366,7 +362,7 @@
// Combine all the metrics per Uid into one record.
NetworkStats stats = nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces,
NetworkStats.TAG_NONE, null).groupedByUid();
- return addNetworkStats(pullCode, stats, false);
+ return addNetworkStats(tagId, stats, false);
} catch (java.io.IOException e) {
Slog.e(TAG, "Pulling netstats for wifi bytes has error", e);
} finally {
@@ -386,7 +382,7 @@
// Combine all the metrics per Uid into one record.
NetworkStats stats = nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces,
NetworkStats.TAG_NONE, null).groupedByUid();
- return addNetworkStats(pullCode, stats, false);
+ return addNetworkStats(tagId, stats, false);
} catch (java.io.IOException e) {
Slog.e(TAG, "Pulling netstats for mobile bytes has error", e);
} finally {
@@ -406,7 +402,7 @@
NetworkStats stats = rollupNetworkStatsByFGBG(
nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces,
NetworkStats.TAG_NONE, null));
- return addNetworkStats(pullCode, stats, true);
+ return addNetworkStats(tagId, stats, true);
} catch (java.io.IOException e) {
Slog.e(TAG, "Pulling netstats for wifi bytes w/ fg/bg has error", e);
} finally {
@@ -426,7 +422,7 @@
NetworkStats stats = rollupNetworkStatsByFGBG(
nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces,
NetworkStats.TAG_NONE, null));
- return addNetworkStats(pullCode, stats, true);
+ return addNetworkStats(tagId, stats, true);
} catch (java.io.IOException e) {
Slog.e(TAG, "Pulling netstats for mobile bytes w/ fg/bg has error", e);
} finally {
@@ -434,14 +430,14 @@
}
break;
}
- case StatsLog.KERNEL_WAKELOCKS_REPORTED: {
+ case StatsLog.KERNEL_WAKELOCK_PULLED: {
final KernelWakelockStats wakelockStats =
mKernelWakelockReader.readKernelWakelockStats(mTmpWakelockStats);
List<StatsLogEventWrapper> ret = new ArrayList();
for (Map.Entry<String, KernelWakelockStats.Entry> ent : wakelockStats.entrySet()) {
String name = ent.getKey();
KernelWakelockStats.Entry kws = ent.getValue();
- StatsLogEventWrapper e = new StatsLogEventWrapper(pullCode, 4);
+ StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 4);
e.writeString(name);
e.writeInt(kws.mCount);
e.writeInt(kws.mVersion);
@@ -451,7 +447,7 @@
return ret.toArray(new StatsLogEventWrapper[ret.size()]);
}
default:
- Slog.w(TAG, "No such pollable data as " + pullCode);
+ Slog.w(TAG, "No such tagId data as " + tagId);
return null;
}
return null;
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index e7e4efc..e8ebbe4 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -166,6 +166,8 @@
private boolean mUserUnlocked;
private Vr2dDisplay mVr2dDisplay;
private boolean mBootsToVr;
+ private boolean mStandby;
+ private boolean mUseStandbyToExitVrMode;
// Handles events from the managed services (e.g. VrListenerService and any bound VR compositor
// service).
@@ -203,7 +205,10 @@
*
*/
private void updateVrModeAllowedLocked() {
- boolean allowed = mSystemSleepFlags == FLAG_ALL && mUserUnlocked;
+ boolean ignoreSleepFlags = mBootsToVr && mUseStandbyToExitVrMode;
+ boolean disallowedByStandby = mStandby && mUseStandbyToExitVrMode;
+ boolean allowed = (mSystemSleepFlags == FLAG_ALL || ignoreSleepFlags) && mUserUnlocked
+ && !disallowedByStandby;
if (mVrModeAllowed != allowed) {
mVrModeAllowed = allowed;
if (DBG) Slog.d(TAG, "VR mode is " + ((allowed) ? "allowed" : "disallowed"));
@@ -273,6 +278,17 @@
}
}
+ private void setStandbyEnabled(boolean standby) {
+ synchronized(mLock) {
+ if (!mBootsToVr) {
+ Slog.e(TAG, "Attempting to set standby mode on a non-standalone device");
+ return;
+ }
+ mStandby = standby;
+ updateVrModeAllowedLocked();
+ }
+ }
+
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
@@ -587,6 +603,12 @@
}
@Override
+ public void setStandbyEnabled(boolean standby) {
+ enforceCallerPermissionAnyOf(Manifest.permission.ACCESS_VR_MANAGER);
+ VrManagerService.this.setStandbyEnabled(standby);
+ }
+
+ @Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
@@ -733,6 +755,8 @@
}
mBootsToVr = SystemProperties.getBoolean("ro.boot.vr", false);
+ mUseStandbyToExitVrMode = mBootsToVr
+ && SystemProperties.getBoolean("persist.vr.use_standby_to_exit_vr_mode", false);
publishLocalService(VrManagerInternal.class, new LocalService());
publishBinderService(Context.VR_SERVICE, mVrManager.asBinder());
}
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 0ac2cff..6e89e3e 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -523,7 +523,7 @@
final DividerSnapAlgorithm algorithm = new DividerSnapAlgorithm(
mService.mContext.getResources(), displayWidth, displayHeight,
dividerSize, orientation == Configuration.ORIENTATION_PORTRAIT, outBounds,
- isMinimizedDockAndHomeStackResizable());
+ getDockSide(), isMinimizedDockAndHomeStackResizable());
final SnapTarget target = algorithm.calculateNonDismissingSnapTarget(dividerPosition);
// Recalculate the bounds based on the position of the target.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index bf5f4bc..b28bb71 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -158,6 +158,7 @@
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.PowerManager;
+import android.os.PowerManager.ServiceType;
import android.os.PowerManagerInternal;
import android.os.PowerSaveState;
import android.os.RemoteException;
@@ -243,7 +244,6 @@
import com.android.server.UiThread;
import com.android.server.Watchdog;
import com.android.server.input.InputManagerService;
-import com.android.server.power.BatterySaverPolicy.ServiceType;
import com.android.server.power.ShutdownThread;
import com.android.server.utils.PriorityDump;
diff --git a/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java b/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
index 69589e7..50ac41c 100644
--- a/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
@@ -15,13 +15,12 @@
*/
package com.android.server.power;
+import android.os.PowerManager.ServiceType;
import android.os.PowerSaveState;
import android.os.Handler;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
-import com.android.server.power.BatterySaverPolicy.ServiceType;
-
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index 4559660..b60d5bf 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -66,7 +66,7 @@
.setBrightnessFactor(BRIGHTNESS_FACTOR)
.build();
when(mBatterySaverPolicy.getBatterySaverPolicy(
- eq(BatterySaverPolicy.ServiceType.SCREEN_BRIGHTNESS), anyBoolean()))
+ eq(PowerManager.ServiceType.SCREEN_BRIGHTNESS), anyBoolean()))
.thenReturn(mPowerSaveState);
mDisplayPowerRequest = new DisplayPowerRequest();
mService = new PowerManagerService(getContext(), mBatterySaverPolicy);
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
index ea4f4b9..bb88264 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -46,11 +46,13 @@
* bit FrameworksServicesTests:com.android.server.wm.AppWindowTokenTests
*/
@SmallTest
-@Presubmit
+// TODO: b/68267650
+// @Presubmit
@RunWith(AndroidJUnit4.class)
public class AppWindowTokenTests extends WindowTestsBase {
@Test
+ @Presubmit
public void testAddWindow_Order() throws Exception {
final WindowTestUtils.TestAppWindowToken token =
new WindowTestUtils.TestAppWindowToken(mDisplayContent);
@@ -79,6 +81,7 @@
}
@Test
+ @Presubmit
public void testFindMainWindow() throws Exception {
final WindowTestUtils.TestAppWindowToken token =
new WindowTestUtils.TestAppWindowToken(mDisplayContent);
@@ -97,6 +100,7 @@
}
@Test
+ @Presubmit
public void testGetTopFullscreenWindow() throws Exception {
final WindowTestUtils.TestAppWindowToken token =
new WindowTestUtils.TestAppWindowToken(mDisplayContent);
@@ -187,6 +191,7 @@
}
@Test
+ @Presubmit
public void testGetOrientation() throws Exception {
final WindowTestUtils.TestAppWindowToken token =
new WindowTestUtils.TestAppWindowToken(mDisplayContent);
@@ -211,6 +216,7 @@
}
@Test
+ @Presubmit
public void testKeyguardFlagsDuringRelaunch() throws Exception {
final WindowTestUtils.TestAppWindowToken token =
new WindowTestUtils.TestAppWindowToken(mDisplayContent);
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
index f53eb15..25c54b3 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -36,12 +36,12 @@
import android.hardware.soundtrigger.SoundTriggerModule;
import android.os.DeadObjectException;
import android.os.PowerManager;
+import android.os.PowerManager.ServiceType;
import android.os.RemoteException;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Slog;
import com.android.internal.logging.MetricsLogger;
-import com.android.server.power.BatterySaverPolicy.ServiceType;
import java.io.FileDescriptor;
import java.io.PrintWriter;
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 1569ac3..44e5314 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -30,6 +30,7 @@
import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
+import android.content.pm.ShortcutServiceInternal;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
@@ -44,6 +45,7 @@
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.os.UserManager;
import android.provider.Settings;
import android.service.voice.IVoiceInteractionService;
import android.service.voice.IVoiceInteractionSession;
@@ -53,6 +55,7 @@
import android.service.voice.VoiceInteractionSession;
import android.speech.RecognitionService;
import android.text.TextUtils;
+import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
@@ -63,6 +66,7 @@
import com.android.internal.content.PackageMonitor;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.DumpUtils;
+import com.android.internal.util.Preconditions;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.UiThread;
@@ -84,7 +88,9 @@
final ContentResolver mResolver;
final DatabaseHelper mDbHelper;
final ActivityManagerInternal mAmInternal;
- final TreeSet<Integer> mLoadedKeyphraseIds;
+ final UserManager mUserManager;
+ final ArraySet<Integer> mLoadedKeyphraseIds = new ArraySet<>();
+ ShortcutServiceInternal mShortcutServiceInternal;
SoundTriggerInternal mSoundTriggerInternal;
private final RemoteCallbackList<IVoiceInteractionSessionListener>
@@ -96,8 +102,10 @@
mResolver = context.getContentResolver();
mDbHelper = new DatabaseHelper(context);
mServiceStub = new VoiceInteractionManagerServiceStub();
- mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
- mLoadedKeyphraseIds = new TreeSet<Integer>();
+ mAmInternal = Preconditions.checkNotNull(
+ LocalServices.getService(ActivityManagerInternal.class));
+ mUserManager = Preconditions.checkNotNull(
+ context.getSystemService(UserManager.class));
PackageManagerInternal packageManagerInternal = LocalServices.getService(
PackageManagerInternal.class);
@@ -124,6 +132,8 @@
@Override
public void onBootPhase(int phase) {
if (PHASE_SYSTEM_SERVICES_READY == phase) {
+ mShortcutServiceInternal = Preconditions.checkNotNull(
+ LocalServices.getService(ShortcutServiceInternal.class));
mSoundTriggerInternal = LocalServices.getService(SoundTriggerInternal.class);
} else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
mServiceStub.systemRunning(isSafeMode());
@@ -180,6 +190,7 @@
private boolean mSafeMode;
private int mCurUser;
+ private boolean mCurUserUnlocked;
private final boolean mEnableService;
VoiceInteractionManagerServiceStub() {
@@ -381,6 +392,7 @@
public void switchUser(int userHandle) {
synchronized (this) {
mCurUser = userHandle;
+ mCurUserUnlocked = false;
switchImplementationIfNeededLocked(false);
}
}
@@ -409,13 +421,24 @@
}
}
+ final boolean hasComponent = serviceComponent != null && serviceInfo != null;
+
+ if (mUserManager.isUserUnlockingOrUnlocked(mCurUser)) {
+ if (hasComponent) {
+ mShortcutServiceInternal.setShortcutHostPackage(TAG,
+ serviceComponent.getPackageName(), mCurUser);
+ } else {
+ mShortcutServiceInternal.setShortcutHostPackage(TAG, null, mCurUser);
+ }
+ }
+
if (force || mImpl == null || mImpl.mUser != mCurUser
|| !mImpl.mComponent.equals(serviceComponent)) {
unloadAllKeyphraseModels();
if (mImpl != null) {
mImpl.shutdownLocked();
}
- if (serviceComponent != null && serviceInfo != null) {
+ if (hasComponent) {
mImpl = new VoiceInteractionManagerServiceImpl(mContext,
UiThread.getHandler(), this, mCurUser, serviceComponent);
mImpl.startLocked();
@@ -953,12 +976,14 @@
}
private synchronized void unloadAllKeyphraseModels() {
- for (int keyphraseId : mLoadedKeyphraseIds) {
+ for (int i = 0; i < mLoadedKeyphraseIds.size(); i++) {
final long caller = Binder.clearCallingIdentity();
try {
- int status = mSoundTriggerInternal.unloadKeyphraseModel(keyphraseId);
+ int status = mSoundTriggerInternal.unloadKeyphraseModel(
+ mLoadedKeyphraseIds.valueAt(i));
if (status != SoundTriggerInternal.STATUS_OK) {
- Slog.w(TAG, "Failed to unload keyphrase " + keyphraseId + ":" + status);
+ Slog.w(TAG, "Failed to unload keyphrase " + mLoadedKeyphraseIds.valueAt(i)
+ + ":" + status);
}
} finally {
Binder.restoreCallingIdentity(caller);
diff --git a/tools/aapt2/Android.mk b/tools/aapt2/Android.mk
new file mode 100644
index 0000000..e0c9d1c
--- /dev/null
+++ b/tools/aapt2/Android.mk
@@ -0,0 +1,7 @@
+include $(CLEAR_VARS)
+
+.PHONY: aapt2_run_host_unit_tests
+aapt2_run_host_unit_tests: PRIVATE_GTEST_OPTIONS := --gtest_output=xml:$(DIST_DIR)/gtest/aapt2_host_unit_tests_result.xml
+aapt2_run_host_unit_tests: $(HOST_OUT_NATIVE_TESTS)/aapt2_tests/aapt2_tests
+ -$(HOST_OUT_NATIVE_TESTS)/aapt2_tests/aapt2_tests $(PRIVATE_GTEST_OPTIONS) > /dev/null 2>&1
+
diff --git a/tools/aapt2/configuration/ConfigurationParser_test.cpp b/tools/aapt2/configuration/ConfigurationParser_test.cpp
index 3654901..afa155f 100644
--- a/tools/aapt2/configuration/ConfigurationParser_test.cpp
+++ b/tools/aapt2/configuration/ConfigurationParser_test.cpp
@@ -423,11 +423,11 @@
TEST_F(ConfigurationParserTest, AndroidSdkGroupAction_NonNumeric) {
static constexpr const char* xml = R"xml(
- <android-sdk-group label="O">
+ <android-sdk-group label="P">
<android-sdk
minSdkVersion="M"
- targetSdkVersion="O"
- maxSdkVersion="O">
+ targetSdkVersion="P"
+ maxSdkVersion="P">
</android-sdk>
</android-sdk-group>)xml";
@@ -438,14 +438,14 @@
ASSERT_TRUE(ok);
ASSERT_EQ(1ul, config.android_sdk_groups.size());
- ASSERT_EQ(1u, config.android_sdk_groups.count("O"));
+ ASSERT_EQ(1u, config.android_sdk_groups.count("P"));
- auto& out = config.android_sdk_groups["O"];
+ auto& out = config.android_sdk_groups["P"];
AndroidSdk sdk;
sdk.min_sdk_version = {}; // Only the latest development version is supported.
- sdk.target_sdk_version = 26;
- sdk.max_sdk_version = 26;
+ sdk.target_sdk_version = 28;
+ sdk.max_sdk_version = 28;
ASSERT_EQ(sdk, out);
}
diff --git a/tools/aapt2/xml/XmlActionExecutor.cpp b/tools/aapt2/xml/XmlActionExecutor.cpp
index cc664a5..602a902 100644
--- a/tools/aapt2/xml/XmlActionExecutor.cpp
+++ b/tools/aapt2/xml/XmlActionExecutor.cpp
@@ -16,6 +16,8 @@
#include "xml/XmlActionExecutor.h"
+using ::android::StringPiece;
+
namespace aapt {
namespace xml {
@@ -46,8 +48,8 @@
*msg << el->name << ">";
}
-bool XmlNodeAction::Execute(XmlActionExecutorPolicy policy, SourcePathDiagnostics* diag,
- Element* el) const {
+bool XmlNodeAction::Execute(XmlActionExecutorPolicy policy, std::vector<StringPiece>* bread_crumb,
+ SourcePathDiagnostics* diag, Element* el) const {
bool error = false;
for (const ActionFuncWithDiag& action : actions_) {
error |= !action(el, diag);
@@ -57,15 +59,21 @@
if (child_el->namespace_uri.empty()) {
std::map<std::string, XmlNodeAction>::const_iterator iter = map_.find(child_el->name);
if (iter != map_.end()) {
- error |= !iter->second.Execute(policy, diag, child_el);
+ // Use the iterator's copy of the element name, because the element may be modified.
+ bread_crumb->push_back(iter->first);
+ error |= !iter->second.Execute(policy, bread_crumb, diag, child_el);
+ bread_crumb->pop_back();
continue;
}
if (policy == XmlActionExecutorPolicy::kWhitelist) {
DiagMessage error_msg(child_el->line_number);
- error_msg << "unknown element ";
+ error_msg << "unexpected element ";
PrintElementToDiagMessage(child_el, &error_msg);
- error_msg << " found";
+ error_msg << " found in ";
+ for (const StringPiece& element : *bread_crumb) {
+ error_msg << "<" << element << ">";
+ }
diag->Error(error_msg);
error = true;
}
@@ -90,14 +98,15 @@
if (el->namespace_uri.empty()) {
std::map<std::string, XmlNodeAction>::const_iterator iter = map_.find(el->name);
if (iter != map_.end()) {
- return iter->second.Execute(policy, &source_diag, el);
+ std::vector<StringPiece> bread_crumb;
+ bread_crumb.push_back(iter->first);
+ return iter->second.Execute(policy, &bread_crumb, &source_diag, el);
}
if (policy == XmlActionExecutorPolicy::kWhitelist) {
DiagMessage error_msg(el->line_number);
- error_msg << "unknown element ";
+ error_msg << "unexpected root element ";
PrintElementToDiagMessage(el, &error_msg);
- error_msg << " found";
source_diag.Error(error_msg);
return false;
}
diff --git a/tools/aapt2/xml/XmlActionExecutor.h b/tools/aapt2/xml/XmlActionExecutor.h
index 1d70045..df70100 100644
--- a/tools/aapt2/xml/XmlActionExecutor.h
+++ b/tools/aapt2/xml/XmlActionExecutor.h
@@ -40,56 +40,46 @@
kWhitelist,
};
-/**
- * Contains the actions to perform at this XML node. This is a recursive data
- * structure that
- * holds XmlNodeActions for child XML nodes.
- */
+// Contains the actions to perform at this XML node. This is a recursive data structure that
+// holds XmlNodeActions for child XML nodes.
class XmlNodeAction {
public:
using ActionFuncWithDiag = std::function<bool(Element*, SourcePathDiagnostics*)>;
using ActionFunc = std::function<bool(Element*)>;
- /**
- * Find or create a child XmlNodeAction that will be performed for the child
- * element with the name `name`.
- */
- XmlNodeAction& operator[](const std::string& name) { return map_[name]; }
+ // Find or create a child XmlNodeAction that will be performed for the child element with the
+ // name `name`.
+ XmlNodeAction& operator[](const std::string& name) {
+ return map_[name];
+ }
- /**
- * Add an action to be performed at this XmlNodeAction.
- */
+ // Add an action to be performed at this XmlNodeAction.
void Action(ActionFunc f);
void Action(ActionFuncWithDiag);
private:
friend class XmlActionExecutor;
- bool Execute(XmlActionExecutorPolicy policy, SourcePathDiagnostics* diag, Element* el) const;
+ bool Execute(XmlActionExecutorPolicy policy, std::vector<::android::StringPiece>* bread_crumb,
+ SourcePathDiagnostics* diag, Element* el) const;
std::map<std::string, XmlNodeAction> map_;
std::vector<ActionFuncWithDiag> actions_;
};
-/**
- * Allows the definition of actions to execute at specific XML elements defined
- * by their
- * hierarchy.
- */
+// Allows the definition of actions to execute at specific XML elements defined by their hierarchy.
class XmlActionExecutor {
public:
XmlActionExecutor() = default;
- /**
- * Find or create a root XmlNodeAction that will be performed for the root XML
- * element with the name `name`.
- */
- XmlNodeAction& operator[](const std::string& name) { return map_[name]; }
+ // Find or create a root XmlNodeAction that will be performed for the root XML element with the
+ // name `name`.
+ XmlNodeAction& operator[](const std::string& name) {
+ return map_[name];
+ }
- /**
- * Execute the defined actions for this XmlResource.
- * Returns true if all actions return true, otherwise returns false.
- */
+ // Execute the defined actions for this XmlResource.
+ // Returns true if all actions return true, otherwise returns false.
bool Execute(XmlActionExecutorPolicy policy, IDiagnostics* diag, XmlResource* doc) const;
private:
diff --git a/tools/aapt2/xml/XmlActionExecutor_test.cpp b/tools/aapt2/xml/XmlActionExecutor_test.cpp
index 0fe7ab0..d39854e 100644
--- a/tools/aapt2/xml/XmlActionExecutor_test.cpp
+++ b/tools/aapt2/xml/XmlActionExecutor_test.cpp
@@ -56,9 +56,13 @@
XmlActionExecutor executor;
executor["manifest"]["application"];
- std::unique_ptr<XmlResource> doc =
- test::BuildXmlDom("<manifest><application /><activity /></manifest>");
+ std::unique_ptr<XmlResource> doc;
StdErrDiagnostics diag;
+
+ doc = test::BuildXmlDom("<manifest><application /><activity /></manifest>");
+ ASSERT_FALSE(executor.Execute(XmlActionExecutorPolicy::kWhitelist, &diag, doc.get()));
+
+ doc = test::BuildXmlDom("<manifest><application><activity /></application></manifest>");
ASSERT_FALSE(executor.Execute(XmlActionExecutorPolicy::kWhitelist, &diag, doc.get()));
}