Merge "Renamed BIND_DATA_SERVICE to BIND_TELEPHONY_DATA_SERVICE"
diff --git a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
index bab2a85..231aaf2 100644
--- a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
@@ -232,7 +232,7 @@
while (state.keepRunning()) {
state.pauseTiming();
final MeasuredText text = new MeasuredText.Builder(
- mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT)
+ mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT), PAINT)
.setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
.build();
diff --git a/api/current.txt b/api/current.txt
index 50579a4..c3e1ba0 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -11616,15 +11616,15 @@
public final class AssetManager implements java.lang.AutoCloseable {
method public void close();
- method public final java.lang.String[] getLocales();
- method public final java.lang.String[] list(java.lang.String) throws java.io.IOException;
- method public final java.io.InputStream open(java.lang.String) throws java.io.IOException;
- method public final java.io.InputStream open(java.lang.String, int) throws java.io.IOException;
- method public final android.content.res.AssetFileDescriptor openFd(java.lang.String) throws java.io.IOException;
- method public final android.content.res.AssetFileDescriptor openNonAssetFd(java.lang.String) throws java.io.IOException;
- method public final android.content.res.AssetFileDescriptor openNonAssetFd(int, java.lang.String) throws java.io.IOException;
- method public final android.content.res.XmlResourceParser openXmlResourceParser(java.lang.String) throws java.io.IOException;
- method public final android.content.res.XmlResourceParser openXmlResourceParser(int, java.lang.String) throws java.io.IOException;
+ method public java.lang.String[] getLocales();
+ method public java.lang.String[] list(java.lang.String) throws java.io.IOException;
+ method public java.io.InputStream open(java.lang.String) throws java.io.IOException;
+ method public java.io.InputStream open(java.lang.String, int) throws java.io.IOException;
+ method public android.content.res.AssetFileDescriptor openFd(java.lang.String) throws java.io.IOException;
+ method public android.content.res.AssetFileDescriptor openNonAssetFd(java.lang.String) throws java.io.IOException;
+ method public android.content.res.AssetFileDescriptor openNonAssetFd(int, java.lang.String) throws java.io.IOException;
+ method public android.content.res.XmlResourceParser openXmlResourceParser(java.lang.String) throws java.io.IOException;
+ method public android.content.res.XmlResourceParser openXmlResourceParser(int, java.lang.String) throws java.io.IOException;
field public static final int ACCESS_BUFFER = 3; // 0x3
field public static final int ACCESS_RANDOM = 1; // 0x1
field public static final int ACCESS_STREAMING = 2; // 0x2
@@ -16489,8 +16489,37 @@
package android.hardware.fingerprint {
public class FingerprintDialog {
- method public void authenticate(android.hardware.fingerprint.FingerprintManager.CryptoObject, android.os.CancellationSignal, java.util.concurrent.Executor, android.hardware.fingerprint.FingerprintManager.AuthenticationCallback);
- method public void authenticate(android.os.CancellationSignal, java.util.concurrent.Executor, android.hardware.fingerprint.FingerprintManager.AuthenticationCallback);
+ method public void authenticate(android.hardware.fingerprint.FingerprintDialog.CryptoObject, android.os.CancellationSignal, java.util.concurrent.Executor, android.hardware.fingerprint.FingerprintDialog.AuthenticationCallback);
+ method public void authenticate(android.os.CancellationSignal, java.util.concurrent.Executor, android.hardware.fingerprint.FingerprintDialog.AuthenticationCallback);
+ field public static final int FINGERPRINT_ACQUIRED_GOOD = 0; // 0x0
+ field public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 3; // 0x3
+ field public static final int FINGERPRINT_ACQUIRED_INSUFFICIENT = 2; // 0x2
+ field public static final int FINGERPRINT_ACQUIRED_PARTIAL = 1; // 0x1
+ field public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 5; // 0x5
+ field public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 4; // 0x4
+ field public static final int FINGERPRINT_ERROR_CANCELED = 5; // 0x5
+ field public static final int FINGERPRINT_ERROR_HW_NOT_PRESENT = 12; // 0xc
+ field public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1; // 0x1
+ field public static final int FINGERPRINT_ERROR_LOCKOUT = 7; // 0x7
+ field public static final int FINGERPRINT_ERROR_LOCKOUT_PERMANENT = 9; // 0x9
+ field public static final int FINGERPRINT_ERROR_NO_FINGERPRINTS = 11; // 0xb
+ field public static final int FINGERPRINT_ERROR_NO_SPACE = 4; // 0x4
+ field public static final int FINGERPRINT_ERROR_TIMEOUT = 3; // 0x3
+ field public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2; // 0x2
+ field public static final int FINGERPRINT_ERROR_USER_CANCELED = 10; // 0xa
+ field public static final int FINGERPRINT_ERROR_VENDOR = 8; // 0x8
+ }
+
+ public static abstract class FingerprintDialog.AuthenticationCallback {
+ ctor public FingerprintDialog.AuthenticationCallback();
+ method public void onAuthenticationError(int, java.lang.CharSequence);
+ method public void onAuthenticationFailed();
+ method public void onAuthenticationHelp(int, java.lang.CharSequence);
+ method public void onAuthenticationSucceeded(android.hardware.fingerprint.FingerprintDialog.AuthenticationResult);
+ }
+
+ public static class FingerprintDialog.AuthenticationResult {
+ method public android.hardware.fingerprint.FingerprintDialog.CryptoObject getCryptoObject();
}
public static class FingerprintDialog.Builder {
@@ -16502,10 +16531,19 @@
method public android.hardware.fingerprint.FingerprintDialog.Builder setTitle(java.lang.CharSequence);
}
- public class FingerprintManager {
- method public void authenticate(android.hardware.fingerprint.FingerprintManager.CryptoObject, android.os.CancellationSignal, int, android.hardware.fingerprint.FingerprintManager.AuthenticationCallback, android.os.Handler);
- method public boolean hasEnrolledFingerprints();
- method public boolean isHardwareDetected();
+ public static final class FingerprintDialog.CryptoObject {
+ ctor public FingerprintDialog.CryptoObject(java.security.Signature);
+ ctor public FingerprintDialog.CryptoObject(javax.crypto.Cipher);
+ ctor public FingerprintDialog.CryptoObject(javax.crypto.Mac);
+ method public javax.crypto.Cipher getCipher();
+ method public javax.crypto.Mac getMac();
+ method public java.security.Signature getSignature();
+ }
+
+ public deprecated class FingerprintManager {
+ method public deprecated void authenticate(android.hardware.fingerprint.FingerprintManager.CryptoObject, android.os.CancellationSignal, int, android.hardware.fingerprint.FingerprintManager.AuthenticationCallback, android.os.Handler);
+ method public deprecated boolean hasEnrolledFingerprints();
+ method public deprecated boolean isHardwareDetected();
field public static final int FINGERPRINT_ACQUIRED_GOOD = 0; // 0x0
field public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 3; // 0x3
field public static final int FINGERPRINT_ACQUIRED_INSUFFICIENT = 2; // 0x2
@@ -16513,9 +16551,11 @@
field public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 5; // 0x5
field public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 4; // 0x4
field public static final int FINGERPRINT_ERROR_CANCELED = 5; // 0x5
+ field public static final int FINGERPRINT_ERROR_HW_NOT_PRESENT = 12; // 0xc
field public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1; // 0x1
field public static final int FINGERPRINT_ERROR_LOCKOUT = 7; // 0x7
field public static final int FINGERPRINT_ERROR_LOCKOUT_PERMANENT = 9; // 0x9
+ field public static final int FINGERPRINT_ERROR_NO_FINGERPRINTS = 11; // 0xb
field public static final int FINGERPRINT_ERROR_NO_SPACE = 4; // 0x4
field public static final int FINGERPRINT_ERROR_TIMEOUT = 3; // 0x3
field public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2; // 0x2
@@ -24518,7 +24558,7 @@
field public static final int DIRECTIONALITY_HYPER_CARDIOID = 4; // 0x4
field public static final int DIRECTIONALITY_OMNI = 1; // 0x1
field public static final int DIRECTIONALITY_SUPER_CARDIOID = 5; // 0x5
- field public static final int DIRECTIONALITY_UNKNOW = 0; // 0x0
+ field public static final int DIRECTIONALITY_UNKNOWN = 0; // 0x0
field public static final int LOCATION_MAINBODY = 1; // 0x1
field public static final int LOCATION_MAINBODY_MOVABLE = 2; // 0x2
field public static final int LOCATION_PERIPHERAL = 3; // 0x3
@@ -33075,7 +33115,7 @@
field public static final java.lang.String DISALLOW_CONFIG_CREDENTIALS = "no_config_credentials";
field public static final java.lang.String DISALLOW_CONFIG_DATE_TIME = "no_config_date_time";
field public static final java.lang.String DISALLOW_CONFIG_LOCALE = "no_config_locale";
- field public static final java.lang.String DISALLOW_CONFIG_LOCATION_MODE = "no_config_location_mode";
+ field public static final java.lang.String DISALLOW_CONFIG_LOCATION = "no_config_location";
field public static final java.lang.String DISALLOW_CONFIG_MOBILE_NETWORKS = "no_config_mobile_networks";
field public static final java.lang.String DISALLOW_CONFIG_SCREEN_TIMEOUT = "no_config_screen_timeout";
field public static final java.lang.String DISALLOW_CONFIG_TETHERING = "no_config_tethering";
diff --git a/api/system-current.txt b/api/system-current.txt
index 4caa820..e06336b 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -774,6 +774,7 @@
public abstract class Context {
method public boolean bindServiceAsUser(android.content.Intent, android.content.ServiceConnection, int, android.os.UserHandle);
method public abstract android.content.Context createCredentialProtectedStorageContext();
+ method public android.content.Context createPackageContextAsUser(java.lang.String, int, android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract java.io.File getPreloadsFileCache();
method public abstract boolean isCredentialProtectedStorage();
method public abstract void sendBroadcast(android.content.Intent, java.lang.String, android.os.Bundle);
@@ -2022,6 +2023,7 @@
method public int describeContents();
method public android.hardware.radio.RadioManager.BandDescriptor[] getBands();
method public int getClassId();
+ method public java.util.Map<java.lang.String, java.lang.Integer> getDabFrequencyTable();
method public int getId();
method public java.lang.String getImplementor();
method public int getNumAudioSources();
diff --git a/api/test-current.txt b/api/test-current.txt
index 92bf24d..b331ba0 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1056,6 +1056,14 @@
}
+package android.view.inputmethod {
+
+ public final class InputMethodManager {
+ method public boolean isInputMethodPickerShown();
+ }
+
+}
+
package android.widget {
public abstract class AbsListView extends android.widget.AdapterView implements android.widget.Filter.FilterListener android.text.TextWatcher android.view.ViewTreeObserver.OnGlobalLayoutListener android.view.ViewTreeObserver.OnTouchModeChangeListener {
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 4e41454..32da94f 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -34,6 +34,7 @@
#include <private/android_filesystem_config.h>
#include <utils/Looper.h>
#include <utils/String16.h>
+#include <statslog.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/system_properties.h>
@@ -235,6 +236,10 @@
if (!args[0].compare(String8("write-to-disk"))) {
return cmd_write_data_to_disk(out);
}
+
+ if (!args[0].compare(String8("log-app-hook"))) {
+ return cmd_log_app_hook(out, args);
+ }
}
print_cmd_help(out);
@@ -272,6 +277,15 @@
fprintf(out, " Flushes all data on memory to disk.\n");
fprintf(out, "\n");
fprintf(out, "\n");
+ fprintf(out, "usage: adb shell cmd stats log-app-hook [UID] LABEL STATE\n");
+ fprintf(out, " Writes an AppHook event to the statslog buffer.\n");
+ fprintf(out, " UID The uid to use. It is only possible to pass a UID\n");
+ fprintf(out, " parameter on eng builds. If UID is omitted the calling\n");
+ fprintf(out, " uid is used.\n");
+ fprintf(out, " LABEL Integer in [0, 15], as per atoms.proto.\n");
+ fprintf(out, " STATE Integer in [0, 3], as per atoms.proto.\n");
+ fprintf(out, "\n");
+ fprintf(out, "\n");
fprintf(out, "usage: adb shell cmd stats config remove [UID] [NAME]\n");
fprintf(out, "usage: adb shell cmd stats config update [UID] NAME\n");
fprintf(out, "\n");
@@ -523,6 +537,42 @@
return NO_ERROR;
}
+status_t StatsService::cmd_log_app_hook(FILE* out, const Vector<String8>& args) {
+ bool good = false;
+ int32_t uid;
+ int32_t label;
+ int32_t state;
+ const int argCount = args.size();
+ if (argCount == 3) {
+ // Automatically pick the UID
+ uid = IPCThreadState::self()->getCallingUid();
+ label = atoi(args[1].c_str());
+ state = atoi(args[2].c_str());
+ good = true;
+ } else if (argCount == 4) {
+ uid = atoi(args[1].c_str());
+ // If it's a userdebug or eng build, then the shell user can impersonate other uids.
+ // Otherwise, the uid must match the actual caller's uid.
+ if (mEngBuild || (uid >= 0 && (uid_t)uid == IPCThreadState::self()->getCallingUid())) {
+ label = atoi(args[2].c_str());
+ state = atoi(args[3].c_str());
+ good = true;
+ } else {
+ fprintf(out,
+ "Selecting a UID for writing AppHook can only be dumped for other UIDs on eng"
+ " or userdebug builds.\n");
+ }
+ }
+ if (good) {
+ fprintf(out, "Logging AppHook(%d, %d, %d) to statslog.\n", uid, label, state);
+ android::util::stats_write(android::util::APP_HOOK, uid, label, state);
+ } else {
+ print_cmd_help(out);
+ return UNKNOWN_ERROR;
+ }
+ return NO_ERROR;
+}
+
status_t StatsService::cmd_print_pulled_metrics(FILE* out, const Vector<String8>& args) {
int s = atoi(args[1].c_str());
vector<shared_ptr<LogEvent> > stats;
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index fd3ed1d..109752b 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -183,6 +183,11 @@
status_t cmd_write_data_to_disk(FILE* out);
/**
+ * Write an AppHook event to the StatsLog buffer, as though StatsLog.write(APP_HOOK).
+ */
+ status_t cmd_log_app_hook(FILE* out, const Vector<String8>& args);
+
+ /**
* Print contents of a pulled metrics source.
*/
status_t cmd_print_pulled_metrics(FILE* out, const Vector<String8>& args);
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index b156d8d..ed570e7 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -95,6 +95,8 @@
AppStartMemoryStateCaptured app_start_memory_state_captured = 55;
ShutdownSequenceReported shutdown_sequence_reported = 56;
BootSequenceReported boot_sequence_reported = 57;
+ DaveyOccurred davey_occurred = 58;
+ OverlayStateChanged overlay_state_changed = 59;
// TODO: Reorder the numbering so that the most frequent occur events occur in the first 15.
}
@@ -723,6 +725,17 @@
}
/**
+ * Logs the duration of a davey (jank of >=700ms) when it occurs
+ *
+ * Logged from:
+ * frameworks/base/libs/hwui/JankTracker.cpp
+ */
+message DaveyOccurred {
+ // Amount of time it took to render the frame. Should be >=700ms.
+ optional int64 jank_duration_ms = 1;
+}
+
+/**
* Logs phone signal strength changes.
*
* Logged from:
@@ -967,6 +980,25 @@
}
/**
+ * Logs overlay action
+ * Logged from:
+ * services/core/java/com/android/server/wm/Session.java
+ */
+message OverlayStateChanged {
+ optional int32 uid = 1;
+
+ optional string package_name = 2;
+
+ optional bool using_alert_window = 3;
+
+ enum State {
+ ENTERED = 1;
+ EXITED = 2;
+ }
+ optional State state = 4;
+}
+
+/**
* Pulls bytes transferred via wifi (Sum of foreground and background usage).
*
* Pulled from:
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 9e72f5b..1dcd853 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -62,13 +62,14 @@
const char* buffer;
size_t len = android_log_write_list_buffer(mContext, &buffer);
// turns to reader mode
- mContext = create_android_log_parser(buffer, len);
- init(mContext);
- // destroy the context to save memory.
- if (mContext) {
+ android_log_context contextForRead = create_android_log_parser(buffer, len);
+ if (contextForRead) {
+ init(contextForRead);
+ // destroy the context to save memory.
// android_log_destroy will set mContext to NULL
- android_log_destroy(&mContext);
+ android_log_destroy(&contextForRead);
}
+ android_log_destroy(&mContext);
}
}
@@ -188,6 +189,9 @@
* of the elements that are written to the log.
*/
void LogEvent::init(android_log_context context) {
+ if (!context) {
+ return;
+ }
android_log_list_element elem;
// TODO: The log is actually structured inside one list. This is convenient
// because we'll be able to use it to put the attribution (WorkSource) block first
diff --git a/cmds/statsd/src/matchers/matcher_util.cpp b/cmds/statsd/src/matchers/matcher_util.cpp
index b6f440f..fae9172 100644
--- a/cmds/statsd/src/matchers/matcher_util.cpp
+++ b/cmds/statsd/src/matchers/matcher_util.cpp
@@ -129,43 +129,60 @@
}
bool matched = false;
switch (matcher.value_matcher_case()) {
- case FieldValueMatcher::ValueMatcherCase::kEqBool:
- // Logd does not support bool, it is int instead.
- matched = ((ret.first->second.value_int() > 0) == matcher.eq_bool());
- break;
- case FieldValueMatcher::ValueMatcherCase::kEqString:
- {
- if (IsAttributionUidField(*rootField)) {
- const int uid = ret.first->second.value_int();
- std::set<string> packageNames =
+ case FieldValueMatcher::ValueMatcherCase::kEqBool: {
+ // Logd does not support bool, it is int instead.
+ matched = ((ret.first->second.value_int() > 0) == matcher.eq_bool());
+ break;
+ }
+ case FieldValueMatcher::ValueMatcherCase::kEqString: {
+ if (IsAttributionUidField(*rootField)) {
+ const int uid = ret.first->second.value_int();
+ std::set<string> packageNames =
uidMap.getAppNamesFromUid(uid, true /* normalize*/);
- matched = packageNames.find(matcher.eq_string()) != packageNames.end();
- } else {
- matched = (ret.first->second.value_str() == matcher.eq_string());
- }
- }
- break;
- case FieldValueMatcher::ValueMatcherCase::kEqInt:
- matched = (ret.first->second.value_int() == matcher.eq_int());
- break;
- case FieldValueMatcher::ValueMatcherCase::kLtInt:
- matched = (ret.first->second.value_int() < matcher.lt_int());
- break;
- case FieldValueMatcher::ValueMatcherCase::kGtInt:
- matched = (ret.first->second.value_int() > matcher.gt_int());
- break;
- case FieldValueMatcher::ValueMatcherCase::kLtFloat:
- matched = (ret.first->second.value_float() < matcher.lt_float());
- break;
- case FieldValueMatcher::ValueMatcherCase::kGtFloat:
- matched = (ret.first->second.value_float() > matcher.gt_float());
- break;
- case FieldValueMatcher::ValueMatcherCase::kLteInt:
- matched = (ret.first->second.value_int() <= matcher.lte_int());
- break;
- case FieldValueMatcher::ValueMatcherCase::kGteInt:
- matched = (ret.first->second.value_int() >= matcher.gte_int());
- break;
+ matched = packageNames.find(matcher.eq_string()) != packageNames.end();
+ } else {
+ matched = (ret.first->second.value_str() == matcher.eq_string());
+ }
+ break;
+ }
+ case FieldValueMatcher::ValueMatcherCase::kEqInt: {
+ int64_t val = ret.first->second.has_value_int() ?
+ ret.first->second.value_int() : ret.first->second.value_long();
+ matched = (val == matcher.eq_int());
+ break;
+ }
+ case FieldValueMatcher::ValueMatcherCase::kLtInt: {
+ int64_t val = ret.first->second.has_value_int() ?
+ ret.first->second.value_int() : ret.first->second.value_long();
+ matched = (val < matcher.lt_int());
+ break;
+ }
+ case FieldValueMatcher::ValueMatcherCase::kGtInt: {
+ int64_t val = ret.first->second.has_value_int() ?
+ ret.first->second.value_int() : ret.first->second.value_long();
+ matched = (val > matcher.gt_int());
+ break;
+ }
+ case FieldValueMatcher::ValueMatcherCase::kLtFloat: {
+ matched = (ret.first->second.value_float() < matcher.lt_float());
+ break;
+ }
+ case FieldValueMatcher::ValueMatcherCase::kGtFloat: {
+ matched = (ret.first->second.value_float() > matcher.gt_float());
+ break;
+ }
+ case FieldValueMatcher::ValueMatcherCase::kLteInt: {
+ int64_t val = ret.first->second.has_value_int() ?
+ ret.first->second.value_int() : ret.first->second.value_long();
+ matched = (val <= matcher.lte_int());
+ break;
+ }
+ case FieldValueMatcher::ValueMatcherCase::kGteInt: {
+ int64_t val = ret.first->second.has_value_int() ?
+ ret.first->second.value_int() : ret.first->second.value_long();
+ matched = (val >= matcher.gte_int());
+ break;
+ }
default:
break;
}
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index d0737de..417145c 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -47,7 +47,7 @@
MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config,
const long timeBaseSec, sp<UidMap> uidMap)
- : mConfigKey(key), mUidMap(uidMap) {
+ : mConfigKey(key), mUidMap(uidMap), mStatsdUid(getStatsdUid()) {
mConfigValid =
initStatsdConfig(key, config, *uidMap, timeBaseSec, mTagIds, mAllAtomMatchers, mAllConditionTrackers,
mAllMetricProducers, mAllAnomalyTrackers, mConditionToMetricMap,
@@ -61,6 +61,7 @@
mAllowedUid.push_back(1000);
mAllowedUid.push_back(0);
+ mAllowedUid.push_back(mStatsdUid);
mAllowedLogSources.insert(mAllowedUid.begin(), mAllowedUid.end());
} else {
for (const auto& source : config.allowed_log_source()) {
@@ -189,28 +190,47 @@
return;
}
- if (event.GetTagId() != android::util::APP_HOOK) {
+ if (event.GetTagId() == android::util::APP_HOOK) { // Check that app hook fields are valid.
+ // TODO: Find a way to make these checks easier to maintain if the app hooks get changed.
+ status_t err = NO_ERROR;
+
+ // Uid is 3rd from last field and must match the caller's uid,
+ // unless that caller is statsd itself (statsd is allowed to spoof uids).
+ long appHookUid = event.GetLong(event.size()-2, &err);
+ int32_t loggerUid = event.GetUid();
+ if (err != NO_ERROR || (loggerUid != appHookUid && loggerUid != mStatsdUid)) {
+ VLOG("AppHook has invalid uid: claimed %ld but caller is %d", appHookUid, loggerUid);
+ return;
+ }
+
+ // Label is 2nd from last field and must be from [0, 15].
+ long appHookLabel = event.GetLong(event.size()-1, &err);
+ if (err != NO_ERROR || appHookLabel < 0 || appHookLabel > 15) {
+ VLOG("AppHook does not have valid label %ld", appHookLabel);
+ return;
+ }
+
+ // The state must be from 0,3. This part of code must be manually updated.
+ long appHookState = event.GetLong(event.size(), &err);
+ if (err != NO_ERROR || appHookState < 0 || appHookState > 3) {
+ VLOG("AppHook does not have valid state %ld", appHookState);
+ return;
+ }
+ } else if (event.GetTagId() == android::util::DAVEY_OCCURRED) {
+ // Daveys can be logged from any app since they are logged in libs/hwui/JankTracker.cpp.
+ // Check that the davey duration is reasonable. Max length check is for privacy.
+ status_t err = NO_ERROR;
+ long duration = event.GetLong(event.size(), &err);
+ if (err != NO_ERROR || duration > 100000) {
+ VLOG("Davey duration is unreasonably long: %ld", duration);
+ return;
+ }
+ } else {
std::lock_guard<std::mutex> lock(mAllowedLogSourcesMutex);
if (mAllowedLogSources.find(event.GetUid()) == mAllowedLogSources.end()) {
VLOG("log source %d not on the whitelist", event.GetUid());
return;
}
- } else { // Check that app hook fields are valid.
- // TODO: Find a way to make these checks easier to maintain if the app hooks get changed.
-
- // Label is 2nd from last field and must be from [0, 15].
- status_t err = NO_ERROR;
- long label = event.GetLong(event.size()-1, &err);
- if (err != NO_ERROR || label < 0 || label > 15) {
- VLOG("App hook does not have valid label %ld", label);
- return;
- }
- // The state must be from 0,3. This part of code must be manually updated.
- long apphookState = event.GetLong(event.size(), &err);
- if (err != NO_ERROR || apphookState < 0 || apphookState > 3) {
- VLOG("App hook does not have valid state %ld", apphookState);
- return;
- }
}
int tagId = event.GetTagId();
@@ -313,6 +333,16 @@
return totalSize;
}
+int32_t MetricsManager::getStatsdUid() {
+ auto suit = UidMap::sAidToUidMapping.find("AID_STATSD");
+ if (suit != UidMap::sAidToUidMapping.end()) {
+ return suit->second;
+ } else {
+ ALOGE("Statsd failed to find its own uid!");
+ return -1;
+ }
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index d4b9102..a1220f9 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -75,6 +75,9 @@
sp<UidMap> mUidMap;
+ // The uid of statsd.
+ const int32_t mStatsdUid;
+
bool mConfigValid = false;
// The uid log sources from StatsdConfig.
@@ -136,6 +139,9 @@
void initLogSourceWhiteList();
+ // Fetches the uid of statsd from UidMap.
+ static int32_t getStatsdUid();
+
// The metrics that don't need to be uploaded or even reported.
std::set<int64_t> mNoReportMetricIds;
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index 2ea79a6..3eaf7a1 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -64,7 +64,7 @@
oneof value_matcher {
bool eq_bool = 3;
string eq_string = 4;
- int32 eq_int = 5;
+ int64 eq_int = 5;
int64 lt_int = 6;
int64 gt_int = 7;
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 05e51a4..58936fc 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -15,6 +15,7 @@
Landroid/app/ActivityManager;->mContext:Landroid/content/Context;
Landroid/app/ActivityManagerNative;->getDefault()Landroid/app/IActivityManager;
Landroid/app/ActivityManager;->PROCESS_STATE_TOP:I
+Landroid/app/ActivityManager$RecentTaskInfo;->firstActiveTime:J
Landroid/app/ActivityManager$RunningAppProcessInfo;->flags:I
Landroid/app/ActivityManager$RunningAppProcessInfo;->processState:I
Landroid/app/Activity;->mApplication:Landroid/app/Application;
@@ -24,6 +25,7 @@
Landroid/app/Activity;->mToken:Landroid/os/IBinder;
Landroid/app/Activity;->mWindow:Landroid/view/Window;
Landroid/app/Activity;->mWindowManager:Landroid/view/WindowManager;
+Landroid/app/Activity;->setDisablePreviewScreenshots(Z)V
Landroid/app/ActivityThread$ActivityClientRecord;->activityInfo:Landroid/content/pm/ActivityInfo;
Landroid/app/ActivityThread$ActivityClientRecord;->token:Landroid/os/IBinder;
Landroid/app/ActivityThread$AppBindData;->info:Landroid/app/LoadedApk;
@@ -31,6 +33,7 @@
Landroid/app/ActivityThread;->currentActivityThread()Landroid/app/ActivityThread;
Landroid/app/ActivityThread;->currentApplication()Landroid/app/Application;
Landroid/app/ActivityThread;->currentPackageName()Ljava/lang/String;
+Landroid/app/ActivityThread;->currentProcessName()Ljava/lang/String;
Landroid/app/ActivityThread;->getApplication()Landroid/app/Application;
Landroid/app/ActivityThread;->getApplicationThread()Landroid/app/ActivityThread$ApplicationThread;
Landroid/app/ActivityThread;->getHandler()Landroid/os/Handler;
@@ -71,6 +74,9 @@
Landroid/app/ApplicationLoaders;->mLoaders:Landroid/util/ArrayMap;
Landroid/app/Application;->mComponentCallbacks:Ljava/util/ArrayList;
Landroid/app/Application;->mLoadedApk:Landroid/app/LoadedApk;
+Landroid/app/ApplicationPackageManager;->deletePackage(Ljava/lang/String;Landroid/content/pm/IPackageDeleteObserver;I)V
+Landroid/app/ApplicationPackageManager;->installExistingPackage(Ljava/lang/String;)I
+Landroid/app/ApplicationPackageManager;->installExistingPackage(Ljava/lang/String;I)I
Landroid/app/AppOpsManager;->checkOp(IILjava/lang/String;)I
Landroid/app/AppOpsManager;->checkOpNoThrow(IILjava/lang/String;)I
Landroid/app/AppOpsManager;->noteOp(I)I
@@ -182,18 +188,24 @@
Landroid/content/Intent;->putExtra(Ljava/lang/String;Landroid/os/IBinder;)Landroid/content/Intent;
Landroid/content/pm/ApplicationInfo;->installLocation:I
Landroid/content/pm/ApplicationInfo;->isForwardLocked()Z
+Landroid/content/pm/ApplicationInfo;->isInstantApp()Z
Landroid/content/pm/ApplicationInfo;->isPrivilegedApp()Z
Landroid/content/pm/ApplicationInfo;->primaryCpuAbi:Ljava/lang/String;
Landroid/content/pm/ApplicationInfo;->privateFlags:I
+Landroid/content/pm/ApplicationInfo;->targetSandboxVersion:I
Landroid/content/pm/IPackageManager;->getLastChosenActivity(Landroid/content/Intent;Ljava/lang/String;I)Landroid/content/pm/ResolveInfo;
Landroid/content/pm/IPackageManager;->setLastChosenActivity(Landroid/content/Intent;Ljava/lang/String;ILandroid/content/IntentFilter;ILandroid/content/ComponentName;)V
Landroid/content/pm/LauncherApps;->mPm:Landroid/content/pm/PackageManager;
Landroid/content/pm/LauncherApps;->startShortcut(Ljava/lang/String;Ljava/lang/String;Landroid/graphics/Rect;Landroid/os/Bundle;I)V
+Landroid/content/pm/PackageInstaller$SessionParams;->setGrantedRuntimePermissions([Ljava/lang/String;)V
+Landroid/content/pm/PackageInstaller$SessionParams;->setInstallAsInstantApp(Z)V
Landroid/content/pm/PackageManager;->freeStorageAndNotify(JLandroid/content/pm/IPackageDataObserver;)V
Landroid/content/pm/PackageManager;->freeStorageAndNotify(Ljava/lang/String;JLandroid/content/pm/IPackageDataObserver;)V
Landroid/content/pm/PackageManager;->freeStorage(JLandroid/content/IntentSender;)V
Landroid/content/pm/PackageManager;->freeStorage(Ljava/lang/String;JLandroid/content/IntentSender;)V
+Landroid/content/pm/PackageManager;->getApplicationInfoAsUser(Ljava/lang/String;II)Landroid/content/pm/ApplicationInfo;
Landroid/content/pm/PackageManager;->getPackageCandidateVolumes(Landroid/content/pm/ApplicationInfo;)Ljava/util/List;
+Landroid/content/pm/PackageManager;->getPackageInfoAsUser(Ljava/lang/String;II)Landroid/content/pm/PackageInfo;
Landroid/content/pm/PackageManager;->getPackageSizeInfo(Ljava/lang/String;Landroid/content/pm/IPackageStatsObserver;)V
Landroid/content/pm/PackageManager;->getResourcesForApplicationAsUser(Ljava/lang/String;I)Landroid/content/res/Resources;
Landroid/content/pm/PackageManager;->movePackage(Ljava/lang/String;Landroid/os/storage/VolumeInfo;)I
@@ -217,6 +229,7 @@
Landroid/content/res/AssetManager;->loadResourceBagValue(IILandroid/util/TypedValue;Z)I
Landroid/content/res/AssetManager;->loadResourceValue(ISLandroid/util/TypedValue;Z)I
Landroid/content/res/AssetManager;->loadThemeAttributeValue(JILandroid/util/TypedValue;Z)I
+Landroid/content/res/AssetManager;->mObject:J
Landroid/content/res/AssetManager;->openNonAssetFdNative(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;
Landroid/content/res/AssetManager;->openNonAsset(ILjava/lang/String;I)Ljava/io/InputStream;
Landroid/content/res/AssetManager;->openNonAsset(ILjava/lang/String;)Ljava/io/InputStream;
@@ -276,6 +289,7 @@
Landroid/graphics/drawable/BitmapDrawable;->getTintMode()Landroid/graphics/PorterDuff$Mode;
Landroid/graphics/drawable/BitmapDrawable;->setBitmap(Landroid/graphics/Bitmap;)V
Landroid/graphics/drawable/DrawableContainer$DrawableContainerState;->mConstantPadding:Landroid/graphics/Rect;
+Landroid/graphics/drawable/DrawableContainer;->getOpticalInsets()Landroid/graphics/Insets;
Landroid/graphics/drawable/DrawableContainer;->mDrawableContainerState:Landroid/graphics/drawable/DrawableContainer$DrawableContainerState;
Landroid/graphics/drawable/Drawable;->inflateWithAttributes(Landroid/content/res/Resources;Lorg/xmlpull/v1/XmlPullParser;Landroid/content/res/TypedArray;I)V
Landroid/graphics/drawable/Drawable;->mCallback:Ljava/lang/ref/WeakReference;
@@ -358,9 +372,25 @@
Landroid/net/ConnectivityManager;->mService:Landroid/net/IConnectivityManager;
Landroid/net/ConnectivityManager;->requestRouteToHostAddress(ILjava/net/InetAddress;)Z
Landroid/net/ConnectivityManager;->requestRouteToHost(II)Z
+Landroid/net/INetworkStatsService$Stub$Proxy;->getMobileIfaces()[Ljava/lang/String;
Landroid/net/LinkProperties;->setHttpProxy(Landroid/net/ProxyInfo;)V
Landroid/net/NetworkPolicyManager;->mService:Landroid/net/INetworkPolicyManager;
+Landroid/net/NetworkStats;->capacity:I
+Landroid/net/NetworkStats;->defaultNetwork:[I
+Landroid/net/NetworkStats;->iface:[Ljava/lang/String;
+Landroid/net/NetworkStats;->metered:[I
+Landroid/net/NetworkStats;->operations:[J
+Landroid/net/NetworkStats;->roaming:[I
+Landroid/net/NetworkStats;->rxBytes:[J
+Landroid/net/NetworkStats;->rxPackets:[J
+Landroid/net/NetworkStats;->set:[I
+Landroid/net/NetworkStats;->size:I
+Landroid/net/NetworkStats;->tag:[I
+Landroid/net/NetworkStats;->txBytes:[J
+Landroid/net/NetworkStats;->txPackets:[J
+Landroid/net/NetworkStats;->uid:[I
Landroid/net/SSLCertificateSocketFactory;->getHttpSocketFactory(ILandroid/net/SSLSessionCache;)Lorg/apache/http/conn/ssl/SSLSocketFactory;
+Landroid/net/TrafficStats;->getStatsService()Landroid/net/INetworkStatsService;
Landroid/net/wifi/p2p/WifiP2pGroup;->getNetworkId()I
Landroid/net/wifi/p2p/WifiP2pGroupList;->getGroupList()Ljava/util/Collection;
Landroid/net/wifi/p2p/WifiP2pManager;->deletePersistentGroup(Landroid/net/wifi/p2p/WifiP2pManager$Channel;ILandroid/net/wifi/p2p/WifiP2pManager$ActionListener;)V
@@ -534,7 +564,9 @@
Landroid/os/UserManager;->getUserHandle(I)I
Landroid/os/UserManager;->getUserInfo(I)Landroid/content/pm/UserInfo;
Landroid/os/UserManager;->getUserSerialNumber(I)I
+Landroid/os/UserManager;->getUsers()Ljava/util/List;
Landroid/os/UserManager;->hasBaseUserRestriction(Ljava/lang/String;Landroid/os/UserHandle;)Z
+Landroid/os/UserManager;->isLinkedUser()Z
Landroid/os/UserManager;->isUserUnlocked(I)Z
Landroid/os/WorkSource;->add(ILjava/lang/String;)Z
Landroid/os/WorkSource;->add(I)Z
@@ -627,6 +659,7 @@
Landroid/telephony/SubscriptionManager;->getPhoneId(I)I
Landroid/telephony/SubscriptionManager;->getSubId(I)[I
Landroid/telephony/SubscriptionManager;->setDefaultSmsSubId(I)V
+Landroid/telephony/TelephonyManager;->checkCarrierPrivilegesForPackage(Ljava/lang/String;)I
Landroid/telephony/TelephonyManager;->from(Landroid/content/Context;)Landroid/telephony/TelephonyManager;
Landroid/telephony/TelephonyManager;->getCurrentPhoneType()I
Landroid/telephony/TelephonyManager;->getCurrentPhoneType(I)I
@@ -636,10 +669,12 @@
Landroid/telephony/TelephonyManager;->getITelephony()Lcom/android/internal/telephony/ITelephony;
Landroid/telephony/TelephonyManager;->getLine1Number(I)Ljava/lang/String;
Landroid/telephony/TelephonyManager;->getNetworkClass(I)I
+Landroid/telephony/TelephonyManager;->getNetworkCountryIso(I)Ljava/lang/String;
Landroid/telephony/TelephonyManager;->getNetworkOperator(I)Ljava/lang/String;
Landroid/telephony/TelephonyManager;->getNetworkOperatorName(I)Ljava/lang/String;
Landroid/telephony/TelephonyManager;->getNetworkType(I)I
Landroid/telephony/TelephonyManager;->getSimOperator(I)Ljava/lang/String;
+Landroid/telephony/TelephonyManager;->getSimOperatorName(I)Ljava/lang/String;
Landroid/telephony/TelephonyManager;->getSimSerialNumber(I)Ljava/lang/String;
Landroid/telephony/TelephonyManager;->getSubscriberId(I)Ljava/lang/String;
Landroid/telephony/TelephonyManager;->isMultiSimEnabled()Z
@@ -711,6 +746,14 @@
Landroid/view/SurfaceView;->mFormat:I
Landroid/view/SurfaceView;->mRequestedFormat:I
Landroid/view/SurfaceView;->mSurfaceHolder:Landroid/view/SurfaceHolder;
+Landroid/view/textclassifier/logging/SmartSelectionEventTracker;-><init>(Landroid/content/Context;I)V
+Landroid/view/textclassifier/logging/SmartSelectionEventTracker;->logEvent(Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;)V
+Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;->selectionAction(III)Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;
+Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;->selectionAction(IIILandroid/view/textclassifier/TextClassification;)Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;
+Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;->selectionModified(II)Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;
+Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;->selectionModified(IILandroid/view/textclassifier/TextClassification;)Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;
+Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;->selectionModified(IILandroid/view/textclassifier/TextSelection;)Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;
+Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;->selectionStarted(I)Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;
Landroid/view/textservice/TextServicesManager;->isSpellCheckerEnabled()Z
Landroid/view/TextureView;->mLayer:Landroid/view/HardwareLayer;
Landroid/view/TextureView;->mSurface:Landroid/graphics/SurfaceTexture;
@@ -718,6 +761,7 @@
Landroid/view/TouchDelegate;->mDelegateTargeted:Z
Landroid/view/VelocityTracker;->obtain(Ljava/lang/String;)Landroid/view/VelocityTracker;
Landroid/view/View;->clearAccessibilityFocus()V
+Landroid/view/View;->computeFitSystemWindows(Landroid/graphics/Rect;Landroid/graphics/Rect;)Z
Landroid/view/View;->computeOpaqueFlags()V
Landroid/view/ViewConfiguration;->mFadingMarqueeEnabled:Z
Landroid/view/ViewConfiguration;->sHasPermanentMenuKeySet:Z
@@ -732,6 +776,7 @@
Landroid/view/View;->getViewRootImpl()Landroid/view/ViewRootImpl;
Landroid/view/ViewGroup;->FLAG_SUPPORT_STATIC_TRANSFORMATIONS:I
Landroid/view/ViewGroup;->FLAG_USE_CHILD_DRAWING_ORDER:I
+Landroid/view/ViewGroup;->makeOptionalFitsSystemWindows()V
Landroid/view/ViewGroup$MarginLayoutParams;->endMargin:I
Landroid/view/ViewGroup$MarginLayoutParams;->startMargin:I
Landroid/view/ViewGroup;->mChildren:[Landroid/view/View;
@@ -810,6 +855,7 @@
Landroid/webkit/WebView;->enablePlatformNotifications()V
Landroid/webkit/WebViewFactory;->getLoadedPackageInfo()Landroid/content/pm/PackageInfo;
Landroid/webkit/WebViewFactory;->getProvider()Landroid/webkit/WebViewFactoryProvider;
+Landroid/webkit/WebViewFactory;->sPackageInfo:Landroid/content/pm/PackageInfo;
Landroid/webkit/WebView;->getVisibleTitleHeight()I
Landroid/webkit/WebView;->getWebViewProvider()Landroid/webkit/WebViewProvider;
Landroid/webkit/WebView;->isPaused()Z
@@ -939,6 +985,7 @@
Landroid/widget/Switch;->mThumbDrawable:Landroid/graphics/drawable/Drawable;
Landroid/widget/Switch;->mTrackDrawable:Landroid/graphics/drawable/Drawable;
Landroid/widget/TabWidget;->setTabSelectionListener(Landroid/widget/TabWidget$OnTabSelectionChanged;)V
+Landroid/widget/TextView;->assumeLayout()V
Landroid/widget/TextView;->createEditorIfNeeded()V
Landroid/widget/TextView;->mCursorDrawableRes:I
Landroid/widget/TextView;->mCurTextColor:I
@@ -977,6 +1024,8 @@
Lcom/android/internal/os/BatteryStatsImpl$Uid$Sensor;->getHandle()I
Lcom/android/internal/os/BatteryStatsImpl$Uid$Sensor;->getSensorTime()Lcom/android/internal/os/BatteryStatsImpl$Timer;
Lcom/android/internal/os/BatteryStatsImpl$Uid$Wakelock;->getWakeTime(I)Lcom/android/internal/os/BatteryStatsImpl$Timer;
+Lcom/android/internal/os/FuseAppLoop;->onCommand(IJJJI[B)V
+Lcom/android/internal/os/FuseAppLoop;->onOpen(JJ)[B
Lcom/android/internal/os/PowerProfile;->getAveragePower(Ljava/lang/String;)D
Lcom/android/internal/os/PowerProfile;->getAveragePower(Ljava/lang/String;I)D
Lcom/android/internal/os/PowerProfile;->getBatteryCapacity()D
@@ -1038,8 +1087,13 @@
Lcom/android/internal/view/menu/MenuItemImpl;->setMenuInfo(Landroid/view/ContextMenu$ContextMenuInfo;)V
Lcom/android/okhttp/ConnectionPool;->maxIdleConnections:I
Lcom/android/okhttp/ConnectionPool;->systemDefault:Lcom/android/okhttp/ConnectionPool;
+Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getAlpnSelectedProtocol()[B
+Lcom/android/org/conscrypt/OpenSSLSocketImpl;->setAlpnProtocols([B)V
Ldalvik/system/BaseDexClassLoader;->getLdLibraryPath()Ljava/lang/String;
Ldalvik/system/BaseDexClassLoader;->pathList:Ldalvik/system/DexPathList;
+Ldalvik/system/CloseGuard;->get()Ldalvik/system/CloseGuard;
+Ldalvik/system/CloseGuard;->open(Ljava/lang/String;)V
+Ldalvik/system/CloseGuard;->warnIfOpen()V
Ldalvik/system/DexFile;->mCookie:Ljava/lang/Object;
Ldalvik/system/DexFile;->mFileName:Ljava/lang/String;
Ldalvik/system/DexFile;->openDexFile(Ljava/lang/String;Ljava/lang/String;ILjava/lang/ClassLoader;[Ldalvik/system/DexPathList$Element;)Ljava/lang/Object;
@@ -1050,6 +1104,7 @@
Ldalvik/system/DexPathList;->makePathElements(Ljava/util/List;Ljava/io/File;Ljava/util/List;)[Ldalvik/system/DexPathList$Element;
Ldalvik/system/DexPathList;->nativeLibraryDirectories:Ljava/util/List;
Ldalvik/system/DexPathList;->nativeLibraryPathElements:[Ldalvik/system/DexPathList$NativeLibraryElement;
+Ldalvik/system/DexPathList;->systemNativeLibraryDirectories:Ljava/util/List;
Ldalvik/system/VMDebug;->dumpReferenceTables()V
Ldalvik/system/VMRuntime;->clearGrowthLimit()V
Ldalvik/system/VMRuntime;->getCurrentInstructionSet()Ljava/lang/String;
@@ -1074,6 +1129,7 @@
Ljava/lang/Class;->dexClassDefIndex:I
Ljava/lang/ClassLoader;->parent:Ljava/lang/ClassLoader;
Ljava/lang/Daemons$Daemon;->stop()V
+Ljava/lang/Daemons$Daemon;->thread:Ljava/lang/Thread;
Ljava/lang/Daemons$FinalizerDaemon;->finalizingObject:Ljava/lang/Object;
Ljava/lang/Daemons$FinalizerDaemon;->INSTANCE:Ljava/lang/Daemons$FinalizerDaemon;
Ljava/lang/Daemons$FinalizerWatchdogDaemon;->INSTANCE:Ljava/lang/Daemons$FinalizerWatchdogDaemon;
@@ -1092,6 +1148,8 @@
Ljava/net/Socket;->impl:Ljava/net/SocketImpl;
Ljava/net/URI;->host:Ljava/lang/String;
Ljava/nio/charset/CharsetEncoder;->canEncode(Ljava/nio/CharBuffer;)Z
+Ljava/security/spec/ECParameterSpec;->getCurveName()Ljava/lang/String;
+Ljava/security/spec/ECParameterSpec;->setCurveName(Ljava/lang/String;)V
Ljava/util/ArrayList$SubList;->parent:Ljava/util/AbstractList;
Ljava/util/ArrayList$SubList;->parentOffset:I
Ljava/util/ArrayList$SubList;->size:I
@@ -1101,5 +1159,6 @@
Ljava/util/Locale;->createConstant(Ljava/lang/String;Ljava/lang/String;)Ljava/util/Locale;
Ljavax/net/ssl/SSLServerSocketFactory;->defaultServerSocketFactory:Ljavax/net/ssl/SSLServerSocketFactory;
Ljavax/net/ssl/SSLSocketFactory;->defaultSocketFactory:Ljavax/net/ssl/SSLSocketFactory;
+Lorg/apache/http/conn/ssl/SSLSocketFactory;-><init>(Ljavax/net/ssl/SSLSocketFactory;)V
Lorg/json/JSONArray;->values:Ljava/util/List;
Lsun/misc/Unsafe;->theUnsafe:Lsun/misc/Unsafe;
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index f21746c..39bccc3 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -51,6 +51,7 @@
import android.os.Build;
import android.os.Bundle;
import android.os.DeadSystemException;
+import android.os.FileUtils;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -1329,11 +1330,7 @@
private void copyStreamToWallpaperFile(InputStream data, FileOutputStream fos)
throws IOException {
- byte[] buffer = new byte[32768];
- int amt;
- while ((amt=data.read(buffer)) > 0) {
- fos.write(buffer, 0, amt);
- }
+ FileUtils.copy(data, fos);
}
/**
diff --git a/core/java/android/app/slice/ISliceManager.aidl b/core/java/android/app/slice/ISliceManager.aidl
index 4461b16..38d9025 100644
--- a/core/java/android/app/slice/ISliceManager.aidl
+++ b/core/java/android/app/slice/ISliceManager.aidl
@@ -31,4 +31,7 @@
SliceSpec[] getPinnedSpecs(in Uri uri, String pkg);
int checkSlicePermission(in Uri uri, String pkg, int pid, int uid);
void grantPermissionFromUser(in Uri uri, String pkg, String callingPkg, boolean allSlices);
+
+ byte[] getBackupPayload(int user);
+ void applyRestore(in byte[] payload, int user);
}
diff --git a/core/java/android/app/slice/SliceManager.java b/core/java/android/app/slice/SliceManager.java
index e5f3eae..3f13fff 100644
--- a/core/java/android/app/slice/SliceManager.java
+++ b/core/java/android/app/slice/SliceManager.java
@@ -20,9 +20,9 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemService;
+import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.Context;
-import android.content.IContentProvider;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.net.Uri;
@@ -193,10 +193,15 @@
* <p>
* Pinned state is not persisted across reboots, so apps are expected to re-pin any slices
* they still care about after a reboot.
+ * <p>
+ * This may only be called by apps that are the default launcher for the device
+ * or the default voice interaction service. Otherwise will throw {@link SecurityException}.
*
* @param uri The uri of the slice being pinned.
* @param specs The list of supported {@link SliceSpec}s of the callback.
* @see SliceProvider#onSlicePinned(Uri)
+ * @see Intent#ACTION_ASSIST
+ * @see Intent#CATEGORY_HOME
*/
public void pinSlice(@NonNull Uri uri, @NonNull List<SliceSpec> specs) {
try {
@@ -211,10 +216,15 @@
* Remove a pin for a slice.
* <p>
* If the slice has no other pins/callbacks then the slice will be unpinned.
+ * <p>
+ * This may only be called by apps that are the default launcher for the device
+ * or the default voice interaction service. Otherwise will throw {@link SecurityException}.
*
* @param uri The uri of the slice being unpinned.
* @see #pinSlice
* @see SliceProvider#onSliceUnpinned(Uri)
+ * @see Intent#ACTION_ASSIST
+ * @see Intent#CATEGORY_HOME
*/
public void unpinSlice(@NonNull Uri uri) {
try {
@@ -262,17 +272,13 @@
*/
public @NonNull Collection<Uri> getSliceDescendants(@NonNull Uri uri) {
ContentResolver resolver = mContext.getContentResolver();
- IContentProvider provider = resolver.acquireProvider(uri);
- try {
+ try (ContentProviderClient provider = resolver.acquireContentProviderClient(uri)) {
Bundle extras = new Bundle();
extras.putParcelable(SliceProvider.EXTRA_BIND_URI, uri);
- final Bundle res = provider.call(resolver.getPackageName(),
- SliceProvider.METHOD_GET_DESCENDANTS, null, extras);
+ final Bundle res = provider.call(SliceProvider.METHOD_GET_DESCENDANTS, null, extras);
return res.getParcelableArrayList(SliceProvider.EXTRA_SLICE_DESCENDANTS);
} catch (RemoteException e) {
Log.e(TAG, "Unable to get slice descendants", e);
- } finally {
- resolver.releaseProvider(provider);
}
return Collections.emptyList();
}
@@ -288,17 +294,15 @@
public @Nullable Slice bindSlice(@NonNull Uri uri, @NonNull List<SliceSpec> supportedSpecs) {
Preconditions.checkNotNull(uri, "uri");
ContentResolver resolver = mContext.getContentResolver();
- IContentProvider provider = resolver.acquireProvider(uri);
- if (provider == null) {
- throw new IllegalArgumentException("Unknown URI " + uri);
- }
- try {
+ try (ContentProviderClient provider = resolver.acquireContentProviderClient(uri)) {
+ if (provider == null) {
+ throw new IllegalArgumentException("Unknown URI " + uri);
+ }
Bundle extras = new Bundle();
extras.putParcelable(SliceProvider.EXTRA_BIND_URI, uri);
extras.putParcelableArrayList(SliceProvider.EXTRA_SUPPORTED_SPECS,
new ArrayList<>(supportedSpecs));
- final Bundle res = provider.call(mContext.getPackageName(), SliceProvider.METHOD_SLICE,
- null, extras);
+ final Bundle res = provider.call(SliceProvider.METHOD_SLICE, null, extras);
Bundle.setDefusable(res, true);
if (res == null) {
return null;
@@ -308,8 +312,6 @@
// Arbitrary and not worth documenting, as Activity
// Manager will kill this process shortly anyway.
return null;
- } finally {
- resolver.releaseProvider(provider);
}
}
@@ -344,15 +346,13 @@
String authority = providers.get(0).providerInfo.authority;
Uri uri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
.authority(authority).build();
- IContentProvider provider = resolver.acquireProvider(uri);
- if (provider == null) {
- throw new IllegalArgumentException("Unknown URI " + uri);
- }
- try {
+ try (ContentProviderClient provider = resolver.acquireContentProviderClient(uri)) {
+ if (provider == null) {
+ throw new IllegalArgumentException("Unknown URI " + uri);
+ }
Bundle extras = new Bundle();
extras.putParcelable(SliceProvider.EXTRA_INTENT, intent);
- final Bundle res = provider.call(mContext.getPackageName(),
- SliceProvider.METHOD_MAP_ONLY_INTENT, null, extras);
+ final Bundle res = provider.call(SliceProvider.METHOD_MAP_ONLY_INTENT, null, extras);
if (res == null) {
return null;
}
@@ -361,8 +361,6 @@
// Arbitrary and not worth documenting, as Activity
// Manager will kill this process shortly anyway.
return null;
- } finally {
- resolver.releaseProvider(provider);
}
}
@@ -399,17 +397,15 @@
String authority = providers.get(0).providerInfo.authority;
Uri uri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
.authority(authority).build();
- IContentProvider provider = resolver.acquireProvider(uri);
- if (provider == null) {
- throw new IllegalArgumentException("Unknown URI " + uri);
- }
- try {
+ try (ContentProviderClient provider = resolver.acquireContentProviderClient(uri)) {
+ if (provider == null) {
+ throw new IllegalArgumentException("Unknown URI " + uri);
+ }
Bundle extras = new Bundle();
extras.putParcelable(SliceProvider.EXTRA_INTENT, intent);
extras.putParcelableArrayList(SliceProvider.EXTRA_SUPPORTED_SPECS,
new ArrayList<>(supportedSpecs));
- final Bundle res = provider.call(mContext.getPackageName(),
- SliceProvider.METHOD_MAP_INTENT, null, extras);
+ final Bundle res = provider.call(SliceProvider.METHOD_MAP_INTENT, null, extras);
if (res == null) {
return null;
}
@@ -418,8 +414,6 @@
// Arbitrary and not worth documenting, as Activity
// Manager will kill this process shortly anyway.
return null;
- } finally {
- resolver.releaseProvider(provider);
}
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index f2eb4a0..753f671 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -49,6 +49,7 @@
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
@@ -4678,9 +4679,15 @@
*
* @hide
*/
- public abstract Context createPackageContextAsUser(
+ @SystemApi
+ public Context createPackageContextAsUser(
String packageName, @CreatePackageOptions int flags, UserHandle user)
- throws PackageManager.NameNotFoundException;
+ throws PackageManager.NameNotFoundException {
+ if (Build.IS_ENG) {
+ throw new IllegalStateException("createPackageContextAsUser not overridden!");
+ }
+ return this;
+ }
/**
* Creates a context given an {@link android.content.pm.ApplicationInfo}.
diff --git a/core/java/android/content/pm/IPackageInstallerSession.aidl b/core/java/android/content/pm/IPackageInstallerSession.aidl
index 0b16852..8fddb99 100644
--- a/core/java/android/content/pm/IPackageInstallerSession.aidl
+++ b/core/java/android/content/pm/IPackageInstallerSession.aidl
@@ -26,9 +26,12 @@
void addClientProgress(float progress);
String[] getNames();
+
ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes);
ParcelFileDescriptor openRead(String name);
+ void write(String name, long offsetBytes, long lengthBytes, in ParcelFileDescriptor fd);
+
void removeSplit(String splitName);
void close();
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index df677d2..d0be6c8 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -829,7 +829,19 @@
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
+ }
+ /** {@hide} */
+ public void write(@NonNull String name, long offsetBytes, long lengthBytes,
+ @NonNull ParcelFileDescriptor fd) throws IOException {
+ try {
+ mSession.write(name, offsetBytes, lengthBytes, fd);
+ } catch (RuntimeException e) {
+ ExceptionUtils.maybeUnwrapIOException(e);
+ throw e;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
diff --git a/core/java/android/hardware/biometrics/BiometricAuthenticator.java b/core/java/android/hardware/biometrics/BiometricAuthenticator.java
new file mode 100644
index 0000000..c811999
--- /dev/null
+++ b/core/java/android/hardware/biometrics/BiometricAuthenticator.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.biometrics;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
+import android.os.CancellationSignal;
+import android.os.Parcelable;
+
+import java.util.concurrent.Executor;
+
+/**
+ * This is the common interface that all biometric authentication classes should implement.
+ * @hide
+ */
+public interface BiometricAuthenticator {
+
+ /**
+ * Container for biometric data
+ * @hide
+ */
+ abstract class BiometricIdentifier implements Parcelable {}
+
+ /**
+ * Container for callback data from {@link BiometricAuthenticator#authenticate(
+ * CancellationSignal, Executor, AuthenticationCallback)} and
+ * {@link BiometricAuthenticator#authenticate(CryptoObject, CancellationSignal, Executor,
+ * AuthenticationCallback)}
+ */
+ class AuthenticationResult {
+ private BiometricIdentifier mIdentifier;
+ private CryptoObject mCryptoObject;
+ private int mUserId;
+
+ /**
+ * @hide
+ */
+ public AuthenticationResult() { }
+
+ /**
+ * Authentication result
+ * @param crypto
+ * @param identifier
+ * @param userId
+ * @hide
+ */
+ public AuthenticationResult(CryptoObject crypto, BiometricIdentifier identifier,
+ int userId) {
+ mCryptoObject = crypto;
+ mIdentifier = identifier;
+ mUserId = userId;
+ }
+
+ /**
+ * Obtain the crypto object associated with this transaction
+ * @return crypto object provided to {@link BiometricAuthenticator#authenticate(
+ * CryptoObject, CancellationSignal, Executor, AuthenticationCallback)}
+ */
+ public CryptoObject getCryptoObject() {
+ return mCryptoObject;
+ }
+
+ /**
+ * Obtain the biometric identifier associated with this operation. Applications are strongly
+ * discouraged from associating specific identifiers with specific applications or
+ * operations.
+ * @hide
+ */
+ public BiometricIdentifier getId() {
+ return mIdentifier;
+ }
+
+ /**
+ * Obtain the userId for which this biometric was authenticated.
+ * @hide
+ */
+ public int getUserId() {
+ return mUserId;
+ }
+ };
+
+ /**
+ * Callback structure provided to {@link BiometricAuthenticator#authenticate(CancellationSignal,
+ * Executor, AuthenticationCallback)} or {@link BiometricAuthenticator#authenticate(
+ * CryptoObject, CancellationSignal, Executor, AuthenticationCallback)}. Users must provide
+ * an implementation of this for listening to biometric events.
+ */
+ abstract class AuthenticationCallback {
+ /**
+ * Called when an unrecoverable error has been encountered and the operation is complete.
+ * No further actions will be made on this object.
+ * @param errorCode An integer identifying the error message
+ * @param errString A human-readable error string that can be shown on an UI
+ */
+ public void onAuthenticationError(int errorCode, CharSequence errString) {}
+
+ /**
+ * Called when a recoverable error has been encountered during authentication. The help
+ * string is provided to give the user guidance for what went wrong, such as "Sensor dirty,
+ * please clean it."
+ * @param helpCode An integer identifying the error message
+ * @param helpString A human-readable string that can be shown on an UI
+ */
+ public void onAuthenticationHelp(int helpCode, CharSequence helpString) {}
+
+ /**
+ * Called when a biometric is recognized.
+ * @param result An object containing authentication-related data
+ */
+ public void onAuthenticationSucceeded(AuthenticationResult result) {}
+
+ /**
+ * Called when a biometric is valid but not recognized.
+ */
+ public void onAuthenticationFailed() {}
+
+ /**
+ * Called when a biometric has been acquired, but hasn't been processed yet.
+ * @hide
+ */
+ public void onAuthenticationAcquired(int acquireInfo) {}
+ };
+
+ /**
+ * This call warms up the hardware and starts scanning for valid biometrics. It terminates
+ * when {@link AuthenticationCallback#onAuthenticationError(int,
+ * CharSequence)} is called or when {@link AuthenticationCallback#onAuthenticationSucceeded(
+ * AuthenticationResult)} is called, at which point the crypto object becomes invalid. This
+ * operation can be canceled by using the provided cancel object. The application wil receive
+ * authentication errors through {@link AuthenticationCallback}. Calling
+ * {@link BiometricAuthenticator#authenticate(CryptoObject, CancellationSignal, Executor,
+ * AuthenticationCallback)} while an existing authentication attempt is occurring will stop
+ * the previous client and start a new authentication. The interrupted client will receive a
+ * cancelled notification through {@link AuthenticationCallback#onAuthenticationError(int,
+ * CharSequence)}.
+ *
+ * @throws IllegalArgumentException If any of the arguments are null
+ *
+ * @param crypto Object associated with the call
+ * @param cancel An object that can be used to cancel authentication
+ * @param executor An executor to handle callback events
+ * @param callback An object to receive authentication events
+ */
+ void authenticate(@NonNull CryptoObject crypto,
+ @NonNull CancellationSignal cancel,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull AuthenticationCallback callback);
+
+ /**
+ * This call warms up the hardware and starts scanning for valid biometrics. It terminates
+ * when {@link AuthenticationCallback#onAuthenticationError(int,
+ * CharSequence)} is called or when {@link AuthenticationCallback#onAuthenticationSucceeded(
+ * AuthenticationResult)} is called. This operation can be canceled by using the provided cancel
+ * object. The application wil receive authentication errors through
+ * {@link AuthenticationCallback}. Calling {@link BiometricAuthenticator#authenticate(
+ * CryptoObject, CancellationSignal, Executor, AuthenticationCallback)} while an existing
+ * authentication attempt is occurring will stop the previous client and start a new
+ * authentication. The interrupted client will receive a cancelled notification through
+ * {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)}.
+ *
+ * @throws IllegalArgumentException If any of the arguments are null
+ *
+ * @param cancel An object that can be used to cancel authentication
+ * @param executor An executor to handle callback events
+ * @param callback An object to receive authentication events
+ */
+ void authenticate(@NonNull CancellationSignal cancel,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull AuthenticationCallback callback);
+}
diff --git a/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java b/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java
new file mode 100644
index 0000000..638f525
--- /dev/null
+++ b/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.biometrics;
+
+import android.hardware.fingerprint.FingerprintManager;
+
+/**
+ * Interface containing all of the fingerprint-specific constants.
+ * @hide
+ */
+public interface BiometricFingerprintConstants {
+ //
+ // Error messages from fingerprint hardware during initilization, enrollment, authentication or
+ // removal. Must agree with the list in fingerprint.h
+ //
+
+ /**
+ * The hardware is unavailable. Try again later.
+ */
+ public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1;
+
+ /**
+ * Error state returned when the sensor was unable to process the current image.
+ */
+ public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2;
+
+ /**
+ * Error state returned when the current request has been running too long. This is intended to
+ * prevent programs from waiting for the fingerprint sensor indefinitely. The timeout is
+ * platform and sensor-specific, but is generally on the order of 30 seconds.
+ */
+ public static final int FINGERPRINT_ERROR_TIMEOUT = 3;
+
+ /**
+ * Error state returned for operations like enrollment; the operation cannot be completed
+ * because there's not enough storage remaining to complete the operation.
+ */
+ public static final int FINGERPRINT_ERROR_NO_SPACE = 4;
+
+ /**
+ * The operation was canceled because the fingerprint sensor is unavailable. For example,
+ * this may happen when the user is switched, the device is locked or another pending operation
+ * prevents or disables it.
+ */
+ public static final int FINGERPRINT_ERROR_CANCELED = 5;
+
+ /**
+ * The {@link FingerprintManager#remove} call failed. Typically this will happen when the
+ * provided fingerprint id was incorrect.
+ *
+ * @hide
+ */
+ public static final int FINGERPRINT_ERROR_UNABLE_TO_REMOVE = 6;
+
+ /**
+ * The operation was canceled because the API is locked out due to too many attempts.
+ * This occurs after 5 failed attempts, and lasts for 30 seconds.
+ */
+ public static final int FINGERPRINT_ERROR_LOCKOUT = 7;
+
+ /**
+ * Hardware vendors may extend this list if there are conditions that do not fall under one of
+ * the above categories. Vendors are responsible for providing error strings for these errors.
+ * These messages are typically reserved for internal operations such as enrollment, but may be
+ * used to express vendor errors not covered by the ones in fingerprint.h. Applications are
+ * expected to show the error message string if they happen, but are advised not to rely on the
+ * message id since they will be device and vendor-specific
+ */
+ public static final int FINGERPRINT_ERROR_VENDOR = 8;
+
+ /**
+ * The operation was canceled because FINGERPRINT_ERROR_LOCKOUT occurred too many times.
+ * Fingerprint authentication is disabled until the user unlocks with strong authentication
+ * (PIN/Pattern/Password)
+ */
+ public static final int FINGERPRINT_ERROR_LOCKOUT_PERMANENT = 9;
+
+ /**
+ * The user canceled the operation. Upon receiving this, applications should use alternate
+ * authentication (e.g. a password). The application should also provide the means to return
+ * to fingerprint authentication, such as a "use fingerprint" button.
+ */
+ public static final int FINGERPRINT_ERROR_USER_CANCELED = 10;
+
+ /**
+ * The user does not have any fingerprints enrolled.
+ */
+ public static final int FINGERPRINT_ERROR_NO_FINGERPRINTS = 11;
+
+ /**
+ * The device does not have a fingerprint sensor.
+ */
+ public static final int FINGERPRINT_ERROR_HW_NOT_PRESENT = 12;
+
+ /**
+ * @hide
+ */
+ public static final int FINGERPRINT_ERROR_VENDOR_BASE = 1000;
+
+ //
+ // Image acquisition messages. Must agree with those in fingerprint.h
+ //
+
+ /**
+ * The image acquired was good.
+ */
+ public static final int FINGERPRINT_ACQUIRED_GOOD = 0;
+
+ /**
+ * Only a partial fingerprint image was detected. During enrollment, the user should be
+ * informed on what needs to happen to resolve this problem, e.g. "press firmly on sensor."
+ */
+ public static final int FINGERPRINT_ACQUIRED_PARTIAL = 1;
+
+ /**
+ * The fingerprint image was too noisy to process due to a detected condition (i.e. dry skin) or
+ * a possibly dirty sensor (See {@link #FINGERPRINT_ACQUIRED_IMAGER_DIRTY}).
+ */
+ public static final int FINGERPRINT_ACQUIRED_INSUFFICIENT = 2;
+
+ /**
+ * The fingerprint image was too noisy due to suspected or detected dirt on the sensor.
+ * For example, it's reasonable return this after multiple
+ * {@link #FINGERPRINT_ACQUIRED_INSUFFICIENT} or actual detection of dirt on the sensor
+ * (stuck pixels, swaths, etc.). The user is expected to take action to clean the sensor
+ * when this is returned.
+ */
+ public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 3;
+
+ /**
+ * The fingerprint image was unreadable due to lack of motion. This is most appropriate for
+ * linear array sensors that require a swipe motion.
+ */
+ public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 4;
+
+ /**
+ * The fingerprint image was incomplete due to quick motion. While mostly appropriate for
+ * linear array sensors, this could also happen if the finger was moved during acquisition.
+ * The user should be asked to move the finger slower (linear) or leave the finger on the sensor
+ * longer.
+ */
+ public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 5;
+
+ /**
+ * Hardware vendors may extend this list if there are conditions that do not fall under one of
+ * the above categories. Vendors are responsible for providing error strings for these errors.
+ * @hide
+ */
+ public static final int FINGERPRINT_ACQUIRED_VENDOR = 6;
+ /**
+ * @hide
+ */
+ public static final int FINGERPRINT_ACQUIRED_VENDOR_BASE = 1000;
+}
diff --git a/core/java/android/hardware/biometrics/CryptoObject.java b/core/java/android/hardware/biometrics/CryptoObject.java
new file mode 100644
index 0000000..496d9c5
--- /dev/null
+++ b/core/java/android/hardware/biometrics/CryptoObject.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.biometrics;
+
+import android.annotation.NonNull;
+import android.security.keystore.AndroidKeyStoreProvider;
+
+import java.security.Signature;
+
+import javax.crypto.Cipher;
+import javax.crypto.Mac;
+
+/**
+ * A wrapper class for the crypto objects supported by FingerprintManager. Currently the
+ * framework supports {@link Signature}, {@link Cipher} and {@link Mac} objects.
+ * @hide
+ */
+public class CryptoObject {
+ private final Object mCrypto;
+
+ public CryptoObject(@NonNull Signature signature) {
+ mCrypto = signature;
+ }
+
+ public CryptoObject(@NonNull Cipher cipher) {
+ mCrypto = cipher;
+ }
+
+ public CryptoObject(@NonNull Mac mac) {
+ mCrypto = mac;
+ }
+
+ /**
+ * Get {@link Signature} object.
+ * @return {@link Signature} object or null if this doesn't contain one.
+ */
+ public Signature getSignature() {
+ return mCrypto instanceof Signature ? (Signature) mCrypto : null;
+ }
+
+ /**
+ * Get {@link Cipher} object.
+ * @return {@link Cipher} object or null if this doesn't contain one.
+ */
+ public Cipher getCipher() {
+ return mCrypto instanceof Cipher ? (Cipher) mCrypto : null;
+ }
+
+ /**
+ * Get {@link Mac} object.
+ * @return {@link Mac} object or null if this doesn't contain one.
+ */
+ public Mac getMac() {
+ return mCrypto instanceof Mac ? (Mac) mCrypto : null;
+ }
+
+ /**
+ * @hide
+ * @return the opId associated with this object or 0 if none
+ */
+ public final long getOpId() {
+ return mCrypto != null
+ ? AndroidKeyStoreProvider.getKeyStoreOperationHandle(mCrypto) : 0;
+ }
+};
diff --git a/core/java/android/hardware/fingerprint/Fingerprint.java b/core/java/android/hardware/fingerprint/Fingerprint.java
index c307634..c7ce8fa 100644
--- a/core/java/android/hardware/fingerprint/Fingerprint.java
+++ b/core/java/android/hardware/fingerprint/Fingerprint.java
@@ -15,6 +15,7 @@
*/
package android.hardware.fingerprint;
+import android.hardware.biometrics.BiometricAuthenticator;
import android.os.Parcel;
import android.os.Parcelable;
@@ -22,7 +23,7 @@
* Container for fingerprint metadata.
* @hide
*/
-public final class Fingerprint implements Parcelable {
+public final class Fingerprint extends BiometricAuthenticator.BiometricIdentifier {
private CharSequence mName;
private int mGroupId;
private int mFingerId;
diff --git a/core/java/android/hardware/fingerprint/FingerprintDialog.java b/core/java/android/hardware/fingerprint/FingerprintDialog.java
index 6b7fab7..49835963 100644
--- a/core/java/android/hardware/fingerprint/FingerprintDialog.java
+++ b/core/java/android/hardware/fingerprint/FingerprintDialog.java
@@ -23,19 +23,25 @@
import android.annotation.RequiresPermission;
import android.content.Context;
import android.content.DialogInterface;
-import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback;
-import android.hardware.fingerprint.FingerprintManager.AuthenticationResult;
+import android.content.pm.PackageManager;
+import android.hardware.biometrics.BiometricAuthenticator;
+import android.hardware.biometrics.BiometricFingerprintConstants;
+import android.hardware.biometrics.CryptoObject;
import android.hardware.fingerprint.IFingerprintDialogReceiver;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.text.TextUtils;
+import java.security.Signature;
import java.util.concurrent.Executor;
+import javax.crypto.Cipher;
+import javax.crypto.Mac;
+
/**
* A class that manages a system-provided fingerprint dialog.
*/
-public class FingerprintDialog {
+public class FingerprintDialog implements BiometricAuthenticator, BiometricFingerprintConstants {
/**
* @hide
@@ -200,6 +206,7 @@
}
}
+ private PackageManager mPackageManager;
private FingerprintManager mFingerprintManager;
private Bundle mBundle;
private ButtonInfo mPositiveButtonInfo;
@@ -227,37 +234,209 @@
mPositiveButtonInfo = positiveButtonInfo;
mNegativeButtonInfo = negativeButtonInfo;
mFingerprintManager = context.getSystemService(FingerprintManager.class);
+ mPackageManager = context.getPackageManager();
}
/**
+ * A wrapper class for the crypto objects supported by FingerprintManager. Currently the
+ * framework supports {@link Signature}, {@link Cipher} and {@link Mac} objects.
+ */
+ public static final class CryptoObject extends android.hardware.biometrics.CryptoObject {
+ public CryptoObject(@NonNull Signature signature) {
+ super(signature);
+ }
+
+ public CryptoObject(@NonNull Cipher cipher) {
+ super(cipher);
+ }
+
+ public CryptoObject(@NonNull Mac mac) {
+ super(mac);
+ }
+
+ /**
+ * Get {@link Signature} object.
+ * @return {@link Signature} object or null if this doesn't contain one.
+ */
+ public Signature getSignature() {
+ return super.getSignature();
+ }
+
+ /**
+ * Get {@link Cipher} object.
+ * @return {@link Cipher} object or null if this doesn't contain one.
+ */
+ public Cipher getCipher() {
+ return super.getCipher();
+ }
+
+ /**
+ * Get {@link Mac} object.
+ * @return {@link Mac} object or null if this doesn't contain one.
+ */
+ public Mac getMac() {
+ return super.getMac();
+ }
+ }
+
+ /**
+ * Container for callback data from {@link #authenticate(
+ * CancellationSignal, Executor, AuthenticationCallback)} and
+ * {@link #authenticate(CryptoObject, CancellationSignal, Executor,
+ * AuthenticationCallback)}
+ */
+ public static class AuthenticationResult extends BiometricAuthenticator.AuthenticationResult {
+ /**
+ * Authentication result
+ * @param crypto
+ * @param identifier
+ * @param userId
+ * @hide
+ */
+ public AuthenticationResult(CryptoObject crypto, BiometricIdentifier identifier,
+ int userId) {
+ super(crypto, identifier, userId);
+ }
+ /**
+ * Obtain the crypto object associated with this transaction
+ * @return crypto object provided to {@link #authenticate(
+ * CryptoObject, CancellationSignal, Executor, AuthenticationCallback)}
+ */
+ public CryptoObject getCryptoObject() {
+ return (CryptoObject) super.getCryptoObject();
+ }
+ }
+
+ /**
+ * Callback structure provided to {@link FingerprintDialog#authenticate(CancellationSignal,
+ * Executor, AuthenticationCallback)} or {@link FingerprintDialog#authenticate(CryptoObject,
+ * CancellationSignal, Executor, AuthenticationCallback)}. Users must provide an implementation
+ * of this for listening to authentication events.
+ */
+ public static abstract class AuthenticationCallback extends
+ BiometricAuthenticator.AuthenticationCallback {
+ /**
+ * Called when an unrecoverable error has been encountered and the operation is complete.
+ * No further actions will be made on this object.
+ * @param errorCode An integer identifying the error message
+ * @param errString A human-readable error string that can be shown on an UI
+ */
+ @Override
+ public void onAuthenticationError(int errorCode, CharSequence errString) {}
+
+ /**
+ * Called when a recoverable error has been encountered during authentication. The help
+ * string is provided to give the user guidance for what went wrong, such as "Sensor dirty,
+ * please clean it."
+ * @param helpCode An integer identifying the error message
+ * @param helpString A human-readable string that can be shown on an UI
+ */
+ @Override
+ public void onAuthenticationHelp(int helpCode, CharSequence helpString) {}
+
+ /**
+ * Called when a biometric is recognized.
+ * @param result An object containing authentication-related data
+ */
+ public void onAuthenticationSucceeded(AuthenticationResult result) {}
+
+ /**
+ * Called when a biometric is valid but not recognized.
+ */
+ @Override
+ public void onAuthenticationFailed() {}
+
+ /**
+ * Called when a biometric has been acquired, but hasn't been processed yet.
+ * @hide
+ */
+ @Override
+ public void onAuthenticationAcquired(int acquireInfo) {}
+
+ /**
+ * @param result An object containing authentication-related data
+ * @hide
+ */
+ @Override
+ public void onAuthenticationSucceeded(BiometricAuthenticator.AuthenticationResult result) {
+ onAuthenticationSucceeded(new AuthenticationResult(
+ (CryptoObject) result.getCryptoObject(),
+ result.getId(),
+ result.getUserId()));
+ }
+ }
+
+
+ /**
+ * @param crypto Object associated with the call
+ * @param cancel An object that can be used to cancel authentication
+ * @param executor An executor to handle callback events
+ * @param callback An object to receive authentication events
+ * @hide
+ */
+ @Override
+ public void authenticate(@NonNull android.hardware.biometrics.CryptoObject crypto,
+ @NonNull CancellationSignal cancel,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull BiometricAuthenticator.AuthenticationCallback callback) {
+ if (!(callback instanceof FingerprintDialog.AuthenticationCallback)) {
+ throw new IllegalArgumentException("Callback cannot be casted");
+ }
+ authenticate(crypto, cancel, executor, (AuthenticationCallback) callback);
+ }
+
+ /**
+ *
+ * @param cancel An object that can be used to cancel authentication
+ * @param executor An executor to handle callback events
+ * @param callback An object to receive authentication events
+ * @hide
+ */
+ @Override
+ public void authenticate(@NonNull CancellationSignal cancel,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull BiometricAuthenticator.AuthenticationCallback callback) {
+ if (!(callback instanceof FingerprintDialog.AuthenticationCallback)) {
+ throw new IllegalArgumentException("Callback cannot be casted");
+ }
+ authenticate(cancel, executor, (AuthenticationCallback) callback);
+ }
+
+
+ /**
* This call warms up the fingerprint hardware, displays a system-provided dialog,
* and starts scanning for a fingerprint. It terminates when
- * {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} is called, when
- * {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult)} is called,
- * when {@link AuthenticationCallback#onAuthenticationFailed()} is called or when the user
- * dismisses the system-provided dialog, at which point the crypto object becomes invalid.
- * This operation can be canceled by using the provided cancel object. The application will
- * receive authentication errors through {@link AuthenticationCallback}, and button events
- * through the corresponding callback set in
- * {@link Builder#setNegativeButton(CharSequence, Executor, DialogInterface.OnClickListener)}.
- * It is safe to reuse the {@link FingerprintDialog} object, and calling
- * {@link FingerprintDialog#authenticate(CancellationSignal, Executor, AuthenticationCallback)}
- * while an existing authentication attempt is occurring will stop the previous client and
- * start a new authentication. The interrupted client will receive a cancelled notification
- * through {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)}.
+ * {@link AuthenticationCallback#onAuthenticationError(int,
+ * CharSequence)} is called, when
+ * {@link AuthenticationCallback#onAuthenticationSucceeded(
+ * AuthenticationResult)}, or when the user dismisses the system-provided dialog, at which point
+ * the crypto object becomes invalid. This operation can be canceled by using the provided
+ * cancel object. The application will receive authentication errors through
+ * {@link AuthenticationCallback}, and button events through the
+ * corresponding callback set in {@link Builder#setNegativeButton(CharSequence,
+ * Executor, DialogInterface.OnClickListener)}. It is safe to reuse the
+ * {@link FingerprintDialog} object, and calling {@link FingerprintDialog#authenticate(
+ * CancellationSignal, Executor, AuthenticationCallback)} while an
+ * existing authentication attempt is occurring will stop the previous client and start a
+ * new authentication. The interrupted client will receive a cancelled notification through
+ * {@link AuthenticationCallback#onAuthenticationError(int,
+ * CharSequence)}.
*
- * @throws IllegalArgumentException if any of the arguments are null
+ * @throws IllegalArgumentException If any of the arguments are null
*
- * @param crypto object associated with the call
- * @param cancel an object that can be used to cancel authentication
- * @param executor an executor to handle callback events
- * @param callback an object to receive authentication events
+ * @param crypto Object associated with the call
+ * @param cancel An object that can be used to cancel authentication
+ * @param executor An executor to handle callback events
+ * @param callback An object to receive authentication events
*/
@RequiresPermission(USE_FINGERPRINT)
- public void authenticate(@NonNull FingerprintManager.CryptoObject crypto,
+ public void authenticate(@NonNull CryptoObject crypto,
@NonNull CancellationSignal cancel,
@NonNull @CallbackExecutor Executor executor,
- @NonNull FingerprintManager.AuthenticationCallback callback) {
+ @NonNull AuthenticationCallback callback) {
+ if (handlePreAuthenticationErrors(callback, executor)) {
+ return;
+ }
mFingerprintManager.authenticate(crypto, cancel, mBundle, executor, mDialogReceiver,
callback);
}
@@ -265,29 +444,57 @@
/**
* This call warms up the fingerprint hardware, displays a system-provided dialog,
* and starts scanning for a fingerprint. It terminates when
- * {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} is called, when
- * {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult)} is called,
- * when {@link AuthenticationCallback#onAuthenticationFailed()} is called or when the user
- * dismisses the system-provided dialog. This operation can be canceled by using the provided
- * cancel object. The application will receive authentication errors through
- * {@link AuthenticationCallback}, and button events through the corresponding callback set in
+ * {@link AuthenticationCallback#onAuthenticationError(int,
+ * CharSequence)} is called, when
+ * {@link AuthenticationCallback#onAuthenticationSucceeded(
+ * AuthenticationResult)} is called, or when the user dismisses the system-provided dialog.
+ * This operation can be canceled by using the provided cancel object. The application will
+ * receive authentication errors through {@link AuthenticationCallback},
+ * and button events through the corresponding callback set in
* {@link Builder#setNegativeButton(CharSequence, Executor, DialogInterface.OnClickListener)}.
* It is safe to reuse the {@link FingerprintDialog} object, and calling
- * {@link FingerprintDialog#authenticate(CancellationSignal, Executor, AuthenticationCallback)}
- * while an existing authentication attempt is occurring will stop the previous client and
- * start a new authentication. The interrupted client will receive a cancelled notification
- * through {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)}.
+ * {@link FingerprintDialog#authenticate(CancellationSignal, Executor,
+ * AuthenticationCallback)} while an existing authentication attempt is
+ * occurring will stop the previous client and start a new authentication. The interrupted
+ * client will receive a cancelled notification through
+ * {@link AuthenticationCallback#onAuthenticationError(int,
+ * CharSequence)}.
*
- * @throws IllegalArgumentException if any of the arguments are null
+ * @throws IllegalArgumentException If any of the arguments are null
*
- * @param cancel an object that can be used to cancel authentication
- * @param executor an executor to handle callback events
- * @param callback an object to receive authentication events
+ * @param cancel An object that can be used to cancel authentication
+ * @param executor An executor to handle callback events
+ * @param callback An object to receive authentication events
*/
@RequiresPermission(USE_FINGERPRINT)
public void authenticate(@NonNull CancellationSignal cancel,
@NonNull @CallbackExecutor Executor executor,
- @NonNull FingerprintManager.AuthenticationCallback callback) {
+ @NonNull AuthenticationCallback callback) {
+ if (handlePreAuthenticationErrors(callback, executor)) {
+ return;
+ }
mFingerprintManager.authenticate(cancel, mBundle, executor, mDialogReceiver, callback);
}
+
+ private boolean handlePreAuthenticationErrors(AuthenticationCallback callback,
+ Executor executor) {
+ if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
+ sendError(FINGERPRINT_ERROR_HW_NOT_PRESENT, callback, executor);
+ return true;
+ } else if (!mFingerprintManager.isHardwareDetected()) {
+ sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, callback, executor);
+ return true;
+ } else if (!mFingerprintManager.hasEnrolledFingerprints()) {
+ sendError(FINGERPRINT_ERROR_NO_FINGERPRINTS, callback, executor);
+ return true;
+ }
+ return false;
+ }
+
+ private void sendError(int error, AuthenticationCallback callback, Executor executor) {
+ executor.execute(() -> {
+ callback.onAuthenticationError(error, mFingerprintManager.getErrorString(
+ error, 0 /* vendorCode */));
+ });
+ }
}
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 62d92c4..2dfe673 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -27,6 +27,8 @@
import android.annotation.SystemService;
import android.app.ActivityManager;
import android.content.Context;
+import android.hardware.biometrics.BiometricAuthenticator;
+import android.hardware.biometrics.BiometricFingerprintConstants;
import android.os.Binder;
import android.os.Bundle;
import android.os.CancellationSignal;
@@ -38,7 +40,6 @@
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.security.keystore.AndroidKeyStoreProvider;
import android.util.Log;
import android.util.Slog;
@@ -51,9 +52,14 @@
/**
* A class that coordinates access to the fingerprint hardware.
+ * @deprecated See {@link FingerprintDialog} which shows a system-provided dialog upon starting
+ * authentication. In a world where devices may have in-display fingerprint sensors, it's much
+ * more realistic to have a system-provided authentication dialog since the in-display sensor
+ * location may vary by vendor/device.
*/
+@Deprecated
@SystemService(Context.FINGERPRINT_SERVICE)
-public class FingerprintManager {
+public class FingerprintManager implements BiometricFingerprintConstants {
private static final String TAG = "FingerprintManager";
private static final boolean DEBUG = true;
private static final int MSG_ENROLL_RESULT = 100;
@@ -64,147 +70,14 @@
private static final int MSG_REMOVED = 105;
private static final int MSG_ENUMERATED = 106;
- //
- // Error messages from fingerprint hardware during initilization, enrollment, authentication or
- // removal. Must agree with the list in fingerprint.h
- //
-
- /**
- * The hardware is unavailable. Try again later.
- */
- public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1;
-
- /**
- * Error state returned when the sensor was unable to process the current image.
- */
- public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2;
-
- /**
- * Error state returned when the current request has been running too long. This is intended to
- * prevent programs from waiting for the fingerprint sensor indefinitely. The timeout is
- * platform and sensor-specific, but is generally on the order of 30 seconds.
- */
- public static final int FINGERPRINT_ERROR_TIMEOUT = 3;
-
- /**
- * Error state returned for operations like enrollment; the operation cannot be completed
- * because there's not enough storage remaining to complete the operation.
- */
- public static final int FINGERPRINT_ERROR_NO_SPACE = 4;
-
- /**
- * The operation was canceled because the fingerprint sensor is unavailable. For example,
- * this may happen when the user is switched, the device is locked or another pending operation
- * prevents or disables it.
- */
- public static final int FINGERPRINT_ERROR_CANCELED = 5;
-
- /**
- * The {@link FingerprintManager#remove} call failed. Typically this will happen when the
- * provided fingerprint id was incorrect.
- *
- * @hide
- */
- public static final int FINGERPRINT_ERROR_UNABLE_TO_REMOVE = 6;
-
- /**
- * The operation was canceled because the API is locked out due to too many attempts.
- * This occurs after 5 failed attempts, and lasts for 30 seconds.
- */
- public static final int FINGERPRINT_ERROR_LOCKOUT = 7;
-
- /**
- * Hardware vendors may extend this list if there are conditions that do not fall under one of
- * the above categories. Vendors are responsible for providing error strings for these errors.
- * These messages are typically reserved for internal operations such as enrollment, but may be
- * used to express vendor errors not covered by the ones in fingerprint.h. Applications are
- * expected to show the error message string if they happen, but are advised not to rely on the
- * message id since they will be device and vendor-specific
- */
- public static final int FINGERPRINT_ERROR_VENDOR = 8;
-
- /**
- * The operation was canceled because FINGERPRINT_ERROR_LOCKOUT occurred too many times.
- * Fingerprint authentication is disabled until the user unlocks with strong authentication
- * (PIN/Pattern/Password)
- */
- public static final int FINGERPRINT_ERROR_LOCKOUT_PERMANENT = 9;
-
- /**
- * The user canceled the operation. Upon receiving this, applications should use alternate
- * authentication (e.g. a password). The application should also provide the means to return
- * to fingerprint authentication, such as a "use fingerprint" button.
- */
- public static final int FINGERPRINT_ERROR_USER_CANCELED = 10;
-
- /**
- * @hide
- */
- public static final int FINGERPRINT_ERROR_VENDOR_BASE = 1000;
-
- //
- // Image acquisition messages. Must agree with those in fingerprint.h
- //
-
- /**
- * The image acquired was good.
- */
- public static final int FINGERPRINT_ACQUIRED_GOOD = 0;
-
- /**
- * Only a partial fingerprint image was detected. During enrollment, the user should be
- * informed on what needs to happen to resolve this problem, e.g. "press firmly on sensor."
- */
- public static final int FINGERPRINT_ACQUIRED_PARTIAL = 1;
-
- /**
- * The fingerprint image was too noisy to process due to a detected condition (i.e. dry skin) or
- * a possibly dirty sensor (See {@link #FINGERPRINT_ACQUIRED_IMAGER_DIRTY}).
- */
- public static final int FINGERPRINT_ACQUIRED_INSUFFICIENT = 2;
-
- /**
- * The fingerprint image was too noisy due to suspected or detected dirt on the sensor.
- * For example, it's reasonable return this after multiple
- * {@link #FINGERPRINT_ACQUIRED_INSUFFICIENT} or actual detection of dirt on the sensor
- * (stuck pixels, swaths, etc.). The user is expected to take action to clean the sensor
- * when this is returned.
- */
- public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 3;
-
- /**
- * The fingerprint image was unreadable due to lack of motion. This is most appropriate for
- * linear array sensors that require a swipe motion.
- */
- public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 4;
-
- /**
- * The fingerprint image was incomplete due to quick motion. While mostly appropriate for
- * linear array sensors, this could also happen if the finger was moved during acquisition.
- * The user should be asked to move the finger slower (linear) or leave the finger on the sensor
- * longer.
- */
- public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 5;
-
- /**
- * Hardware vendors may extend this list if there are conditions that do not fall under one of
- * the above categories. Vendors are responsible for providing error strings for these errors.
- * @hide
- */
- public static final int FINGERPRINT_ACQUIRED_VENDOR = 6;
- /**
- * @hide
- */
- public static final int FINGERPRINT_ACQUIRED_VENDOR_BASE = 1000;
-
private IFingerprintService mService;
private Context mContext;
private IBinder mToken = new Binder();
- private AuthenticationCallback mAuthenticationCallback;
+ private BiometricAuthenticator.AuthenticationCallback mAuthenticationCallback;
private EnrollmentCallback mEnrollmentCallback;
private RemovalCallback mRemovalCallback;
private EnumerateCallback mEnumerateCallback;
- private CryptoObject mCryptoObject;
+ private android.hardware.biometrics.CryptoObject mCryptoObject;
private Fingerprint mRemovalFingerprint;
private Handler mHandler;
private Executor mExecutor;
@@ -217,9 +90,9 @@
}
private class OnAuthenticationCancelListener implements OnCancelListener {
- private CryptoObject mCrypto;
+ private android.hardware.biometrics.CryptoObject mCrypto;
- public OnAuthenticationCancelListener(CryptoObject crypto) {
+ public OnAuthenticationCancelListener(android.hardware.biometrics.CryptoObject crypto) {
mCrypto = crypto;
}
@@ -233,18 +106,17 @@
* A wrapper class for the crypto objects supported by FingerprintManager. Currently the
* framework supports {@link Signature}, {@link Cipher} and {@link Mac} objects.
*/
- public static final class CryptoObject {
-
+ public static final class CryptoObject extends android.hardware.biometrics.CryptoObject {
public CryptoObject(@NonNull Signature signature) {
- mCrypto = signature;
+ super(signature);
}
public CryptoObject(@NonNull Cipher cipher) {
- mCrypto = cipher;
+ super(cipher);
}
public CryptoObject(@NonNull Mac mac) {
- mCrypto = mac;
+ super(mac);
}
/**
@@ -252,7 +124,7 @@
* @return {@link Signature} object or null if this doesn't contain one.
*/
public Signature getSignature() {
- return mCrypto instanceof Signature ? (Signature) mCrypto : null;
+ return super.getSignature();
}
/**
@@ -260,7 +132,7 @@
* @return {@link Cipher} object or null if this doesn't contain one.
*/
public Cipher getCipher() {
- return mCrypto instanceof Cipher ? (Cipher) mCrypto : null;
+ return super.getCipher();
}
/**
@@ -268,20 +140,9 @@
* @return {@link Mac} object or null if this doesn't contain one.
*/
public Mac getMac() {
- return mCrypto instanceof Mac ? (Mac) mCrypto : null;
+ return super.getMac();
}
-
- /**
- * @hide
- * @return the opId associated with this object or 0 if none
- */
- public long getOpId() {
- return mCrypto != null ?
- AndroidKeyStoreProvider.getKeyStoreOperationHandle(mCrypto) : 0;
- }
-
- private final Object mCrypto;
- };
+ }
/**
* Container for callback data from {@link FingerprintManager#authenticate(CryptoObject,
@@ -334,13 +195,15 @@
* int, AuthenticationCallback, Handler) } must provide an implementation of this for listening to
* fingerprint events.
*/
- public static abstract class AuthenticationCallback {
+ public static abstract class AuthenticationCallback
+ extends BiometricAuthenticator.AuthenticationCallback {
/**
* Called when an unrecoverable error has been encountered and the operation is complete.
* No further callbacks will be made on this object.
* @param errorCode An integer identifying the error message
* @param errString A human-readable error string that can be shown in UI
*/
+ @Override
public void onAuthenticationError(int errorCode, CharSequence errString) { }
/**
@@ -350,6 +213,7 @@
* @param helpCode An integer identifying the error message
* @param helpString A human-readable string that can be shown in UI
*/
+ @Override
public void onAuthenticationHelp(int helpCode, CharSequence helpString) { }
/**
@@ -361,6 +225,7 @@
/**
* Called when a fingerprint is valid but not recognized.
*/
+ @Override
public void onAuthenticationFailed() { }
/**
@@ -369,7 +234,19 @@
* @param acquireInfo one of FINGERPRINT_ACQUIRED_* constants
* @hide
*/
+ @Override
public void onAuthenticationAcquired(int acquireInfo) {}
+
+ /**
+ * @hide
+ * @param result
+ */
+ @Override
+ public void onAuthenticationSucceeded(BiometricAuthenticator.AuthenticationResult result) {
+ onAuthenticationSucceeded(new AuthenticationResult(
+ (CryptoObject) result.getCryptoObject(),
+ (Fingerprint) result.getId(), result.getUserId()));
+ }
};
/**
@@ -489,7 +366,12 @@
* by <a href="{@docRoot}training/articles/keystore.html">Android Keystore
* facility</a>.
* @throws IllegalStateException if the crypto primitive is not initialized.
+ * @deprecated See {@link FingerprintDialog#authenticate(CancellationSignal, Executor,
+ * FingerprintDialog.AuthenticationCallback)} and {@link FingerprintDialog#authenticate(
+ * FingerprintDialog.CryptoObject, CancellationSignal, Executor,
+ * FingerprintDialog.AuthenticationCallback)}
*/
+ @Deprecated
@RequiresPermission(USE_FINGERPRINT)
public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
int flags, @NonNull AuthenticationCallback callback, @Nullable Handler handler) {
@@ -554,12 +436,12 @@
* @param userId the user ID that the fingerprint hardware will authenticate for.
*/
private void authenticate(int userId,
- @Nullable CryptoObject crypto,
+ @Nullable android.hardware.biometrics.CryptoObject crypto,
@NonNull CancellationSignal cancel,
@NonNull Bundle bundle,
@NonNull @CallbackExecutor Executor executor,
@NonNull IFingerprintDialogReceiver receiver,
- @NonNull AuthenticationCallback callback) {
+ @NonNull BiometricAuthenticator.AuthenticationCallback callback) {
mCryptoObject = crypto;
if (cancel.isCanceled()) {
Log.w(TAG, "authentication already canceled");
@@ -598,7 +480,7 @@
@NonNull Bundle bundle,
@NonNull @CallbackExecutor Executor executor,
@NonNull IFingerprintDialogReceiver receiver,
- @NonNull AuthenticationCallback callback) {
+ @NonNull BiometricAuthenticator.AuthenticationCallback callback) {
if (cancel == null) {
throw new IllegalArgumentException("Must supply a cancellation signal");
}
@@ -626,12 +508,12 @@
* @param callback
* @hide
*/
- public void authenticate(@NonNull CryptoObject crypto,
+ public void authenticate(@NonNull android.hardware.biometrics.CryptoObject crypto,
@NonNull CancellationSignal cancel,
@NonNull Bundle bundle,
@NonNull @CallbackExecutor Executor executor,
@NonNull IFingerprintDialogReceiver receiver,
- @NonNull AuthenticationCallback callback) {
+ @NonNull BiometricAuthenticator.AuthenticationCallback callback) {
if (crypto == null) {
throw new IllegalArgumentException("Must supply a crypto object");
}
@@ -648,9 +530,10 @@
throw new IllegalArgumentException("Must supply a receiver");
}
if (callback == null) {
- throw new IllegalArgumentException("Must supply a calback");
+ throw new IllegalArgumentException("Must supply a callback");
}
- authenticate(UserHandle.myUserId(), crypto, cancel, bundle, executor, receiver, callback);
+ authenticate(UserHandle.myUserId(), crypto, cancel,
+ bundle, executor, receiver, callback);
}
/**
@@ -848,7 +731,10 @@
* Determine if there is at least one fingerprint enrolled.
*
* @return true if at least one fingerprint is enrolled, false otherwise
+ * @deprecated See {@link FingerprintDialog} and
+ * {@link FingerprintDialog#FINGERPRINT_ERROR_NO_FINGERPRINTS}
*/
+ @Deprecated
@RequiresPermission(USE_FINGERPRINT)
public boolean hasEnrolledFingerprints() {
if (mService != null) try {
@@ -879,7 +765,10 @@
* Determine if fingerprint hardware is present and functional.
*
* @return true if hardware is present and functional, false otherwise.
+ * @deprecated See {@link FingerprintDialog} and
+ * {@link FingerprintDialog#FINGERPRINT_ERROR_HW_UNAVAILABLE}
*/
+ @Deprecated
@RequiresPermission(USE_FINGERPRINT)
public boolean isHardwareDetected() {
if (mService != null) {
@@ -1049,8 +938,8 @@
private void sendAuthenticatedSucceeded(Fingerprint fp, int userId) {
if (mAuthenticationCallback != null) {
- final AuthenticationResult result =
- new AuthenticationResult(mCryptoObject, fp, userId);
+ final BiometricAuthenticator.AuthenticationResult result =
+ new BiometricAuthenticator.AuthenticationResult(mCryptoObject, fp, userId);
mAuthenticationCallback.onAuthenticationSucceeded(result);
}
}
@@ -1126,7 +1015,7 @@
}
}
- private void cancelAuthentication(CryptoObject cryptoObject) {
+ private void cancelAuthentication(android.hardware.biometrics.CryptoObject cryptoObject) {
if (mService != null) try {
mService.cancelAuthentication(mToken, mContext.getOpPackageName());
} catch (RemoteException e) {
@@ -1160,6 +1049,12 @@
case FINGERPRINT_ERROR_USER_CANCELED:
return mContext.getString(
com.android.internal.R.string.fingerprint_error_user_canceled);
+ case FINGERPRINT_ERROR_NO_FINGERPRINTS:
+ return mContext.getString(
+ com.android.internal.R.string.fingerprint_error_no_fingerprints);
+ case FINGERPRINT_ERROR_HW_NOT_PRESENT:
+ return mContext.getString(
+ com.android.internal.R.string.fingerprint_error_hw_not_present);
case FINGERPRINT_ERROR_VENDOR: {
String[] msgArray = mContext.getResources().getStringArray(
com.android.internal.R.array.fingerprint_error_vendor);
diff --git a/core/java/android/hardware/radio/RadioManager.java b/core/java/android/hardware/radio/RadioManager.java
index b00f603..e1d7edf 100644
--- a/core/java/android/hardware/radio/RadioManager.java
+++ b/core/java/android/hardware/radio/RadioManager.java
@@ -213,6 +213,7 @@
private final boolean mIsBgScanSupported;
private final Set<Integer> mSupportedProgramTypes;
private final Set<Integer> mSupportedIdentifierTypes;
+ @Nullable private final Map<String, Integer> mDabFrequencyTable;
@NonNull private final Map<String, String> mVendorInfo;
/** @hide */
@@ -221,6 +222,7 @@
boolean isCaptureSupported, BandDescriptor[] bands, boolean isBgScanSupported,
@ProgramSelector.ProgramType int[] supportedProgramTypes,
@ProgramSelector.IdentifierType int[] supportedIdentifierTypes,
+ @Nullable Map<String, Integer> dabFrequencyTable,
Map<String, String> vendorInfo) {
mId = id;
mServiceName = TextUtils.isEmpty(serviceName) ? "default" : serviceName;
@@ -236,6 +238,13 @@
mIsBgScanSupported = isBgScanSupported;
mSupportedProgramTypes = arrayToSet(supportedProgramTypes);
mSupportedIdentifierTypes = arrayToSet(supportedIdentifierTypes);
+ if (dabFrequencyTable != null) {
+ for (Map.Entry<String, Integer> entry : dabFrequencyTable.entrySet()) {
+ Objects.requireNonNull(entry.getKey());
+ Objects.requireNonNull(entry.getValue());
+ }
+ }
+ mDabFrequencyTable = dabFrequencyTable;
mVendorInfo = (vendorInfo == null) ? new HashMap<>() : vendorInfo;
}
@@ -363,6 +372,19 @@
}
/**
+ * A frequency table for Digital Audio Broadcasting (DAB).
+ *
+ * The key is a channel name, i.e. 5A, 7B.
+ *
+ * The value is a frequency, in kHz.
+ *
+ * @return a frequency table, or {@code null} if the module doesn't support DAB
+ */
+ public @Nullable Map<String, Integer> getDabFrequencyTable() {
+ return mDabFrequencyTable;
+ }
+
+ /**
* A map of vendor-specific opaque strings, passed from HAL without changes.
* Format of these strings can vary across vendors.
*
@@ -403,6 +425,7 @@
mIsBgScanSupported = in.readInt() == 1;
mSupportedProgramTypes = arrayToSet(in.createIntArray());
mSupportedIdentifierTypes = arrayToSet(in.createIntArray());
+ mDabFrequencyTable = Utils.readStringIntMap(in);
mVendorInfo = Utils.readStringMap(in);
}
@@ -433,6 +456,7 @@
dest.writeInt(mIsBgScanSupported ? 1 : 0);
dest.writeIntArray(setToArray(mSupportedProgramTypes));
dest.writeIntArray(setToArray(mSupportedIdentifierTypes));
+ Utils.writeStringIntMap(dest, mDabFrequencyTable);
Utils.writeStringMap(dest, mVendorInfo);
}
@@ -456,67 +480,31 @@
@Override
public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + mId;
- result = prime * result + mServiceName.hashCode();
- result = prime * result + mClassId;
- result = prime * result + ((mImplementor == null) ? 0 : mImplementor.hashCode());
- result = prime * result + ((mProduct == null) ? 0 : mProduct.hashCode());
- result = prime * result + ((mVersion == null) ? 0 : mVersion.hashCode());
- result = prime * result + ((mSerial == null) ? 0 : mSerial.hashCode());
- result = prime * result + mNumTuners;
- result = prime * result + mNumAudioSources;
- result = prime * result + (mIsCaptureSupported ? 1 : 0);
- result = prime * result + Arrays.hashCode(mBands);
- result = prime * result + (mIsBgScanSupported ? 1 : 0);
- result = prime * result + mVendorInfo.hashCode();
- return result;
+ return Objects.hash(mId, mServiceName, mClassId, mImplementor, mProduct, mVersion,
+ mSerial, mNumTuners, mNumAudioSources, mIsCaptureSupported, mBands,
+ mIsBgScanSupported, mDabFrequencyTable, mVendorInfo);
}
@Override
public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (!(obj instanceof ModuleProperties))
- return false;
+ if (this == obj) return true;
+ if (!(obj instanceof ModuleProperties)) return false;
ModuleProperties other = (ModuleProperties) obj;
- if (mId != other.getId())
- return false;
+
+ if (mId != other.getId()) return false;
if (!TextUtils.equals(mServiceName, other.mServiceName)) return false;
- if (mClassId != other.getClassId())
- return false;
- if (mImplementor == null) {
- if (other.getImplementor() != null)
- return false;
- } else if (!mImplementor.equals(other.getImplementor()))
- return false;
- if (mProduct == null) {
- if (other.getProduct() != null)
- return false;
- } else if (!mProduct.equals(other.getProduct()))
- return false;
- if (mVersion == null) {
- if (other.getVersion() != null)
- return false;
- } else if (!mVersion.equals(other.getVersion()))
- return false;
- if (mSerial == null) {
- if (other.getSerial() != null)
- return false;
- } else if (!mSerial.equals(other.getSerial()))
- return false;
- if (mNumTuners != other.getNumTuners())
- return false;
- if (mNumAudioSources != other.getNumAudioSources())
- return false;
- if (mIsCaptureSupported != other.isCaptureSupported())
- return false;
- if (!Arrays.equals(mBands, other.getBands()))
- return false;
- if (mIsBgScanSupported != other.isBackgroundScanningSupported())
- return false;
- if (!mVendorInfo.equals(other.mVendorInfo)) return false;
+ if (mClassId != other.mClassId) return false;
+ if (!Objects.equals(mImplementor, other.mImplementor)) return false;
+ if (!Objects.equals(mProduct, other.mProduct)) return false;
+ if (!Objects.equals(mVersion, other.mVersion)) return false;
+ if (!Objects.equals(mSerial, other.mSerial)) return false;
+ if (mNumTuners != other.mNumTuners) return false;
+ if (mNumAudioSources != other.mNumAudioSources) return false;
+ if (mIsCaptureSupported != other.mIsCaptureSupported) return false;
+ if (!Objects.equals(mBands, other.mBands)) return false;
+ if (mIsBgScanSupported != other.mIsBgScanSupported) return false;
+ if (!Objects.equals(mDabFrequencyTable, other.mDabFrequencyTable)) return false;
+ if (!Objects.equals(mVendorInfo, other.mVendorInfo)) return false;
return true;
}
}
diff --git a/core/java/android/hardware/radio/Utils.java b/core/java/android/hardware/radio/Utils.java
index f1b5897..9887f78 100644
--- a/core/java/android/hardware/radio/Utils.java
+++ b/core/java/android/hardware/radio/Utils.java
@@ -56,6 +56,29 @@
return map;
}
+ static void writeStringIntMap(@NonNull Parcel dest, @Nullable Map<String, Integer> map) {
+ if (map == null) {
+ dest.writeInt(0);
+ return;
+ }
+ dest.writeInt(map.size());
+ for (Map.Entry<String, Integer> entry : map.entrySet()) {
+ dest.writeString(entry.getKey());
+ dest.writeInt(entry.getValue());
+ }
+ }
+
+ static @NonNull Map<String, Integer> readStringIntMap(@NonNull Parcel in) {
+ int size = in.readInt();
+ Map<String, Integer> map = new HashMap<>();
+ while (size-- > 0) {
+ String key = in.readString();
+ int value = in.readInt();
+ map.put(key, value);
+ }
+ return map;
+ }
+
static <T extends Parcelable> void writeSet(@NonNull Parcel dest, @Nullable Set<T> set) {
if (set == null) {
dest.writeInt(0);
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index bda720bb..7922276 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -439,6 +439,10 @@
}
}
+ private static long addIfSupported(long stat) {
+ return (stat == UNSUPPORTED) ? 0 : stat;
+ }
+
/**
* Return number of packets transmitted across mobile networks since device
* boot. Counts packets across all mobile network interfaces, and always
@@ -451,7 +455,7 @@
public static long getMobileTxPackets() {
long total = 0;
for (String iface : getMobileIfaces()) {
- total += getTxPackets(iface);
+ total += addIfSupported(getTxPackets(iface));
}
return total;
}
@@ -468,7 +472,7 @@
public static long getMobileRxPackets() {
long total = 0;
for (String iface : getMobileIfaces()) {
- total += getRxPackets(iface);
+ total += addIfSupported(getRxPackets(iface));
}
return total;
}
@@ -485,7 +489,7 @@
public static long getMobileTxBytes() {
long total = 0;
for (String iface : getMobileIfaces()) {
- total += getTxBytes(iface);
+ total += addIfSupported(getTxBytes(iface));
}
return total;
}
@@ -502,7 +506,7 @@
public static long getMobileRxBytes() {
long total = 0;
for (String iface : getMobileIfaces()) {
- total += getRxBytes(iface);
+ total += addIfSupported(getRxBytes(iface));
}
return total;
}
@@ -517,9 +521,7 @@
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
- if (stat != UNSUPPORTED) {
- total += stat;
- }
+ total += addIfSupported(stat);
}
return total;
}
@@ -534,9 +536,7 @@
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
- if (stat != UNSUPPORTED) {
- total += stat;
- }
+ total += addIfSupported(stat);
}
return total;
}
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index 9edcc0e..5ca3a41 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -720,6 +720,10 @@
LOOP: while (end < length) {
switch (uriString.charAt(end)) {
case '/': // Start of path
+ case '\\':// Start of path
+ // Per http://url.spec.whatwg.org/#host-state, the \ character
+ // is treated as if it were a / character when encountered in a
+ // host
case '?': // Start of query
case '#': // Start of fragment
break LOOP;
@@ -758,6 +762,10 @@
case '#': // Start of fragment
return ""; // Empty path.
case '/': // Start of path!
+ case '\\':// Start of path!
+ // Per http://url.spec.whatwg.org/#host-state, the \ character
+ // is treated as if it were a / character when encountered in a
+ // host
break LOOP;
}
pathStart++;
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 21d245d..1160415c 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -33,6 +33,7 @@
import android.webkit.MimeTypeMap;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.SizedInputStream;
import libcore.io.IoUtils;
import libcore.util.EmptyArray;
@@ -93,7 +94,7 @@
private static final long COPY_CHECKPOINT_BYTES = 524288;
- public interface CopyListener {
+ public interface ProgressListener {
public void onProgress(long progress);
}
@@ -202,7 +203,7 @@
}
/**
- * @deprecated use {@link #copy(InputStream, OutputStream)} instead.
+ * @deprecated use {@link #copy(File, File)} instead.
*/
@Deprecated
public static boolean copyFile(File srcFile, File destFile) {
@@ -215,7 +216,7 @@
}
/**
- * @deprecated use {@link #copy(InputStream, OutputStream)} instead.
+ * @deprecated use {@link #copy(File, File)} instead.
*/
@Deprecated
public static void copyFileOrThrow(File srcFile, File destFile) throws IOException {
@@ -255,44 +256,124 @@
}
}
- public static void copy(File from, File to) throws IOException {
+ /**
+ * Copy the contents of one file to another, replacing any existing content.
+ * <p>
+ * Attempts to use several optimization strategies to copy the data in the
+ * kernel before falling back to a userspace copy as a last resort.
+ *
+ * @return number of bytes copied.
+ */
+ public static long copy(@NonNull File from, @NonNull File to) throws IOException {
+ return copy(from, to, null, null);
+ }
+
+ /**
+ * Copy the contents of one file to another, replacing any existing content.
+ * <p>
+ * Attempts to use several optimization strategies to copy the data in the
+ * kernel before falling back to a userspace copy as a last resort.
+ *
+ * @param listener to be periodically notified as the copy progresses.
+ * @param signal to signal if the copy should be cancelled early.
+ * @return number of bytes copied.
+ */
+ public static long copy(@NonNull File from, @NonNull File to,
+ @Nullable ProgressListener listener, @Nullable CancellationSignal signal)
+ throws IOException {
try (FileInputStream in = new FileInputStream(from);
FileOutputStream out = new FileOutputStream(to)) {
- copy(in, out);
+ return copy(in, out, listener, signal);
}
}
- public static void copy(InputStream in, OutputStream out) throws IOException {
- copy(in, out, null, null);
+ /**
+ * Copy the contents of one stream to another.
+ * <p>
+ * Attempts to use several optimization strategies to copy the data in the
+ * kernel before falling back to a userspace copy as a last resort.
+ *
+ * @return number of bytes copied.
+ */
+ public static long copy(@NonNull InputStream in, @NonNull OutputStream out) throws IOException {
+ return copy(in, out, null, null);
}
- public static void copy(InputStream in, OutputStream out, CopyListener listener,
- CancellationSignal signal) throws IOException {
+ /**
+ * Copy the contents of one stream to another.
+ * <p>
+ * Attempts to use several optimization strategies to copy the data in the
+ * kernel before falling back to a userspace copy as a last resort.
+ *
+ * @param listener to be periodically notified as the copy progresses.
+ * @param signal to signal if the copy should be cancelled early.
+ * @return number of bytes copied.
+ */
+ public static long copy(@NonNull InputStream in, @NonNull OutputStream out,
+ @Nullable ProgressListener listener, @Nullable CancellationSignal signal)
+ throws IOException {
if (ENABLE_COPY_OPTIMIZATIONS) {
if (in instanceof FileInputStream && out instanceof FileOutputStream) {
- copy(((FileInputStream) in).getFD(), ((FileOutputStream) out).getFD(),
+ return copy(((FileInputStream) in).getFD(), ((FileOutputStream) out).getFD(),
listener, signal);
}
}
// Worse case fallback to userspace
- copyInternalUserspace(in, out, listener, signal);
+ return copyInternalUserspace(in, out, listener, signal);
}
- public static void copy(FileDescriptor in, FileDescriptor out) throws IOException {
- copy(in, out, null, null);
+ /**
+ * Copy the contents of one FD to another.
+ * <p>
+ * Attempts to use several optimization strategies to copy the data in the
+ * kernel before falling back to a userspace copy as a last resort.
+ *
+ * @return number of bytes copied.
+ */
+ public static long copy(@NonNull FileDescriptor in, @NonNull FileDescriptor out)
+ throws IOException {
+ return copy(in, out, null, null);
}
- public static void copy(FileDescriptor in, FileDescriptor out, CopyListener listener,
- CancellationSignal signal) throws IOException {
+ /**
+ * Copy the contents of one FD to another.
+ * <p>
+ * Attempts to use several optimization strategies to copy the data in the
+ * kernel before falling back to a userspace copy as a last resort.
+ *
+ * @param listener to be periodically notified as the copy progresses.
+ * @param signal to signal if the copy should be cancelled early.
+ * @return number of bytes copied.
+ */
+ public static long copy(@NonNull FileDescriptor in, @NonNull FileDescriptor out,
+ @Nullable ProgressListener listener, @Nullable CancellationSignal signal)
+ throws IOException {
+ return copy(in, out, listener, signal, Long.MAX_VALUE);
+ }
+
+ /**
+ * Copy the contents of one FD to another.
+ * <p>
+ * Attempts to use several optimization strategies to copy the data in the
+ * kernel before falling back to a userspace copy as a last resort.
+ *
+ * @param listener to be periodically notified as the copy progresses.
+ * @param signal to signal if the copy should be cancelled early.
+ * @param count the number of bytes to copy.
+ * @return number of bytes copied.
+ */
+ public static long copy(@NonNull FileDescriptor in, @NonNull FileDescriptor out,
+ @Nullable ProgressListener listener, @Nullable CancellationSignal signal, long count)
+ throws IOException {
if (ENABLE_COPY_OPTIMIZATIONS) {
try {
final StructStat st_in = Os.fstat(in);
final StructStat st_out = Os.fstat(out);
if (S_ISREG(st_in.st_mode) && S_ISREG(st_out.st_mode)) {
- copyInternalSendfile(in, out, listener, signal);
+ return copyInternalSendfile(in, out, listener, signal, count);
} else if (S_ISFIFO(st_in.st_mode) || S_ISFIFO(st_out.st_mode)) {
- copyInternalSplice(in, out, listener, signal);
+ return copyInternalSplice(in, out, listener, signal, count);
}
} catch (ErrnoException e) {
throw e.rethrowAsIOException();
@@ -300,23 +381,25 @@
}
// Worse case fallback to userspace
- copyInternalUserspace(in, out, listener, signal);
+ return copyInternalUserspace(in, out, listener, signal, count);
}
/**
* Requires one of input or output to be a pipe.
*/
@VisibleForTesting
- public static void copyInternalSplice(FileDescriptor in, FileDescriptor out,
- CopyListener listener, CancellationSignal signal) throws ErrnoException {
+ public static long copyInternalSplice(FileDescriptor in, FileDescriptor out,
+ ProgressListener listener, CancellationSignal signal, long count)
+ throws ErrnoException {
long progress = 0;
long checkpoint = 0;
long t;
- while ((t = Os.splice(in, null, out, null, COPY_CHECKPOINT_BYTES,
+ while ((t = Os.splice(in, null, out, null, Math.min(count, COPY_CHECKPOINT_BYTES),
SPLICE_F_MOVE | SPLICE_F_MORE)) != 0) {
progress += t;
checkpoint += t;
+ count -= t;
if (checkpoint >= COPY_CHECKPOINT_BYTES) {
if (signal != null) {
@@ -328,21 +411,24 @@
checkpoint = 0;
}
}
+ return progress;
}
/**
* Requires both input and output to be a regular file.
*/
@VisibleForTesting
- public static void copyInternalSendfile(FileDescriptor in, FileDescriptor out,
- CopyListener listener, CancellationSignal signal) throws ErrnoException {
+ public static long copyInternalSendfile(FileDescriptor in, FileDescriptor out,
+ ProgressListener listener, CancellationSignal signal, long count)
+ throws ErrnoException {
long progress = 0;
long checkpoint = 0;
long t;
- while ((t = Os.sendfile(out, in, null, COPY_CHECKPOINT_BYTES)) != 0) {
+ while ((t = Os.sendfile(out, in, null, Math.min(count, COPY_CHECKPOINT_BYTES))) != 0) {
progress += t;
checkpoint += t;
+ count -= t;
if (checkpoint >= COPY_CHECKPOINT_BYTES) {
if (signal != null) {
@@ -354,17 +440,24 @@
checkpoint = 0;
}
}
+ return progress;
}
@VisibleForTesting
- public static void copyInternalUserspace(FileDescriptor in, FileDescriptor out,
- CopyListener listener, CancellationSignal signal) throws IOException {
- copyInternalUserspace(new FileInputStream(in), new FileOutputStream(out), listener, signal);
+ public static long copyInternalUserspace(FileDescriptor in, FileDescriptor out,
+ ProgressListener listener, CancellationSignal signal, long count) throws IOException {
+ if (count != Long.MAX_VALUE) {
+ return copyInternalUserspace(new SizedInputStream(new FileInputStream(in), count),
+ new FileOutputStream(out), listener, signal);
+ } else {
+ return copyInternalUserspace(new FileInputStream(in),
+ new FileOutputStream(out), listener, signal);
+ }
}
@VisibleForTesting
- public static void copyInternalUserspace(InputStream in, OutputStream out,
- CopyListener listener, CancellationSignal signal) throws IOException {
+ public static long copyInternalUserspace(InputStream in, OutputStream out,
+ ProgressListener listener, CancellationSignal signal) throws IOException {
long progress = 0;
long checkpoint = 0;
byte[] buffer = new byte[8192];
@@ -386,6 +479,7 @@
checkpoint = 0;
}
}
+ return progress;
}
/**
@@ -997,7 +1091,7 @@
}
}
} catch (IOException | ErrnoException e) {
- throw new RuntimeException(e);
+ // Ignored
} finally {
if (sink) {
SystemClock.sleep(TimeUnit.SECONDS.toMillis(1));
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index b2b43cf..2093cec 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -393,8 +393,9 @@
public static final String DISALLOW_CONFIG_VPN = "no_config_vpn";
/**
- * Specifies if a user is disallowed from configuring location mode. Device owner and profile
- * owners can set this restriction and it only applies on the managed user.
+ * Specifies if a user is disallowed from enabling or disabling location providers. As a
+ * result, user is disallowed from turning on or off location. Device owner and profile owners
+ * can set this restriction and it only applies on the managed user.
*
* <p>In a managed profile, location sharing is forced off when it's off on primary user, so
* user can still turn off location sharing on managed profile when the restriction is set by
@@ -408,11 +409,12 @@
*
* <p>Key for user restrictions.
* <p>Type: Boolean
+ * @see android.location.LocationManager#isProviderEnabled(String)
* @see DevicePolicyManager#addUserRestriction(ComponentName, String)
* @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
* @see #getUserRestrictions()
*/
- public static final String DISALLOW_CONFIG_LOCATION_MODE = "no_config_location_mode";
+ public static final String DISALLOW_CONFIG_LOCATION = "no_config_location";
/**
* Specifies if date, time and timezone configuring is disallowed.
diff --git a/core/java/android/print/PrintFileDocumentAdapter.java b/core/java/android/print/PrintFileDocumentAdapter.java
index 747400d..a5f9305 100644
--- a/core/java/android/print/PrintFileDocumentAdapter.java
+++ b/core/java/android/print/PrintFileDocumentAdapter.java
@@ -21,6 +21,8 @@
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.CancellationSignal.OnCancelListener;
+import android.os.FileUtils;
+import android.os.OperationCanceledException;
import android.os.ParcelFileDescriptor;
import android.util.Log;
@@ -114,28 +116,15 @@
@Override
protected Void doInBackground(Void... params) {
- InputStream in = null;
- OutputStream out = new FileOutputStream(mDestination.getFileDescriptor());
- final byte[] buffer = new byte[8192];
- try {
- in = new FileInputStream(mFile);
- while (true) {
- if (isCancelled()) {
- break;
- }
- final int readByteCount = in.read(buffer);
- if (readByteCount < 0) {
- break;
- }
- out.write(buffer, 0, readByteCount);
- }
- } catch (IOException ioe) {
- Log.e(LOG_TAG, "Error writing data!", ioe);
- mResultCallback.onWriteFailed(mContext.getString(
- R.string.write_fail_reason_cannot_write));
- } finally {
- IoUtils.closeQuietly(in);
- IoUtils.closeQuietly(out);
+ try (InputStream in = new FileInputStream(mFile);
+ OutputStream out = new FileOutputStream(mDestination.getFileDescriptor())) {
+ FileUtils.copy(in, out, null, mCancellationSignal);
+ } catch (OperationCanceledException e) {
+ // Ignored; already handled below
+ } catch (IOException e) {
+ Log.e(LOG_TAG, "Error writing data!", e);
+ mResultCallback.onWriteFailed(mContext.getString(
+ R.string.write_fail_reason_cannot_write));
}
return null;
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ad0ce49..e3b8a109 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9315,17 +9315,6 @@
private static final Validator WIFI_WAKEUP_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
/**
- * Value to specify if Wi-Fi Wakeup is available.
- *
- * Wi-Fi Wakeup will only operate if it's available
- * and {@link #WIFI_WAKEUP_ENABLED} is true.
- *
- * Type: int (0 for false, 1 for true)
- * @hide
- */
- public static final String WIFI_WAKEUP_AVAILABLE = "wifi_wakeup_available";
-
- /**
* Value to specify whether network quality scores and badging should be shown in the UI.
*
* Type: int (0 for false, 1 for true)
@@ -10750,14 +10739,14 @@
public static final String LOW_POWER_MODE = "low_power";
/**
- * Battery level [1-99] at which low power mode automatically turns on.
+ * Battery level [1-100] at which low power mode automatically turns on.
* If 0, it will not automatically turn on.
* @hide
*/
public static final String LOW_POWER_MODE_TRIGGER_LEVEL = "low_power_trigger_level";
private static final Validator LOW_POWER_MODE_TRIGGER_LEVEL_VALIDATOR =
- new SettingsValidators.InclusiveIntegerRangeValidator(0, 99);
+ new SettingsValidators.InclusiveIntegerRangeValidator(0, 100);
/**
* If not 0, the activity manager will aggressively finish activities and
diff --git a/core/java/android/se/omapi/Channel.java b/core/java/android/se/omapi/Channel.java
index f0b9fa2d..65ce67f 100644
--- a/core/java/android/se/omapi/Channel.java
+++ b/core/java/android/se/omapi/Channel.java
@@ -25,6 +25,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.RemoteException;
+import android.os.ServiceSpecificException;
import android.util.Log;
import java.io.IOException;
@@ -168,8 +169,10 @@
throw new IOException("Error in communicating with Secure Element");
}
return response;
- } catch (RemoteException e) {
+ } catch (ServiceSpecificException e) {
throw new IOException(e.getMessage());
+ } catch (RemoteException e) {
+ throw new IllegalStateException(e.getMessage());
}
}
}
@@ -244,8 +247,10 @@
synchronized (mLock) {
return mChannel.selectNext();
}
- } catch (RemoteException e) {
+ } catch (ServiceSpecificException e) {
throw new IOException(e.getMessage());
+ } catch (RemoteException e) {
+ throw new IllegalStateException(e.getMessage());
}
}
}
diff --git a/core/java/android/se/omapi/Reader.java b/core/java/android/se/omapi/Reader.java
index 9f15739..3dec976 100644
--- a/core/java/android/se/omapi/Reader.java
+++ b/core/java/android/se/omapi/Reader.java
@@ -24,6 +24,7 @@
import android.annotation.NonNull;
import android.os.RemoteException;
+import android.os.ServiceSpecificException;
import android.util.Log;
import java.io.IOException;
@@ -45,8 +46,7 @@
private final Object mLock = new Object();
- Reader(SEService service, String name, ISecureElementReader reader) throws
- IOException {
+ Reader(SEService service, String name, ISecureElementReader reader) {
if (reader == null || service == null || name == null) {
throw new IllegalArgumentException("Parameters cannot be null");
}
@@ -96,8 +96,10 @@
ISecureElementSession session;
try {
session = mReader.openSession();
- } catch (RemoteException e) {
+ } catch (ServiceSpecificException e) {
throw new IOException(e.getMessage());
+ } catch (RemoteException e) {
+ throw new IllegalStateException(e.getMessage());
}
if (session == null) {
throw new IOException("service session is null.");
diff --git a/core/java/android/se/omapi/SEService.java b/core/java/android/se/omapi/SEService.java
index 1e37277d..b8937e6 100644
--- a/core/java/android/se/omapi/SEService.java
+++ b/core/java/android/se/omapi/SEService.java
@@ -42,6 +42,23 @@
*/
public class SEService {
+ /**
+ * Error code used with ServiceSpecificException.
+ * Thrown if there was an error communicating with the Secure Element.
+ *
+ * @hide
+ */
+ public static final int IO_ERROR = 1;
+
+ /**
+ * Error code used with ServiceSpecificException.
+ * Thrown if AID cannot be selected or is not available when opening
+ * a logical channel.
+ *
+ * @hide
+ */
+ public static final int NO_SUCH_ELEMENT_ERROR = 2;
+
private static final String TAG = "OMAPI.SEService";
private final Object mLock = new Object();
diff --git a/core/java/android/se/omapi/Session.java b/core/java/android/se/omapi/Session.java
index bb2a032..19a018e 100644
--- a/core/java/android/se/omapi/Session.java
+++ b/core/java/android/se/omapi/Session.java
@@ -25,6 +25,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.RemoteException;
+import android.os.ServiceSpecificException;
import android.util.Log;
import java.io.IOException;
@@ -207,8 +208,16 @@
return null;
}
return new Channel(mService, this, channel);
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == SEService.IO_ERROR) {
+ throw new IOException(e.getMessage());
+ } else if (e.errorCode == SEService.NO_SUCH_ELEMENT_ERROR) {
+ throw new NoSuchElementException(e.getMessage());
+ } else {
+ throw new IllegalStateException(e.getMessage());
+ }
} catch (RemoteException e) {
- throw new IOException(e.getMessage());
+ throw new IllegalStateException(e.getMessage());
}
}
}
@@ -311,8 +320,16 @@
return null;
}
return new Channel(mService, this, channel);
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == SEService.IO_ERROR) {
+ throw new IOException(e.getMessage());
+ } else if (e.errorCode == SEService.NO_SUCH_ELEMENT_ERROR) {
+ throw new NoSuchElementException(e.getMessage());
+ } else {
+ throw new IllegalStateException(e.getMessage());
+ }
} catch (RemoteException e) {
- throw new IOException(e.getMessage());
+ throw new IllegalStateException(e.getMessage());
}
}
}
diff --git a/core/java/android/security/keystore/recovery/RecoveryController.java b/core/java/android/security/keystore/recovery/RecoveryController.java
index 4e4a037..7cd08f7 100644
--- a/core/java/android/security/keystore/recovery/RecoveryController.java
+++ b/core/java/android/security/keystore/recovery/RecoveryController.java
@@ -26,9 +26,13 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
+import android.security.KeyStore;
+import android.security.keystore.AndroidKeyStoreProvider;
import com.android.internal.widget.ILockSettings;
+import java.security.Key;
+import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.List;
@@ -113,9 +117,11 @@
private final ILockSettings mBinder;
+ private final KeyStore mKeyStore;
- private RecoveryController(ILockSettings binder) {
+ private RecoveryController(ILockSettings binder, KeyStore keystore) {
mBinder = binder;
+ mKeyStore = keystore;
}
/**
@@ -133,7 +139,7 @@
public static RecoveryController getInstance(Context context) {
ILockSettings lockSettings =
ILockSettings.Stub.asInterface(ServiceManager.getService("lock_settings"));
- return new RecoveryController(lockSettings);
+ return new RecoveryController(lockSettings, KeyStore.getInstance());
}
/**
@@ -430,6 +436,7 @@
}
/**
+ * Deprecated.
* Generates a AES256/GCM/NoPADDING key called {@code alias} and loads it into the recoverable
* key store. Returns the raw material of the key.
*
@@ -444,7 +451,6 @@
public byte[] generateAndStoreKey(@NonNull String alias, byte[] account)
throws InternalRecoveryServiceException, LockScreenRequiredException {
try {
- // TODO: add account
return mBinder.generateAndStoreKey(alias);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -457,6 +463,72 @@
}
/**
+ * Generates a AES256/GCM/NoPADDING key called {@code alias} and loads it into the recoverable
+ * key store. Returns {@link javax.crypto.SecretKey}.
+ *
+ * @param alias The key alias.
+ * @param account The account associated with the key.
+ * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
+ * service.
+ * @throws LockScreenRequiredException if the user has not set a lock screen. This is required
+ * to generate recoverable keys, as the snapshots are encrypted using a key derived from the
+ * lock screen.
+ * @hide
+ */
+ public Key generateKey(@NonNull String alias, byte[] account)
+ throws InternalRecoveryServiceException, LockScreenRequiredException {
+ // TODO: update RecoverySession.recoverKeys
+ try {
+ String grantAlias = mBinder.generateKey(alias, account);
+ if (grantAlias == null) {
+ return null;
+ }
+ Key result = AndroidKeyStoreProvider.loadAndroidKeyStoreKeyFromKeystore(
+ mKeyStore,
+ grantAlias,
+ KeyStore.UID_SELF);
+ return result;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ } catch (UnrecoverableKeyException e) {
+ throw new InternalRecoveryServiceException("Access to newly generated key failed for");
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ERROR_INSECURE_USER) {
+ throw new LockScreenRequiredException(e.getMessage());
+ }
+ throw wrapUnexpectedServiceSpecificException(e);
+ }
+ }
+
+ /**
+ * Gets a key called {@code alias} from the recoverable key store.
+ *
+ * @param alias The key alias.
+ * @return The key.
+ * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
+ * service.
+ * @throws UnrecoverableKeyException if key is permanently invalidated or not found.
+ * @hide
+ */
+ public @Nullable Key getKey(@NonNull String alias)
+ throws InternalRecoveryServiceException, UnrecoverableKeyException {
+ try {
+ String grantAlias = mBinder.getKey(alias);
+ if (grantAlias == null) {
+ return null;
+ }
+ return AndroidKeyStoreProvider.loadAndroidKeyStoreKeyFromKeystore(
+ mKeyStore,
+ grantAlias,
+ KeyStore.UID_SELF);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ } catch (ServiceSpecificException e) {
+ throw wrapUnexpectedServiceSpecificException(e);
+ }
+ }
+
+ /**
* Removes a key called {@code alias} from the recoverable key store.
*
* @param alias The key alias.
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 23ae4b9..d66322c 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -17,6 +17,7 @@
package android.service.notification;
import android.app.ActivityManager;
+import android.app.AlarmManager;
import android.app.NotificationManager;
import android.app.NotificationManager.Policy;
import android.content.ComponentName;
@@ -1445,4 +1446,99 @@
return !config.allowAlarms && !config.allowMediaSystemOther
&& areAllPriorityOnlyNotificationZenSoundsMuted(config);
}
+
+ /**
+ * Returns a description of the current do not disturb settings from config.
+ * - If turned on manually and end time is known, returns end time.
+ * - If turned on by an automatic rule, returns the automatic rule name.
+ * - If on due to an app, returns the app name.
+ * - If there's a combination of rules/apps that trigger, then shows the one that will
+ * last the longest if applicable.
+ * @return null if do not disturb is off.
+ */
+ public static String getDescription(Context context, boolean zenOn, ZenModeConfig config) {
+ if (!zenOn) {
+ return null;
+ }
+
+ String secondaryText = "";
+ long latestEndTime = -1;
+
+ // DND turned on by manual rule
+ if (config.manualRule != null) {
+ final Uri id = config.manualRule.conditionId;
+ if (config.manualRule.enabler != null) {
+ // app triggered manual rule
+ String appName = getOwnerCaption(context, config.manualRule.enabler);
+ if (!appName.isEmpty()) {
+ secondaryText = appName;
+ }
+ } else {
+ if (id == null) {
+ // Do not disturb manually triggered to remain on forever until turned off
+ // No subtext
+ return null;
+ } else {
+ latestEndTime = tryParseCountdownConditionId(id);
+ if (latestEndTime > 0) {
+ final CharSequence formattedTime = getFormattedTime(context,
+ latestEndTime, isToday(latestEndTime),
+ context.getUserId());
+ secondaryText = context.getString(R.string.zen_mode_until, formattedTime);
+ }
+ }
+ }
+ }
+
+ // DND turned on by an automatic rule
+ for (ZenRule automaticRule : config.automaticRules.values()) {
+ if (automaticRule.isAutomaticActive()) {
+ if (isValidEventConditionId(automaticRule.conditionId)
+ || isValidScheduleConditionId(automaticRule.conditionId)) {
+ // set text if automatic rule end time is the latest active rule end time
+ long endTime = parseAutomaticRuleEndTime(context, automaticRule.conditionId);
+ if (endTime > latestEndTime) {
+ latestEndTime = endTime;
+ secondaryText = automaticRule.name;
+ }
+ } else {
+ // set text if 3rd party rule
+ return automaticRule.name;
+ }
+ }
+ }
+
+ return !secondaryText.equals("") ? secondaryText : null;
+ }
+
+ private static long parseAutomaticRuleEndTime(Context context, Uri id) {
+ if (isValidEventConditionId(id)) {
+ // cannot look up end times for events
+ return Long.MAX_VALUE;
+ }
+
+ if (isValidScheduleConditionId(id)) {
+ ScheduleCalendar schedule = toScheduleCalendar(id);
+ long endTimeMs = schedule.getNextChangeTime(System.currentTimeMillis());
+
+ // check if automatic rule will end on next alarm
+ if (schedule.exitAtAlarm()) {
+ long nextAlarm = getNextAlarm(context);
+ schedule.maybeSetNextAlarm(System.currentTimeMillis(), nextAlarm);
+ if (schedule.shouldExitForAlarm(endTimeMs)) {
+ return nextAlarm;
+ }
+ }
+
+ return endTimeMs;
+ }
+
+ return -1;
+ }
+
+ private static long getNextAlarm(Context context) {
+ final AlarmManager alarms = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+ final AlarmManager.AlarmClockInfo info = alarms.getNextAlarmClock(context.getUserId());
+ return info != null ? info.getTriggerTime() : 0;
+ }
}
diff --git a/core/java/android/util/apk/ApkVerityBuilder.java b/core/java/android/util/apk/ApkVerityBuilder.java
index 4c6e511..a3eeb27 100644
--- a/core/java/android/util/apk/ApkVerityBuilder.java
+++ b/core/java/android/util/apk/ApkVerityBuilder.java
@@ -106,18 +106,22 @@
calculateFsveritySignatureInternal(apk, signatureInfo, null, null, header, extensions);
MessageDigest md = MessageDigest.getInstance(JCA_DIGEST_ALGORITHM);
- md.update(DEFAULT_SALT);
- md.update(verityBlock);
+ md.update(header);
+ md.update(extensions);
md.update(apkDigest);
return md.digest();
}
+ /**
+ * Internal method to generate various parts of FSVerity constructs, including the header,
+ * extensions, Merkle tree, and the tree's root hash. The output buffer is flipped to the
+ * generated data size and is readey for consuming.
+ */
private static void calculateFsveritySignatureInternal(
RandomAccessFile apk, SignatureInfo signatureInfo, ByteBuffer treeOutput,
ByteBuffer rootHashOutput, ByteBuffer headerOutput, ByteBuffer extensionsOutput)
throws IOException, NoSuchAlgorithmException, DigestException {
assertSigningBlockAlignedAndHasFullPages(signatureInfo);
-
long signingBlockSize =
signatureInfo.centralDirOffset - signatureInfo.apkSigningBlockOffset;
long dataSize = apk.length() - signingBlockSize - ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE;
@@ -128,6 +132,7 @@
levelOffset, treeOutput);
if (rootHashOutput != null) {
rootHashOutput.put(apkRootHash);
+ rootHashOutput.flip();
}
}
@@ -333,9 +338,9 @@
buffer.put((byte) 0); // auth block offset, disabled here
buffer.put((byte) 2); // extension count
buffer.put(salt); // salt (8 bytes)
- // skip(buffer, 22); // reserved
+ skip(buffer, 22); // reserved
- buffer.rewind();
+ buffer.flip();
return buffer;
}
@@ -396,12 +401,10 @@
buffer.put((byte) ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE); // length
skip(buffer, 7); // reserved
buffer.putInt(Math.toIntExact(signingBlockOffset)); // databytes
-
- // There are extra kPadding bytes of 0s here, included in the total size field of the
- // extension header. The output ByteBuffer is assumed to be initialized to 0.
+ skip(buffer, kPadding); // padding
}
- buffer.rewind();
+ buffer.flip();
return buffer;
}
diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java
index 3fd4696..8cb46b7 100644
--- a/core/java/android/view/PointerIcon.java
+++ b/core/java/android/view/PointerIcon.java
@@ -23,6 +23,10 @@
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.RectF;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
@@ -396,6 +400,33 @@
return true;
}
+ /**
+ * Get the Bitmap from the Drawable.
+ *
+ * If the Bitmap needed to be scaled up to account for density, BitmapDrawable
+ * handles this at draw time. But this class doesn't actually draw the Bitmap;
+ * it is just a holder for native code to access its SkBitmap. So this needs to
+ * get a version that is scaled to account for density.
+ */
+ private Bitmap getBitmapFromDrawable(BitmapDrawable bitmapDrawable) {
+ Bitmap bitmap = bitmapDrawable.getBitmap();
+ final int scaledWidth = bitmapDrawable.getIntrinsicWidth();
+ final int scaledHeight = bitmapDrawable.getIntrinsicHeight();
+ if (scaledWidth == bitmap.getWidth() && scaledHeight == bitmap.getHeight()) {
+ return bitmap;
+ }
+
+ Rect src = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
+ RectF dst = new RectF(0, 0, scaledWidth, scaledHeight);
+
+ Bitmap scaled = Bitmap.createBitmap(scaledWidth, scaledHeight, bitmap.getConfig());
+ Canvas canvas = new Canvas(scaled);
+ Paint paint = new Paint();
+ paint.setFilterBitmap(true);
+ canvas.drawBitmap(bitmap, src, dst, paint);
+ return scaled;
+ }
+
private void loadResource(Context context, Resources resources, @XmlRes int resourceId) {
final XmlResourceParser parser = resources.getXml(resourceId);
final int bitmapRes;
@@ -452,7 +483,8 @@
+ "is different. All frames should have the exact same size and "
+ "share the same hotspot.");
}
- mBitmapFrames[i - 1] = ((BitmapDrawable)drawableFrame).getBitmap();
+ BitmapDrawable bitmapDrawableFrame = (BitmapDrawable) drawableFrame;
+ mBitmapFrames[i - 1] = getBitmapFromDrawable(bitmapDrawableFrame);
}
}
}
@@ -461,7 +493,8 @@
+ "refer to a bitmap drawable.");
}
- final Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
+ BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
+ final Bitmap bitmap = getBitmapFromDrawable(bitmapDrawable);
validateHotSpot(bitmap, hotSpotX, hotSpotY);
// Set the properties now that we have successfully loaded the icon.
mBitmap = bitmap;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 3cbd275..c3e9e73 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -23689,9 +23689,16 @@
Point shadowTouchPoint = new Point();
shadowBuilder.onProvideShadowMetrics(shadowSize, shadowTouchPoint);
- if ((shadowSize.x <= 0) || (shadowSize.y <= 0)
+ if ((shadowSize.x < 0) || (shadowSize.y < 0)
|| (shadowTouchPoint.x < 0) || (shadowTouchPoint.y < 0)) {
- throw new IllegalStateException("Drag shadow dimensions must be positive");
+ throw new IllegalStateException("Drag shadow dimensions must not be negative");
+ }
+
+ // Create 1x1 surface when zero surface size is specified because SurfaceControl.Builder
+ // does not accept zero size surface.
+ if (shadowSize.x == 0 || shadowSize.y == 0) {
+ shadowSize.x = 1;
+ shadowSize.y = 1;
}
if (ViewDebug.DEBUG_DRAG) {
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 7db5c32..33c9f7a 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -22,6 +22,7 @@
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemService;
+import android.annotation.TestApi;
import android.content.Context;
import android.graphics.Rect;
import android.inputmethodservice.InputMethodService;
@@ -2137,6 +2138,26 @@
}
/**
+ * A test API for CTS to make sure that {@link #showInputMethodPicker()} works as expected.
+ *
+ * <p>When customizing the implementation of {@link #showInputMethodPicker()} API, make sure
+ * that this test API returns when and only while and only while
+ * {@link #showInputMethodPicker()} is showing UI. Otherwise your OS implementation may not
+ * pass CTS.</p>
+ *
+ * @return {@code true} while and only while {@link #showInputMethodPicker()} is showing UI.
+ * @hide
+ */
+ @TestApi
+ public boolean isInputMethodPickerShown() {
+ try {
+ return mService.isInputMethodPickerShownForTest();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Show the settings for enabling subtypes of the specified input method.
* @param imiId An input method, whose subtypes settings will be shown. If imiId is null,
* subtypes of all input methods will be shown.
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 1dc5b44..4b951fa 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -23,10 +23,12 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.ColorStateList;
+import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
+import android.graphics.ImageDecoder;
import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
@@ -53,7 +55,6 @@
import com.android.internal.R;
import java.io.IOException;
-import java.io.InputStream;
/**
* Displays image resources, for example {@link android.graphics.Bitmap}
@@ -946,21 +947,15 @@
}
} else if (ContentResolver.SCHEME_CONTENT.equals(scheme)
|| ContentResolver.SCHEME_FILE.equals(scheme)) {
- InputStream stream = null;
try {
- stream = mContext.getContentResolver().openInputStream(uri);
- return Drawable.createFromResourceStream(sCompatUseCorrectStreamDensity
- ? getResources() : null, null, stream, null);
- } catch (Exception e) {
+ Resources res = sCompatUseCorrectStreamDensity ? getResources() : null;
+ ImageDecoder.Source src = ImageDecoder.createSource(mContext.getContentResolver(),
+ uri, res);
+ return ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
+ decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+ });
+ } catch (IOException e) {
Log.w(LOG_TAG, "Unable to open content: " + uri, e);
- } finally {
- if (stream != null) {
- try {
- stream.close();
- } catch (IOException e) {
- Log.w(LOG_TAG, "Unable to close content: " + uri, e);
- }
- }
}
} else {
return Drawable.createFromPath(uri.toString());
diff --git a/core/java/android/widget/MediaControlView2.java b/core/java/android/widget/MediaControlView2.java
index 5f6d9ce..e58e62f 100644
--- a/core/java/android/widget/MediaControlView2.java
+++ b/core/java/android/widget/MediaControlView2.java
@@ -22,8 +22,8 @@
import android.content.Context;
import android.media.session.MediaController;
import android.media.update.ApiLoader;
-import android.media.update.FrameLayoutHelper;
import android.media.update.MediaControlView2Provider;
+import android.media.update.ViewGroupHelper;
import android.util.AttributeSet;
import java.lang.annotation.Retention;
@@ -61,7 +61,7 @@
* TODO PUBLIC API
* @hide
*/
-public class MediaControlView2 extends FrameLayoutHelper<MediaControlView2Provider> {
+public class MediaControlView2 extends ViewGroupHelper<MediaControlView2Provider> {
/** @hide */
@IntDef({
BUTTON_PLAY_PAUSE,
@@ -155,10 +155,12 @@
public MediaControlView2(@NonNull Context context, @Nullable AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
- super((instance, superProvider) ->
+ super((instance, superProvider, privateProvider) ->
ApiLoader.getProvider(context).createMediaControlView2(
- (MediaControlView2) instance, superProvider),
+ (MediaControlView2) instance, superProvider, privateProvider,
+ attrs, defStyleAttr, defStyleRes),
context, attrs, defStyleAttr, defStyleRes);
+ mProvider.initialize(attrs, defStyleAttr, defStyleRes);
}
/**
@@ -169,13 +171,6 @@
}
/**
- * Returns whether the control view is currently shown or hidden.
- */
- public boolean isShowing() {
- return mProvider.isShowing_impl();
- }
-
- /**
* Changes the visibility state of an individual button. Default value is View.Visible.
*
* @param button the {@code Button} assigned to individual buttons
@@ -223,9 +218,7 @@
}
@Override
- // TODO Move this method to ViewProvider
- public void onVisibilityAggregated(boolean isVisible) {
-
- mProvider.onVisibilityAggregated_impl(isVisible);
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ mProvider.onLayout_impl(changed, l, t, r, b);
}
}
diff --git a/core/java/android/widget/VideoView2.java b/core/java/android/widget/VideoView2.java
index 78ca011..3081180 100644
--- a/core/java/android/widget/VideoView2.java
+++ b/core/java/android/widget/VideoView2.java
@@ -27,8 +27,8 @@
import android.media.session.MediaSession;
import android.media.session.PlaybackState;
import android.media.update.ApiLoader;
-import android.media.update.FrameLayoutHelper;
import android.media.update.VideoView2Provider;
+import android.media.update.ViewGroupHelper;
import android.net.Uri;
import android.os.Bundle;
import android.util.AttributeSet;
@@ -101,7 +101,7 @@
*
* @hide
*/
-public class VideoView2 extends FrameLayoutHelper<VideoView2Provider> {
+public class VideoView2 extends ViewGroupHelper<VideoView2Provider> {
/** @hide */
@IntDef({
VIEW_TYPE_TEXTUREVIEW,
@@ -139,10 +139,12 @@
public VideoView2(
@NonNull Context context, @Nullable AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
- super((instance, superProvider) ->
+ super((instance, superProvider, privateProvider) ->
ApiLoader.getProvider(context).createVideoView2(
- (VideoView2) instance, superProvider, attrs, defStyleAttr, defStyleRes),
+ (VideoView2) instance, superProvider, privateProvider,
+ attrs, defStyleAttr, defStyleRes),
context, attrs, defStyleAttr, defStyleRes);
+ mProvider.initialize(attrs, defStyleAttr, defStyleRes);
}
/**
@@ -487,4 +489,9 @@
*/
void onCustomAction(String action, Bundle extras);
}
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ mProvider.onLayout_impl(changed, l, t, r, b);
+ }
}
diff --git a/core/java/com/android/internal/alsa/AlsaCardsParser.java b/core/java/com/android/internal/alsa/AlsaCardsParser.java
index bb75bf6..fa8db96 100644
--- a/core/java/com/android/internal/alsa/AlsaCardsParser.java
+++ b/core/java/com/android/internal/alsa/AlsaCardsParser.java
@@ -31,7 +31,9 @@
private static final String TAG = "AlsaCardsParser";
protected static final boolean DEBUG = false;
- private static final String kCardsFilePath = "/proc/asound/cards";
+ private static final String kAlsaFolderPath = "/proc/asound";
+ private static final String kCardsFilePath = kAlsaFolderPath + "/cards";
+ private static final String kDeviceAddressPrefix = "/dev/bus/usb/";
private static LineTokenizer mTokenizer = new LineTokenizer(" :[]");
@@ -47,14 +49,31 @@
private static final String TAG = "AlsaCardRecord";
private static final String kUsbCardKeyStr = "at usb-";
- public int mCardNum = -1;
- public String mField1 = "";
- public String mCardName = "";
- public String mCardDescription = "";
- public boolean mIsUsb = false;
+ int mCardNum = -1;
+ String mField1 = "";
+ String mCardName = "";
+ String mCardDescription = "";
+
+ private String mUsbDeviceAddress = null;
public AlsaCardRecord() {}
+ public int getCardNum() {
+ return mCardNum;
+ }
+
+ public String getCardName() {
+ return mCardName;
+ }
+
+ public String getCardDescription() {
+ return mCardDescription;
+ }
+
+ public void setDeviceAddress(String usbDeviceAddress) {
+ mUsbDeviceAddress = usbDeviceAddress;
+ }
+
private boolean parse(String line, int lineIndex) {
int tokenIndex = 0;
int delimIndex = 0;
@@ -87,8 +106,8 @@
tokenIndex = mTokenizer.nextToken(line, 0);
if (tokenIndex != -1) {
int keyIndex = line.indexOf(kUsbCardKeyStr);
- mIsUsb = keyIndex != -1;
- if (mIsUsb) {
+ boolean isUsb = keyIndex != -1;
+ if (isUsb) {
mCardDescription = line.substring(tokenIndex, keyIndex - 1);
}
}
@@ -97,14 +116,18 @@
return true;
}
+ boolean isUsb() {
+ return mUsbDeviceAddress != null;
+ }
+
public String textFormat() {
- return mCardName + " : " + mCardDescription;
+ return mCardName + " : " + mCardDescription + " [addr:" + mUsbDeviceAddress + "]";
}
public void log(int listIndex) {
Slog.d(TAG, "" + listIndex +
" [" + mCardNum + " " + mCardName + " : " + mCardDescription +
- " usb:" + mIsUsb);
+ " usb:" + isUsb());
}
}
@@ -112,7 +135,7 @@
public int scan() {
if (DEBUG) {
- Slog.i(TAG, "AlsaCardsParser.scan()....");
+ Slog.d(TAG, "AlsaCardsParser.scan()....");
}
mCardRecords = new ArrayList<AlsaCardRecord>();
@@ -125,7 +148,7 @@
while ((line = bufferedReader.readLine()) != null) {
AlsaCardRecord cardRecord = new AlsaCardRecord();
if (DEBUG) {
- Slog.i(TAG, " " + line);
+ Slog.d(TAG, " " + line);
}
cardRecord.parse(line, 0);
@@ -134,10 +157,23 @@
break;
}
if (DEBUG) {
- Slog.i(TAG, " " + line);
+ Slog.d(TAG, " " + line);
}
cardRecord.parse(line, 1);
+ // scan "usbbus" file
+ int cardNum = cardRecord.mCardNum;
+ String cardFolderPath = kAlsaFolderPath + "/card" + cardNum;
+ File usbbusFile = new File(cardFolderPath + "/usbbus");
+ if (usbbusFile.exists()) {
+ // read it in
+ FileReader usbbusReader = new FileReader(usbbusFile);
+ String deviceAddress = (new BufferedReader(usbbusReader)).readLine();
+ if (deviceAddress != null) {
+ cardRecord.setDeviceAddress(kDeviceAddressPrefix + deviceAddress);
+ }
+ usbbusReader.close();
+ }
mCardRecords.add(cardRecord);
}
reader.close();
@@ -147,14 +183,12 @@
mScanStatus = SCANSTATUS_EMPTY;
}
} catch (FileNotFoundException e) {
- e.printStackTrace();
mScanStatus = SCANSTATUS_FAIL;
} catch (IOException e) {
- e.printStackTrace();
mScanStatus = SCANSTATUS_FAIL;
}
if (DEBUG) {
- Slog.i(TAG, " status:" + mScanStatus);
+ Slog.d(TAG, " status:" + mScanStatus);
}
return mScanStatus;
}
@@ -163,142 +197,33 @@
return mScanStatus;
}
- public ArrayList<AlsaCardRecord> getScanRecords() {
- return mCardRecords;
- }
-
- public AlsaCardRecord getCardRecordAt(int index) {
- return mCardRecords.get(index);
- }
-
- public AlsaCardRecord getCardRecordFor(int cardNum) {
- for (AlsaCardRecord rec : mCardRecords) {
- if (rec.mCardNum == cardNum) {
- return rec;
+ public AlsaCardRecord findCardNumFor(String deviceAddress) {
+ for(AlsaCardRecord cardRec : mCardRecords) {
+ if (cardRec.isUsb() && cardRec.mUsbDeviceAddress.equals(deviceAddress)) {
+ return cardRec;
}
}
-
return null;
}
- public int getNumCardRecords() {
- return mCardRecords.size();
- }
-
- public boolean isCardUsb(int cardNum) {
- for (AlsaCardRecord rec : mCardRecords) {
- if (rec.mCardNum == cardNum) {
- return rec.mIsUsb;
- }
- }
-
- return false;
- }
-
- // return -1 if none found
- public int getDefaultUsbCard() {
- // save the current list of devices
- ArrayList<AlsaCardsParser.AlsaCardRecord> prevRecs = mCardRecords;
- if (DEBUG) {
- LogDevices("Previous Devices:", prevRecs);
- }
-
- // get the new list of devices
- if (scan() != SCANSTATUS_SUCCESS) {
- Slog.e(TAG, "Error scanning Alsa cards file.");
- return -1;
- }
-
- if (DEBUG) {
- LogDevices("Current Devices:", mCardRecords);
- }
-
- // Calculate the difference between the old and new device list
- ArrayList<AlsaCardRecord> newRecs = getNewCardRecords(prevRecs);
- if (DEBUG) {
- LogDevices("New Devices:", newRecs);
- }
-
- // Choose the most-recently added EXTERNAL card
- // Check recently added devices
- for (AlsaCardRecord rec : newRecs) {
- if (DEBUG) {
- Slog.d(TAG, rec.mCardName + " card:" + rec.mCardNum + " usb:" + rec.mIsUsb);
- }
- if (rec.mIsUsb) {
- // Found it
- return rec.mCardNum;
- }
- }
-
- // or return the first added EXTERNAL card?
- for (AlsaCardRecord rec : prevRecs) {
- if (DEBUG) {
- Slog.d(TAG, rec.mCardName + " card:" + rec.mCardNum + " usb:" + rec.mIsUsb);
- }
- if (rec.mIsUsb) {
- return rec.mCardNum;
- }
- }
-
- return -1;
- }
-
- public int getDefaultCard() {
- // return an external card if possible
- int card = getDefaultUsbCard();
- if (DEBUG) {
- Slog.d(TAG, "getDefaultCard() default usb card:" + card);
- }
-
- if (card < 0 && getNumCardRecords() > 0) {
- // otherwise return the (internal) card with the highest number
- card = getCardRecordAt(getNumCardRecords() - 1).mCardNum;
- }
- if (DEBUG) {
- Slog.d(TAG, " returns card:" + card);
- }
- return card;
- }
-
- static public boolean hasCardNumber(ArrayList<AlsaCardRecord> recs, int cardNum) {
- for (AlsaCardRecord cardRec : recs) {
- if (cardRec.mCardNum == cardNum) {
- return true;
- }
- }
- return false;
- }
-
- public ArrayList<AlsaCardRecord> getNewCardRecords(ArrayList<AlsaCardRecord> prevScanRecs) {
- ArrayList<AlsaCardRecord> newRecs = new ArrayList<AlsaCardRecord>();
- for (AlsaCardRecord rec : mCardRecords) {
- // now scan to see if this card number is in the previous scan list
- if (!hasCardNumber(prevScanRecs, rec.mCardNum)) {
- newRecs.add(rec);
- }
- }
- return newRecs;
- }
-
//
// Logging
//
private void Log(String heading) {
if (DEBUG) {
- Slog.i(TAG, heading);
+ Slog.d(TAG, heading);
for (AlsaCardRecord cardRec : mCardRecords) {
- Slog.i(TAG, cardRec.textFormat());
+ Slog.d(TAG, cardRec.textFormat());
}
}
}
- static private void LogDevices(String caption, ArrayList<AlsaCardRecord> deviceList) {
- Slog.d(TAG, caption + " ----------------");
- int listIndex = 0;
- for (AlsaCardRecord device : deviceList) {
- device.log(listIndex++);
- }
- Slog.d(TAG, "----------------");
- }
+// static private void LogDevices(String caption, ArrayList<AlsaCardRecord> deviceList) {
+// Slog.d(TAG, caption + " ----------------");
+// int listIndex = 0;
+// for (AlsaCardRecord device : deviceList) {
+// device.log(listIndex++);
+// }
+// Slog.d(TAG, caption + "----------------");
+// }
}
diff --git a/core/java/com/android/internal/alsa/AlsaDevicesParser.java b/core/java/com/android/internal/alsa/AlsaDevicesParser.java
index 15261baf..8d92d01 100644
--- a/core/java/com/android/internal/alsa/AlsaDevicesParser.java
+++ b/core/java/com/android/internal/alsa/AlsaDevicesParser.java
@@ -27,6 +27,9 @@
* @hide
* Retrieves information from an ALSA "devices" file.
*/
+/*
+ * NOTE: This class is currently not being used, but may be needed in the future.
+ */
public class AlsaDevicesParser {
private static final String TAG = "AlsaDevicesParser";
protected static final boolean DEBUG = false;
@@ -207,12 +210,6 @@
//
// Predicates
//
-/*
- public boolean hasPlaybackDevices() {
- return mHasPlaybackDevices;
- }
-*/
-
public boolean hasPlaybackDevices(int card) {
for (AlsaDeviceRecord deviceRecord : mDeviceRecords) {
if (deviceRecord.mCardNum == card &&
@@ -224,12 +221,6 @@
return false;
}
-/*
- public boolean hasCaptureDevices() {
- return mHasCaptureDevices;
- }
-*/
-
public boolean hasCaptureDevices(int card) {
for (AlsaDeviceRecord deviceRecord : mDeviceRecords) {
if (deviceRecord.mCardNum == card &&
@@ -241,12 +232,6 @@
return false;
}
-/*
- public boolean hasMIDIDevices() {
- return mHasMIDIDevices;
- }
-*/
-
public boolean hasMIDIDevices(int card) {
for (AlsaDeviceRecord deviceRecord : mDeviceRecords) {
if (deviceRecord.mCardNum == card &&
@@ -280,6 +265,7 @@
if (isLineDeviceRecord(line)) {
AlsaDeviceRecord deviceRecord = new AlsaDeviceRecord();
deviceRecord.parse(line);
+ Slog.i(TAG, deviceRecord.textFormat());
mDeviceRecords.add(deviceRecord);
}
}
diff --git a/core/java/com/android/internal/app/UnlaunchableAppActivity.java b/core/java/com/android/internal/app/UnlaunchableAppActivity.java
index 902c8c1..6f7695c 100644
--- a/core/java/com/android/internal/app/UnlaunchableAppActivity.java
+++ b/core/java/com/android/internal/app/UnlaunchableAppActivity.java
@@ -21,24 +21,15 @@
import android.app.Activity;
import android.app.AlertDialog;
-import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
-import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentSender;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
-import android.text.TextUtils;
import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
import android.view.Window;
-import android.widget.TextView;
import com.android.internal.R;
@@ -85,14 +76,9 @@
return;
}
- View rootView = LayoutInflater.from(this).inflate(R.layout.unlaunchable_app_activity, null);
- TextView titleView = (TextView)rootView.findViewById(R.id.unlaunchable_app_title);
- TextView messageView = (TextView)rootView.findViewById(R.id.unlaunchable_app_message);
- titleView.setText(dialogTitle);
- messageView.setText(dialogMessage);
-
AlertDialog.Builder builder = new AlertDialog.Builder(this)
- .setView(rootView)
+ .setTitle(dialogTitle)
+ .setMessage(dialogMessage)
.setOnDismissListener(this);
if (mReason == UNLAUNCHABLE_REASON_QUIET_MODE) {
builder.setPositiveButton(R.string.work_mode_turn_on, this)
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 39279b5..74802c8 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -583,7 +583,7 @@
installd.dexopt(classPathElement, Process.SYSTEM_UID, packageName,
instructionSet, dexoptNeeded, outputPath, dexFlags, compilerFilter,
uuid, classLoaderContext, seInfo, false /* downgrade */,
- targetSdkVersion, /*profileName*/ null);
+ targetSdkVersion, /*profileName*/ null, /*dexMetadataPath*/ null);
} catch (RemoteException | ServiceSpecificException e) {
// Ignore (but log), we need this on the classpath for fallback mode.
Log.w(TAG, "Failed compiling classpath element for system server: "
diff --git a/core/java/com/android/internal/os/logging/MetricsLoggerWrapper.java b/core/java/com/android/internal/os/logging/MetricsLoggerWrapper.java
index 245a66e..1376687 100644
--- a/core/java/com/android/internal/os/logging/MetricsLoggerWrapper.java
+++ b/core/java/com/android/internal/os/logging/MetricsLoggerWrapper.java
@@ -96,4 +96,14 @@
context.getApplicationInfo().className,
StatsLog.PICTURE_IN_PICTURE_STATE_CHANGED__STATE__EXPANDED_TO_FULL_SCREEN);
}
+
+ public static void logAppOverlayEnter(int uid, String packageName, boolean usingAlertWindow) {
+ StatsLog.write(StatsLog.OVERLAY_STATE_CHANGED, uid, packageName, usingAlertWindow,
+ StatsLog.OVERLAY_STATE_CHANGED__STATE__ENTERED);
+ }
+
+ public static void logAppOverlayExit(int uid, String packageName, boolean usingAlertWindow) {
+ StatsLog.write(StatsLog.OVERLAY_STATE_CHANGED, uid, packageName, usingAlertWindow,
+ StatsLog.OVERLAY_STATE_CHANGED__STATE__EXITED);
+ }
}
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index ebb5f9f..f70d3c2 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -132,6 +132,12 @@
void clickQsTile(in ComponentName tile);
void handleSystemKey(in int key);
+ /**
+ * Methods to show toast messages for screen pinning
+ */
+ void showPinningEnterExitToast(boolean entering);
+ void showPinningEscapeToast();
+
void showShutdownUi(boolean isReboot, String reason);
// Used to show the dialog when FingerprintService starts authentication
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index cb0b53c..adf4287 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -81,6 +81,12 @@
void clickTile(in ComponentName tile);
void handleSystemKey(in int key);
+ /**
+ * Methods to show toast messages for screen pinning
+ */
+ void showPinningEnterExitToast(boolean entering);
+ void showPinningEscapeToast();
+
// Used to show the dialog when FingerprintService starts authentication
void showFingerprintDialog(in Bundle bundle, IFingerprintDialogReceiver receiver);
// Used to hide the dialog when a finger is authenticated
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 5e0a986b..0282286 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -68,6 +68,7 @@
void showInputMethodPickerFromClient(in IInputMethodClient client,
int auxiliarySubtypeMode);
void showInputMethodAndSubtypeEnablerFromClient(in IInputMethodClient client, String topId);
+ boolean isInputMethodPickerShownForTest();
void setInputMethod(in IBinder token, String id);
void setInputMethodAndSubtype(in IBinder token, String id, in InputMethodSubtype subtype);
void hideMySoftInput(in IBinder token, int flags);
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index 5673814..732534c 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -66,6 +66,8 @@
void initRecoveryService(in String rootCertificateAlias, in byte[] signedPublicKeyList);
KeyChainSnapshot getKeyChainSnapshot();
byte[] generateAndStoreKey(String alias);
+ String generateKey(String alias, in byte[] account);
+ String getKey(String alias);
void removeKey(String alias);
void setSnapshotCreatedPendingIntent(in PendingIntent intent);
Map getRecoverySnapshotVersions();
diff --git a/core/java/com/android/server/backup/SliceBackupHelper.java b/core/java/com/android/server/backup/SliceBackupHelper.java
new file mode 100644
index 0000000..8e5a5ee
--- /dev/null
+++ b/core/java/com/android/server/backup/SliceBackupHelper.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.server.backup;
+
+import android.app.backup.BlobBackupHelper;
+import android.app.slice.ISliceManager;
+import android.content.Context;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.util.Log;
+import android.util.Slog;
+
+public class SliceBackupHelper extends BlobBackupHelper {
+ static final String TAG = "SliceBackupHelper";
+ static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ // Current version of the blob schema
+ static final int BLOB_VERSION = 1;
+
+ // Key under which the payload blob is stored
+ static final String KEY_SLICES = "slices";
+
+ public SliceBackupHelper(Context context) {
+ super(BLOB_VERSION, KEY_SLICES);
+ // context is currently unused
+ }
+
+ @Override
+ protected byte[] getBackupPayload(String key) {
+ byte[] newPayload = null;
+ if (KEY_SLICES.equals(key)) {
+ try {
+ ISliceManager sm = ISliceManager.Stub.asInterface(
+ ServiceManager.getService(Context.SLICE_SERVICE));
+ // TODO: http://b/22388012
+ newPayload = sm.getBackupPayload(UserHandle.USER_SYSTEM);
+ } catch (Exception e) {
+ // Treat as no data
+ Slog.e(TAG, "Couldn't communicate with slice manager");
+ newPayload = null;
+ }
+ }
+ return newPayload;
+ }
+
+ @Override
+ protected void applyRestoredPayload(String key, byte[] payload) {
+ if (DEBUG) Slog.v(TAG, "Got restore of " + key);
+
+ if (KEY_SLICES.equals(key)) {
+ try {
+ ISliceManager sm = ISliceManager.Stub.asInterface(
+ ServiceManager.getService(Context.SLICE_SERVICE));
+ // TODO: http://b/22388012
+ sm.applyRestore(payload, UserHandle.USER_SYSTEM);
+ } catch (Exception e) {
+ Slog.e(TAG, "Couldn't communicate with slice manager");
+ }
+ }
+ }
+
+}
diff --git a/core/java/com/android/server/backup/SystemBackupAgent.java b/core/java/com/android/server/backup/SystemBackupAgent.java
index a96b5dd..47e7a0e7 100644
--- a/core/java/com/android/server/backup/SystemBackupAgent.java
+++ b/core/java/com/android/server/backup/SystemBackupAgent.java
@@ -51,6 +51,7 @@
private static final String USAGE_STATS_HELPER = "usage_stats";
private static final String SHORTCUT_MANAGER_HELPER = "shortcut_manager";
private static final String ACCOUNT_MANAGER_HELPER = "account_manager";
+ private static final String SLICES_HELPER = "slices";
// These paths must match what the WallpaperManagerService uses. The leaf *_FILENAME
// are also used in the full-backup file format, so must not change unless steps are
@@ -88,6 +89,7 @@
addHelper(USAGE_STATS_HELPER, new UsageStatsBackupHelper(this));
addHelper(SHORTCUT_MANAGER_HELPER, new ShortcutBackupHelper());
addHelper(ACCOUNT_MANAGER_HELPER, new AccountManagerBackupHelper());
+ addHelper(SLICES_HELPER, new SliceBackupHelper(this));
super.onBackup(oldState, data, newState);
}
@@ -116,6 +118,7 @@
addHelper(USAGE_STATS_HELPER, new UsageStatsBackupHelper(this));
addHelper(SHORTCUT_MANAGER_HELPER, new ShortcutBackupHelper());
addHelper(ACCOUNT_MANAGER_HELPER, new AccountManagerBackupHelper());
+ addHelper(SLICES_HELPER, new SliceBackupHelper(this));
super.onRestore(data, appVersionCode, newState);
}
diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto
index bfd575a..ff0f4fd 100644
--- a/core/proto/android/providers/settings.proto
+++ b/core/proto/android/providers/settings.proto
@@ -208,7 +208,7 @@
optional SettingProto wifi_on = 136 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto wifi_scan_always_available = 137 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto wifi_wakeup_enabled = 138 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto wifi_wakeup_available = 305 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ reserved 305; // Removed wifi_wakeup_available
optional SettingProto network_scoring_ui_enabled = 306 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto speed_label_cache_eviction_age_millis = 307 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto recommended_network_evaluator_cache_expiry_ms = 308 [ (android.privacy).dest = DEST_AUTOMATIC ];
diff --git a/core/proto/android/server/alarmmanagerservice.proto b/core/proto/android/server/alarmmanagerservice.proto
index aa2663f..0342c9c 100644
--- a/core/proto/android/server/alarmmanagerservice.proto
+++ b/core/proto/android/server/alarmmanagerservice.proto
@@ -27,6 +27,7 @@
option java_multiple_files = true;
+// next ID: 43
message AlarmManagerServiceProto {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
@@ -114,7 +115,14 @@
optional int32 uid = 1;
// In the 'elapsed' timebase.
optional int64 time_ms = 2;
+
+ // Time when the next while-idle is allowed, in the 'elapsed' timebase.
+ optional int64 next_allowed_ms = 3;
}
+
+ // Whether the short or long while-idle timeout should be used for each UID.
+ repeated int32 use_allow_while_idle_short_time = 42;
+
// For each uid, this is the last time we dispatched an "allow while idle"
// alarm, used to determine the earliest we can dispatch the next such alarm.
repeated LastAllowWhileIdleDispatch last_allow_while_idle_dispatch_times = 36;
diff --git a/core/proto/android/server/forceappstandbytracker.proto b/core/proto/android/server/forceappstandbytracker.proto
index 43c869c..5296e47 100644
--- a/core/proto/android/server/forceappstandbytracker.proto
+++ b/core/proto/android/server/forceappstandbytracker.proto
@@ -24,14 +24,19 @@
option java_multiple_files = true;
// Dump from com.android.server.ForceAppStandbyTracker.
+//
+// Next ID: 12
message ForceAppStandbyTrackerProto {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
// Whether all apps are forced standby or not.
optional bool force_all_apps_standby = 1;
+ // UIDs currently active.
+ repeated int32 active_uids = 2;
+
// UIDs currently in the foreground.
- repeated int32 foreground_uids = 2;
+ repeated int32 foreground_uids = 11;
// App ids that are in power-save whitelist.
repeated int32 power_save_whitelist_app_ids = 3;
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index c11058a..449e546 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -295,7 +295,6 @@
optional bool animating_exit = 14;
repeated WindowStateProto child_windows = 15;
optional .android.graphics.RectProto surface_position = 16;
- optional .android.graphics.RectProto shown_position = 17;
optional int32 requested_width = 18;
optional int32 requested_height = 19;
optional int32 view_visibility = 20;
diff --git a/core/res/res/layout/unlaunchable_app_activity.xml b/core/res/res/layout/unlaunchable_app_activity.xml
deleted file mode 100644
index 429d5ed..0000000
--- a/core/res/res/layout/unlaunchable_app_activity.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 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.
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:padding="@dimen/dialog_padding"
- android:orientation="vertical">
- <TextView android:id="@+id/unlaunchable_app_title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingStart="@dimen/dialog_padding"
- android:paddingBottom="@dimen/dialog_padding"
- android:textAppearance="@android:style/TextAppearance.Material.Title" />
-
- <TextView android:id="@+id/unlaunchable_app_message"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingStart="@dimen/dialog_padding"
- android:textAppearance="@android:style/TextAppearance.Material.Subhead"
- android:textColor="?android:attr/textColorSecondary" />
-</LinearLayout>
-
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 607414d..05d51ec 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -432,12 +432,6 @@
<!-- Activity name to enable wifi tethering after provisioning app succeeds -->
<string translatable="false" name="config_wifi_tether_enable">com.android.settings/.wifi.tether.TetherService</string>
- <!-- Controls the WiFi wakeup feature.
- 0 = Not available.
- 1 = Available.
- -->
- <integer translatable="false" name="config_wifi_wakeup_available">1</integer>
-
<!-- Array of ConnectivityManager.TYPE_xxxx values allowable for tethering.
Common options are [1, 4] for TYPE_WIFI and TYPE_MOBILE_DUN or
@@ -1132,7 +1126,7 @@
<bool name="config_hotswapCapable">false</bool>
<!-- Component name of the ICC hotswap prompt for restart dialog -->
- <string name="config_iccHotswapPromptForRestartDialogComponent" translateable="false">@null</string>
+ <string name="config_iccHotswapPromptForRestartDialogComponent" translatable="false">@null</string>
<!-- Enable puk unlockscreen by default.
If unlock screen is disabled, the puk should be unlocked through Emergency Dialer -->
@@ -1431,7 +1425,7 @@
permission.
[This is only used if config_enableUpdateableTimeZoneRules and
config_timeZoneRulesUpdateTrackingEnabled are true.] -->
- <string name="config_timeZoneRulesUpdaterPackage" translateable="false">com.android.timezone.updater</string>
+ <string name="config_timeZoneRulesUpdaterPackage" translatable="false">com.android.timezone.updater</string>
<!-- The package of the time zone rules data application. Expected to be configured
by OEMs to reference their own priv-app APK package.
@@ -1440,7 +1434,7 @@
data app packages.
[This is only used if config_enableUpdateableTimeZoneRules and
config_timeZoneRulesUpdateTrackingEnabled are true.] -->
- <string name="config_timeZoneRulesDataPackage" translateable="false"></string>
+ <string name="config_timeZoneRulesDataPackage" translatable="false"></string>
<!-- The allowed time in milliseconds between an update check intent being broadcast and the
response being considered overdue. Reliability triggers will not fire in this time.
@@ -3258,7 +3252,7 @@
<string translatable="false" name="config_deviceSpecificAudioService"></string>
<!-- Component name of media projection permission dialog -->
- <string name="config_mediaProjectionPermissionDialogComponent" translateable="false">com.android.systemui/com.android.systemui.media.MediaProjectionPermissionActivity</string>
+ <string name="config_mediaProjectionPermissionDialogComponent" translatable="false">com.android.systemui/com.android.systemui.media.MediaProjectionPermissionActivity</string>
<!-- Corner radius of system dialogs -->
<dimen name="config_dialogCornerRadius">2dp</dimen>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 224503b..ec81df7 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1351,6 +1351,10 @@
<string name="fingerprint_error_lockout_permanent">Too many attempts. Fingerprint sensor disabled.</string>
<!-- Generic error message shown when the fingerprint hardware can't recognize the fingerprint -->
<string name="fingerprint_error_unable_to_process">Try again.</string>
+ <!-- Generic error message shown when the user has no enrolled fingerprints -->
+ <string name="fingerprint_error_no_fingerprints">No fingerprints enrolled.</string>
+ <!-- Generic error message shown when the app requests fingerprint authentication on a device without a sensor -->
+ <string name="fingerprint_error_hw_not_present">This device does not have a fingerprint sensor</string>
<!-- Template to be used to name enrolled fingerprints by default. -->
<string name="fingerprint_name_template">Finger <xliff:g id="fingerId" example="1">%d</xliff:g></string>
@@ -4423,15 +4427,6 @@
<!-- DO NOT TRANSLATE -->
<string name="date_picker_day_typeface">sans-serif-medium</string>
- <!-- Notify use that they are in Lock-to-app -->
- <string name="lock_to_app_toast">To unpin this screen, touch & hold Back and Overview
- buttons</string>
-
- <!-- Starting lock-to-app indication. -->
- <string name="lock_to_app_start">Screen pinned</string>
- <!-- Exting lock-to-app indication. -->
- <string name="lock_to_app_exit">Screen unpinned</string>
-
<!-- Lock-to-app unlock pin string -->
<string name="lock_to_app_unlock_pin">Ask for PIN before unpinning</string>
<!-- Lock-to-app unlock pattern string -->
@@ -4815,7 +4810,7 @@
A toast message shown when an app shortcut that was restored from a previous device is clicked,
but it cannot be started because the shortcut was created by a newer version of the app.
-->
- <string name="shortcut_restored_on_lower_version">This shortcut requires latest app</string>
+ <string name="shortcut_restored_on_lower_version">App version downgraded, or isn\u2019t compatible with this shortcut</string>
<!--
A toast message shown when an app shortcut that was restored from a previous device is clicked,
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a338f89..2ed94a0 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -767,9 +767,6 @@
<java-symbol type="string" name="kilobyteShort" />
<java-symbol type="string" name="last_month" />
<java-symbol type="string" name="launchBrowserDefault" />
- <java-symbol type="string" name="lock_to_app_toast" />
- <java-symbol type="string" name="lock_to_app_start" />
- <java-symbol type="string" name="lock_to_app_exit" />
<java-symbol type="string" name="lock_to_app_unlock_pin" />
<java-symbol type="string" name="lock_to_app_unlock_pattern" />
<java-symbol type="string" name="lock_to_app_unlock_password" />
@@ -2155,7 +2152,6 @@
<java-symbol type="string" name="config_mobile_hotspot_provision_response" />
<java-symbol type="integer" name="config_mobile_hotspot_provision_check_period" />
<java-symbol type="string" name="config_wifi_tether_enable" />
- <java-symbol type="integer" name="config_wifi_wakeup_available" />
<java-symbol type="bool" name="config_intrusiveNotificationLed" />
<java-symbol type="bool" name="config_notificationBadging" />
<java-symbol type="dimen" name="preference_fragment_padding_bottom" />
@@ -2354,6 +2350,8 @@
<java-symbol type="string" name="fingerprint_error_lockout_permanent" />
<java-symbol type="string" name="fingerprint_name_template" />
<java-symbol type="string" name="fingerprint_not_recognized" />
+ <java-symbol type="string" name="fingerprint_error_no_fingerprints" />
+ <java-symbol type="string" name="fingerprint_error_hw_not_present" />
<!-- Fingerprint config -->
<java-symbol type="integer" name="config_fingerprintMaxTemplatesPerUser"/>
@@ -2702,9 +2700,6 @@
<java-symbol type="string" name="language_selection_title" />
<java-symbol type="string" name="search_language_hint" />
- <java-symbol type="layout" name="unlaunchable_app_activity" />
- <java-symbol type="id" name="unlaunchable_app_title" />
- <java-symbol type="id" name="unlaunchable_app_message" />
<java-symbol type="string" name="work_mode_off_title" />
<java-symbol type="string" name="work_mode_off_message" />
<java-symbol type="string" name="work_mode_turn_on" />
@@ -3153,6 +3148,7 @@
<java-symbol type="integer" name="config_storageManagerDaystoRetainDefault" />
<java-symbol type="string" name="config_headlineFontFamily" />
<java-symbol type="string" name="config_headlineFontFamilyLight" />
+ <java-symbol type="string" name="config_headlineFontFamilyMedium" />
<java-symbol type="drawable" name="stat_sys_vitals" />
diff --git a/core/tests/benchmarks/src/android/os/FileUtilsBenchmark.java b/core/tests/benchmarks/src/android/os/FileUtilsBenchmark.java
index 4f7c924..5989da7 100644
--- a/core/tests/benchmarks/src/android/os/FileUtilsBenchmark.java
+++ b/core/tests/benchmarks/src/android/os/FileUtilsBenchmark.java
@@ -54,7 +54,7 @@
for (int i = 0; i < reps; i++) {
try (FileInputStream in = new FileInputStream(mSrc);
FileOutputStream out = new FileOutputStream(mDest)) {
- copyInternalUserspace(in.getFD(), out.getFD(), null, null);
+ copyInternalUserspace(in.getFD(), out.getFD(), null, null, Long.MAX_VALUE);
}
}
}
@@ -63,7 +63,7 @@
for (int i = 0; i < reps; i++) {
try (FileInputStream in = new FileInputStream(mSrc);
FileOutputStream out = new FileOutputStream(mDest)) {
- copyInternalSendfile(in.getFD(), out.getFD(), null, null);
+ copyInternalSendfile(in.getFD(), out.getFD(), null, null, Long.MAX_VALUE);
}
}
}
@@ -72,7 +72,7 @@
for (int i = 0; i < reps; i++) {
try (MemoryPipe in = MemoryPipe.createSource(mData);
FileOutputStream out = new FileOutputStream(mDest)) {
- copyInternalUserspace(in.getFD(), out.getFD(), null, null);
+ copyInternalUserspace(in.getFD(), out.getFD(), null, null, Long.MAX_VALUE);
}
}
}
@@ -81,7 +81,7 @@
for (int i = 0; i < reps; i++) {
try (MemoryPipe in = MemoryPipe.createSource(mData);
FileOutputStream out = new FileOutputStream(mDest)) {
- copyInternalSplice(in.getFD(), out.getFD(), null, null);
+ copyInternalSplice(in.getFD(), out.getFD(), null, null, Long.MAX_VALUE);
}
}
}
@@ -90,7 +90,7 @@
for (int i = 0; i < reps; i++) {
try (FileInputStream in = new FileInputStream(mSrc);
MemoryPipe out = MemoryPipe.createSink(mData)) {
- copyInternalUserspace(in.getFD(), out.getFD(), null, null);
+ copyInternalUserspace(in.getFD(), out.getFD(), null, null, Long.MAX_VALUE);
}
}
}
@@ -99,7 +99,7 @@
for (int i = 0; i < reps; i++) {
try (FileInputStream in = new FileInputStream(mSrc);
MemoryPipe out = MemoryPipe.createSink(mData)) {
- copyInternalSplice(in.getFD(), out.getFD(), null, null);
+ copyInternalSplice(in.getFD(), out.getFD(), null, null, Long.MAX_VALUE);
}
}
}
diff --git a/core/tests/coretests/src/android/net/UriTest.java b/core/tests/coretests/src/android/net/UriTest.java
index 27b7f9e..ea0347d 100644
--- a/core/tests/coretests/src/android/net/UriTest.java
+++ b/core/tests/coretests/src/android/net/UriTest.java
@@ -192,6 +192,12 @@
assertEquals("a:a@example.com:a@example2.com", uri.getAuthority());
assertEquals("example2.com", uri.getHost());
assertEquals(-1, uri.getPort());
+ assertEquals("/path", uri.getPath());
+
+ uri = Uri.parse("http://a.foo.com\\.example.com/path");
+ assertEquals("a.foo.com", uri.getHost());
+ assertEquals(-1, uri.getPort());
+ assertEquals("\\.example.com/path", uri.getPath());
}
@SmallTest
diff --git a/core/tests/coretests/src/android/os/FileUtilsTest.java b/core/tests/coretests/src/android/os/FileUtilsTest.java
index b7220b3..0bc3a2d 100644
--- a/core/tests/coretests/src/android/os/FileUtilsTest.java
+++ b/core/tests/coretests/src/android/os/FileUtilsTest.java
@@ -181,6 +181,27 @@
}
@Test
+ public void testCopy_ShortPipeToFile() throws Exception {
+ byte[] source = new byte[33_000_000];
+ new Random().nextBytes(source);
+
+ for (int size : DATA_SIZES) {
+ final File dest = new File(mTarget, "dest");
+
+ byte[] expected = Arrays.copyOf(source, size);
+ byte[] actual = new byte[size];
+
+ try (MemoryPipe in = MemoryPipe.createSource(source);
+ FileOutputStream out = new FileOutputStream(dest)) {
+ FileUtils.copy(in.getFD(), out.getFD(), null, null, size);
+ }
+
+ actual = readFile(dest);
+ assertArrayEquals(expected, actual);
+ }
+ }
+
+ @Test
public void testIsFilenameSafe() throws Exception {
assertTrue(FileUtils.isFilenameSafe(new File("foobar")));
assertTrue(FileUtils.isFilenameSafe(new File("a_b-c=d.e/0,1+23")));
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 0083b01..83d0719 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -436,7 +436,6 @@
Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS,
Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED,
Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED,
- Settings.Global.WIFI_WAKEUP_AVAILABLE,
Settings.Global.WIFI_WATCHDOG_ON,
Settings.Global.WIMAX_NETWORKS_AVAILABLE_NOTIFICATION_ON,
Settings.Global.WINDOW_ANIMATION_SCALE,
diff --git a/core/tests/overlaytests/device/Android.mk b/core/tests/overlaytests/device/Android.mk
new file mode 100644
index 0000000..4ca3e4c
--- /dev/null
+++ b/core/tests/overlaytests/device/Android.mk
@@ -0,0 +1,31 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(call all-java-files-under,src)
+LOCAL_MODULE_TAGS := tests
+LOCAL_PACKAGE_NAME := OverlayDeviceTests
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_COMPATIBILITY_SUITE := device-tests
+LOCAL_TARGET_REQUIRED_MODULES := \
+ OverlayDeviceTests_AppOverlayOne \
+ OverlayDeviceTests_AppOverlayTwo \
+ OverlayDeviceTests_FrameworkOverlay
+include $(BUILD_PACKAGE)
+
+# Include to build test-apps.
+include $(call all-makefiles-under,$(LOCAL_PATH))
+
diff --git a/core/tests/overlaytests/device/AndroidManifest.xml b/core/tests/overlaytests/device/AndroidManifest.xml
index e01caee..d14fdf5 100644
--- a/core/tests/overlaytests/device/AndroidManifest.xml
+++ b/core/tests/overlaytests/device/AndroidManifest.xml
@@ -15,15 +15,15 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.om.test">
+ package="com.android.overlaytest">
<uses-sdk android:minSdkVersion="21" />
<application>
- <uses-library android:name="android.test.runner" />
+ <uses-library android:name="android.test.runner"/>
</application>
<instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.server.om.test" />
-
+ android:targetPackage="com.android.overlaytest"
+ android:label="Runtime resource overlay tests" />
</manifest>
diff --git a/core/tests/overlaytests/device/AndroidTest.xml b/core/tests/overlaytests/device/AndroidTest.xml
new file mode 100644
index 0000000..f069835
--- /dev/null
+++ b/core/tests/overlaytests/device/AndroidTest.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<configuration description="Test module config for OverlayDeviceTests">
+ <option name="test-tag" value="OverlayDeviceTests" />
+ <option name="test-suite-tag" value="apct" />
+
+ <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <option name="test-file-name" value="OverlayDeviceTests.apk" />
+ <option name="test-file-name" value="OverlayDeviceTests_AppOverlayOne.apk" />
+ <option name="test-file-name" value="OverlayDeviceTests_AppOverlayTwo.apk" />
+ <option name="test-file-name" value="OverlayDeviceTests_FrameworkOverlay.apk" />
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command"
+ value="cmd overlay disable com.android.overlaytest.framework" />
+ <option name="run-command"
+ value="cmd overlay disable com.android.overlaytest.app_overlay_one" />
+ <option name="run-command"
+ value="cmd overlay disable com.android.overlaytest.app_overlay_two" />
+ <option name="teardown-command"
+ value="cmd overlay disable com.android.overlaytest.framework" />
+ <option name="teardown-command"
+ value="cmd overlay disable com.android.overlaytest.app_overlay_one" />
+ <option name="teardown-command"
+ value="cmd overlay disable com.android.overlaytest.app_overlay_two" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="com.android.overlaytest" />
+ <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+ </test>
+</configuration>
diff --git a/core/tests/overlaytests/device/OverlayAppFiltered/Android.mk b/core/tests/overlaytests/device/OverlayAppFiltered/Android.mk
deleted file mode 100644
index f76de7a..0000000
--- a/core/tests/overlaytests/device/OverlayAppFiltered/Android.mk
+++ /dev/null
@@ -1,10 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SDK_VERSION := system_current
-
-LOCAL_PACKAGE_NAME := com.android.overlaytest.filtered_app_overlay
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/device/OverlayAppFiltered/AndroidManifest.xml b/core/tests/overlaytests/device/OverlayAppFiltered/AndroidManifest.xml
deleted file mode 100644
index 5b7950a..0000000
--- a/core/tests/overlaytests/device/OverlayAppFiltered/AndroidManifest.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.overlaytest.filtered_app_overlay"
- android:versionCode="1"
- android:versionName="1.0">
- <overlay android:targetPackage="com.android.overlaytest"
- android:requiredSystemPropertyName="persist.oem.overlay.test"
- android:requiredSystemPropertyValue="foo"
- android:priority="3"/>
-</manifest>
diff --git a/core/tests/overlaytests/device/OverlayAppFiltered/res/raw/lorem_ipsum.txt b/core/tests/overlaytests/device/OverlayAppFiltered/res/raw/lorem_ipsum.txt
deleted file mode 100644
index 0954ced..0000000
--- a/core/tests/overlaytests/device/OverlayAppFiltered/res/raw/lorem_ipsum.txt
+++ /dev/null
@@ -1 +0,0 @@
-Lorem ipsum: filtered overlays.
diff --git a/core/tests/overlaytests/device/OverlayAppFiltered/res/values/config.xml b/core/tests/overlaytests/device/OverlayAppFiltered/res/values/config.xml
deleted file mode 100644
index 60b94ee..0000000
--- a/core/tests/overlaytests/device/OverlayAppFiltered/res/values/config.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
- <string name="str">filtered</string>
-</resources>
diff --git a/core/tests/overlaytests/device/OverlayAppFiltered/res/xml/integer.xml b/core/tests/overlaytests/device/OverlayAppFiltered/res/xml/integer.xml
deleted file mode 100644
index e2652b7..0000000
--- a/core/tests/overlaytests/device/OverlayAppFiltered/res/xml/integer.xml
+++ /dev/null
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<integer value="3"/>
diff --git a/core/tests/overlaytests/device/OverlayAppFirst/Android.mk b/core/tests/overlaytests/device/OverlayAppFirst/Android.mk
deleted file mode 100644
index bf9416c..0000000
--- a/core/tests/overlaytests/device/OverlayAppFirst/Android.mk
+++ /dev/null
@@ -1,10 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_PACKAGE_NAME := com.android.overlaytest.first_app_overlay
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/device/OverlayAppFirst/AndroidManifest.xml b/core/tests/overlaytests/device/OverlayAppFirst/AndroidManifest.xml
deleted file mode 100644
index ec10bbc..0000000
--- a/core/tests/overlaytests/device/OverlayAppFirst/AndroidManifest.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.overlaytest.first_app_overlay"
- android:versionCode="1"
- android:versionName="1.0">
- <overlay android:targetPackage="com.android.overlaytest" android:priority="1"/>
-</manifest>
diff --git a/core/tests/overlaytests/device/OverlayAppSecond/Android.mk b/core/tests/overlaytests/device/OverlayAppSecond/Android.mk
deleted file mode 100644
index bb7d142..0000000
--- a/core/tests/overlaytests/device/OverlayAppSecond/Android.mk
+++ /dev/null
@@ -1,10 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_PACKAGE_NAME := com.android.overlaytest.second_app_overlay
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/device/OverlayAppSecond/AndroidManifest.xml b/core/tests/overlaytests/device/OverlayAppSecond/AndroidManifest.xml
deleted file mode 100644
index ed49863..0000000
--- a/core/tests/overlaytests/device/OverlayAppSecond/AndroidManifest.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.overlaytest.second_app_overlay"
- android:versionCode="1"
- android:versionName="1.0">
- <overlay android:targetPackage="com.android.overlaytest" android:priority="2"/>
-</manifest>
diff --git a/core/tests/overlaytests/device/OverlayTest/Android.mk b/core/tests/overlaytests/device/OverlayTest/Android.mk
deleted file mode 100644
index 5fe7b91..0000000
--- a/core/tests/overlaytests/device/OverlayTest/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_PACKAGE_NAME := OverlayTest
-
-LOCAL_DEX_PREOPT := false
-
-LOCAL_JAVA_LIBRARIES += android.test.base
-
-LOCAL_MODULE_PATH := $(TARGET_OUT)/app
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/device/OverlayTest/AndroidManifest.xml b/core/tests/overlaytests/device/OverlayTest/AndroidManifest.xml
deleted file mode 100644
index 9edba12..0000000
--- a/core/tests/overlaytests/device/OverlayTest/AndroidManifest.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.overlaytest">
- <uses-permission android:name="android.permission.RUN_INSTRUMENTATION"/>
- <application>
- <uses-library android:name="android.test.runner"/>
- </application>
- <instrumentation android:name="android.test.InstrumentationTestRunner"
- android:targetPackage="com.android.overlaytest"
- android:label="Runtime resource overlay tests"/>
-</manifest>
diff --git a/core/tests/overlaytests/device/OverlayTest/src/com/android/overlaytest/WithMultipleOverlaysTest.java b/core/tests/overlaytests/device/OverlayTest/src/com/android/overlaytest/WithMultipleOverlaysTest.java
deleted file mode 100644
index e104f5a..0000000
--- a/core/tests/overlaytests/device/OverlayTest/src/com/android/overlaytest/WithMultipleOverlaysTest.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.android.overlaytest;
-
-public class WithMultipleOverlaysTest extends OverlayBaseTest {
- public WithMultipleOverlaysTest() {
- mMode = MODE_MULTIPLE_OVERLAYS;
- }
-}
diff --git a/core/tests/overlaytests/device/OverlayTest/src/com/android/overlaytest/WithOverlayTest.java b/core/tests/overlaytests/device/OverlayTest/src/com/android/overlaytest/WithOverlayTest.java
deleted file mode 100644
index 816a476..0000000
--- a/core/tests/overlaytests/device/OverlayTest/src/com/android/overlaytest/WithOverlayTest.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.android.overlaytest;
-
-public class WithOverlayTest extends OverlayBaseTest {
- public WithOverlayTest() {
- mMode = MODE_SINGLE_OVERLAY;
- }
-}
diff --git a/core/tests/overlaytests/device/OverlayTest/src/com/android/overlaytest/WithoutOverlayTest.java b/core/tests/overlaytests/device/OverlayTest/src/com/android/overlaytest/WithoutOverlayTest.java
deleted file mode 100644
index 318cccc..0000000
--- a/core/tests/overlaytests/device/OverlayTest/src/com/android/overlaytest/WithoutOverlayTest.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.android.overlaytest;
-
-public class WithoutOverlayTest extends OverlayBaseTest {
- public WithoutOverlayTest() {
- mMode = MODE_NO_OVERLAY;
- }
-}
diff --git a/core/tests/overlaytests/device/OverlayTestOverlay/Android.mk b/core/tests/overlaytests/device/OverlayTestOverlay/Android.mk
deleted file mode 100644
index ed330467..0000000
--- a/core/tests/overlaytests/device/OverlayTestOverlay/Android.mk
+++ /dev/null
@@ -1,10 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_PACKAGE_NAME := com.android.overlaytest.overlay
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/device/OverlayTestOverlay/AndroidManifest.xml b/core/tests/overlaytests/device/OverlayTestOverlay/AndroidManifest.xml
deleted file mode 100644
index f8b6c7b..0000000
--- a/core/tests/overlaytests/device/OverlayTestOverlay/AndroidManifest.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.overlaytest.overlay"
- android:versionCode="1"
- android:versionName="1.0">
- <overlay android:targetPackage="android" android:priority="1"/>
-</manifest>
diff --git a/core/tests/overlaytests/device/OverlayTest/res/drawable-nodpi/drawable.jpg b/core/tests/overlaytests/device/res/drawable-nodpi/drawable.jpg
similarity index 100%
rename from core/tests/overlaytests/device/OverlayTest/res/drawable-nodpi/drawable.jpg
rename to core/tests/overlaytests/device/res/drawable-nodpi/drawable.jpg
Binary files differ
diff --git a/core/tests/overlaytests/device/OverlayTest/res/raw/lorem_ipsum.txt b/core/tests/overlaytests/device/res/raw/lorem_ipsum.txt
similarity index 100%
rename from core/tests/overlaytests/device/OverlayTest/res/raw/lorem_ipsum.txt
rename to core/tests/overlaytests/device/res/raw/lorem_ipsum.txt
diff --git a/core/tests/overlaytests/device/OverlayTest/res/values-sv/config.xml b/core/tests/overlaytests/device/res/values-sv/config.xml
similarity index 100%
rename from core/tests/overlaytests/device/OverlayTest/res/values-sv/config.xml
rename to core/tests/overlaytests/device/res/values-sv/config.xml
diff --git a/core/tests/overlaytests/device/OverlayTest/res/values/config.xml b/core/tests/overlaytests/device/res/values/config.xml
similarity index 100%
rename from core/tests/overlaytests/device/OverlayTest/res/values/config.xml
rename to core/tests/overlaytests/device/res/values/config.xml
diff --git a/core/tests/overlaytests/device/OverlayTest/res/xml/integer.xml b/core/tests/overlaytests/device/res/xml/integer.xml
similarity index 100%
rename from core/tests/overlaytests/device/OverlayTest/res/xml/integer.xml
rename to core/tests/overlaytests/device/res/xml/integer.xml
diff --git a/core/tests/overlaytests/device/OverlayTest/src/com/android/overlaytest/OverlayBaseTest.java b/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java
similarity index 76%
rename from core/tests/overlaytests/device/OverlayTest/src/com/android/overlaytest/OverlayBaseTest.java
rename to core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java
index e57c55c..96ab977 100644
--- a/core/tests/overlaytests/device/OverlayTest/src/com/android/overlaytest/OverlayBaseTest.java
+++ b/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java
@@ -1,45 +1,80 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.overlaytest;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import android.app.UiAutomation;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
-import android.test.AndroidTestCase;
+import android.os.LocaleList;
+import android.os.ParcelFileDescriptor;
+import android.support.test.InstrumentationRegistry;
import android.util.AttributeSet;
import android.util.Xml;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
import java.util.Locale;
-public abstract class OverlayBaseTest extends AndroidTestCase {
+@Ignore
+public abstract class OverlayBaseTest {
private Resources mResources;
- protected int mMode; // will be set by subclasses
- static final protected int MODE_NO_OVERLAY = 0;
- static final protected int MODE_SINGLE_OVERLAY = 1;
- static final protected int MODE_MULTIPLE_OVERLAYS = 2;
+ private final int mMode;
+ static final int MODE_NO_OVERLAY = 0;
+ static final int MODE_SINGLE_OVERLAY = 1;
+ static final int MODE_MULTIPLE_OVERLAYS = 2;
- protected void setUp() {
- mResources = getContext().getResources();
+ static final String APP_OVERLAY_ONE_PKG = "com.android.overlaytest.app_overlay_one";
+ static final String APP_OVERLAY_TWO_PKG = "com.android.overlaytest.app_overlay_two";
+ static final String FRAMEWORK_OVERLAY_PKG = "com.android.overlaytest.framework";
+
+ protected OverlayBaseTest(int mode) {
+ mMode = mode;
+ }
+
+ @Before
+ public void setUp() {
+ mResources = InstrumentationRegistry.getContext().getResources();
}
private int calculateRawResourceChecksum(int resId) throws Throwable {
- InputStream input = null;
- try {
- input = mResources.openRawResource(resId);
+ try (InputStream input = mResources.openRawResource(resId)) {
int ch, checksum = 0;
while ((ch = input.read()) != -1) {
checksum = (checksum + ch) % 0xffddbb00;
}
return checksum;
- } finally {
- input.close();
}
}
private void setLocale(Locale locale) {
- Locale.setDefault(locale);
+ final LocaleList locales = new LocaleList(locale);
+ LocaleList.setDefault(locales);
Configuration config = new Configuration();
- config.locale = locale;
+ config.setLocales(locales);
mResources.updateConfiguration(config, mResources.getDisplayMetrics());
}
@@ -126,6 +161,7 @@
}
}
+ @Test
public void testFrameworkBooleanOverlay() throws Throwable {
// config_annoy_dianne has the value:
// - true when no overlay exists (MODE_NO_OVERLAY)
@@ -135,6 +171,7 @@
assertResource(resId, true, false, false);
}
+ @Test
public void testBooleanOverlay() throws Throwable {
// usually_false has the value:
// - false when no overlay exists (MODE_NO_OVERLAY)
@@ -144,12 +181,14 @@
assertResource(resId, false, true, false);
}
+ @Test
public void testBoolean() throws Throwable {
// always_true has no overlay
final int resId = R.bool.always_true;
assertResource(resId, true, true, true);
}
+ @Test
public void testIntegerArrayOverlay() throws Throwable {
// fibonacci has values:
// - eight first values of Fibonacci sequence, when no overlay exists (MODE_NO_OVERLAY)
@@ -162,6 +201,7 @@
new int[]{21, 13, 8, 5, 3, 2, 1, 1});
}
+ @Test
public void testIntegerArray() throws Throwable {
// prime_numbers has no overlay
final int resId = R.array.prime_numbers;
@@ -169,6 +209,7 @@
assertResource(resId, expected, expected, expected);
}
+ @Test
public void testDrawable() throws Throwable {
// drawable-nodpi/drawable has overlay (default config)
final int resId = R.drawable.drawable;
@@ -188,16 +229,19 @@
assertEquals(expected, actual);
}
+ @Test
public void testAppString() throws Throwable {
final int resId = R.string.str;
assertResource(resId, "none", "single", "multiple");
}
+ @Test
public void testApp2() throws Throwable {
final int resId = R.string.str2; // only in base package and first app overlay
assertResource(resId, "none", "single", "single");
}
+ @Test
public void testAppXml() throws Throwable {
int expected = getExpected(0, 1, 2);
int actual = -1;
@@ -214,6 +258,7 @@
assertEquals(expected, actual);
}
+ @Test
public void testAppRaw() throws Throwable {
final int resId = R.raw.lorem_ipsum;
@@ -256,10 +301,10 @@
* SLOT PACKAGE CONFIGURATION VALUE
* A target package (default) 100
* B target package -sv 200
- * C OverlayAppFirst (default) 300
- * D OverlayAppFirst -sv 400
- * E OverlayAppSecond (default) 500
- * F OverlayAppSecond -sv 600
+ * C AppOverlayOne (default) 300
+ * D AppOverlayOne -sv 400
+ * E AppOverlayTwo (default) 500
+ * F AppOverlayTwo -sv 600
*
* Example: in testMatrix101110, the base package defines the
* R.integer.matrix101110 resource for the default configuration (value
@@ -269,195 +314,283 @@
* are loaded, the expected value after setting the language to Swedish is
* 400.
*/
+ @Test
public void testMatrix100000() throws Throwable {
final int resId = R.integer.matrix_100000;
setLocale(new Locale("sv", "SE"));
assertResource(resId, 100, 100, 100);
}
+ @Test
public void testMatrix100001() throws Throwable {
final int resId = R.integer.matrix_100001;
setLocale(new Locale("sv", "SE"));
assertResource(resId, 100, 100, 600);
}
+ @Test
public void testMatrix100010() throws Throwable {
final int resId = R.integer.matrix_100010;
setLocale(new Locale("sv", "SE"));
assertResource(resId, 100, 100, 500);
}
+ @Test
public void testMatrix100011() throws Throwable {
final int resId = R.integer.matrix_100011;
setLocale(new Locale("sv", "SE"));
assertResource(resId, 100, 100, 600);
}
+ @Test
public void testMatrix100100() throws Throwable {
final int resId = R.integer.matrix_100100;
setLocale(new Locale("sv", "SE"));
assertResource(resId, 100, 400, 400);
}
+ @Test
public void testMatrix100101() throws Throwable {
final int resId = R.integer.matrix_100101;
setLocale(new Locale("sv", "SE"));
assertResource(resId, 100, 400, 600);
}
+ @Test
public void testMatrix100110() throws Throwable {
final int resId = R.integer.matrix_100110;
setLocale(new Locale("sv", "SE"));
assertResource(resId, 100, 400, 400);
}
+ @Test
public void testMatrix100111() throws Throwable {
final int resId = R.integer.matrix_100111;
setLocale(new Locale("sv", "SE"));
assertResource(resId, 100, 400, 600);
}
+ @Test
public void testMatrix101000() throws Throwable {
final int resId = R.integer.matrix_101000;
setLocale(new Locale("sv", "SE"));
assertResource(resId, 100, 300, 300);
}
+ @Test
public void testMatrix101001() throws Throwable {
final int resId = R.integer.matrix_101001;
setLocale(new Locale("sv", "SE"));
assertResource(resId, 100, 300, 600);
}
+ @Test
public void testMatrix101010() throws Throwable {
final int resId = R.integer.matrix_101010;
setLocale(new Locale("sv", "SE"));
assertResource(resId, 100, 300, 500);
}
+ @Test
public void testMatrix101011() throws Throwable {
final int resId = R.integer.matrix_101011;
setLocale(new Locale("sv", "SE"));
assertResource(resId, 100, 300, 600);
}
+ @Test
public void testMatrix101100() throws Throwable {
final int resId = R.integer.matrix_101100;
setLocale(new Locale("sv", "SE"));
assertResource(resId, 100, 400, 400);
}
+ @Test
public void testMatrix101101() throws Throwable {
final int resId = R.integer.matrix_101101;
setLocale(new Locale("sv", "SE"));
assertResource(resId, 100, 400, 600);
}
+ @Test
public void testMatrix101110() throws Throwable {
final int resId = R.integer.matrix_101110;
setLocale(new Locale("sv", "SE"));
assertResource(resId, 100, 400, 400);
}
+ @Test
public void testMatrix101111() throws Throwable {
final int resId = R.integer.matrix_101111;
setLocale(new Locale("sv", "SE"));
assertResource(resId, 100, 400, 600);
}
+ @Test
public void testMatrix110000() throws Throwable {
final int resId = R.integer.matrix_110000;
setLocale(new Locale("sv", "SE"));
assertResource(resId, 200, 200, 200);
}
+ @Test
public void testMatrix110001() throws Throwable {
final int resId = R.integer.matrix_110001;
setLocale(new Locale("sv", "SE"));
assertResource(resId, 200, 200, 600);
}
+ @Test
public void testMatrix110010() throws Throwable {
final int resId = R.integer.matrix_110010;
setLocale(new Locale("sv", "SE"));
assertResource(resId, 200, 200, 200);
}
+ @Test
public void testMatrix110011() throws Throwable {
final int resId = R.integer.matrix_110011;
setLocale(new Locale("sv", "SE"));
assertResource(resId, 200, 200, 600);
}
+ @Test
public void testMatrix110100() throws Throwable {
final int resId = R.integer.matrix_110100;
setLocale(new Locale("sv", "SE"));
assertResource(resId, 200, 400, 400);
}
+ @Test
public void testMatrix110101() throws Throwable {
final int resId = R.integer.matrix_110101;
setLocale(new Locale("sv", "SE"));
assertResource(resId, 200, 400, 600);
}
+ @Test
public void testMatrix110110() throws Throwable {
final int resId = R.integer.matrix_110110;
setLocale(new Locale("sv", "SE"));
assertResource(resId, 200, 400, 400);
}
+ @Test
public void testMatrix110111() throws Throwable {
final int resId = R.integer.matrix_110111;
setLocale(new Locale("sv", "SE"));
assertResource(resId, 200, 400, 600);
}
+ @Test
public void testMatrix111000() throws Throwable {
final int resId = R.integer.matrix_111000;
setLocale(new Locale("sv", "SE"));
assertResource(resId, 200, 200, 200);
}
+ @Test
public void testMatrix111001() throws Throwable {
final int resId = R.integer.matrix_111001;
setLocale(new Locale("sv", "SE"));
assertResource(resId, 200, 200, 600);
}
+ @Test
public void testMatrix111010() throws Throwable {
final int resId = R.integer.matrix_111010;
setLocale(new Locale("sv", "SE"));
assertResource(resId, 200, 200, 200);
}
+ @Test
public void testMatrix111011() throws Throwable {
final int resId = R.integer.matrix_111011;
setLocale(new Locale("sv", "SE"));
assertResource(resId, 200, 200, 600);
}
+ @Test
public void testMatrix111100() throws Throwable {
final int resId = R.integer.matrix_111100;
setLocale(new Locale("sv", "SE"));
assertResource(resId, 200, 400, 400);
}
+ @Test
public void testMatrix111101() throws Throwable {
final int resId = R.integer.matrix_111101;
setLocale(new Locale("sv", "SE"));
assertResource(resId, 200, 400, 600);
}
+ @Test
public void testMatrix111110() throws Throwable {
final int resId = R.integer.matrix_111110;
setLocale(new Locale("sv", "SE"));
assertResource(resId, 200, 400, 400);
}
+ @Test
public void testMatrix111111() throws Throwable {
final int resId = R.integer.matrix_111111;
setLocale(new Locale("sv", "SE"));
assertResource(resId, 200, 400, 600);
}
+
+ /**
+ * Executes the shell command and reads all the output to ensure the command ran and didn't
+ * get stuck buffering on output.
+ */
+ protected static String executeShellCommand(UiAutomation automation, String command)
+ throws Exception {
+ final ParcelFileDescriptor pfd = automation.executeShellCommand(command);
+ try (InputStream in = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {
+ final BufferedReader reader = new BufferedReader(
+ new InputStreamReader(in, StandardCharsets.UTF_8));
+ StringBuilder str = new StringBuilder();
+ String line;
+ while ((line = reader.readLine()) != null) {
+ str.append(line);
+ }
+ return str.toString();
+ }
+ }
+
+ /**
+ * Enables overlay packages and waits for a configuration change event before
+ * returning, to guarantee that Resources are up-to-date.
+ * @param packages the list of package names to enable.
+ */
+ protected static void enableOverlayPackages(String... packages) throws Exception {
+ enableOverlayPackages(true, packages);
+ }
+
+ /**
+ * Disables overlay packages and waits for a configuration change event before
+ * returning, to guarantee that Resources are up-to-date.
+ * @param packages the list of package names to disable.
+ */
+ protected static void disableOverlayPackages(String... packages) throws Exception {
+ enableOverlayPackages(false, packages);
+ }
+
+ /**
+ * Enables/disables overlay packages and waits for a configuration change event before
+ * returning, to guarantee that Resources are up-to-date.
+ * @param enable enables the overlays when true, disables when false.
+ * @param packages the list of package names to enable/disable.
+ */
+ private static void enableOverlayPackages(boolean enable, String[] packages)
+ throws Exception {
+ final UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation()
+ .getUiAutomation();
+ for (final String pkg : packages) {
+ executeShellCommand(uiAutomation,
+ "cmd overlay " + (enable ? "enable " : "disable ") + pkg);
+ }
+
+ // Wait for the overlay change to propagate.
+ Thread.sleep(1000);
+ }
}
diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/WithMultipleOverlaysTest.java b/core/tests/overlaytests/device/src/com/android/overlaytest/WithMultipleOverlaysTest.java
new file mode 100644
index 0000000..f35e511
--- /dev/null
+++ b/core/tests/overlaytests/device/src/com/android/overlaytest/WithMultipleOverlaysTest.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.overlaytest;
+
+import android.support.test.filters.MediumTest;
+
+import org.junit.BeforeClass;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+@MediumTest
+public class WithMultipleOverlaysTest extends OverlayBaseTest {
+ public WithMultipleOverlaysTest() {
+ super(MODE_MULTIPLE_OVERLAYS);
+ }
+
+ @BeforeClass
+ public static void enableOverlay() throws Exception {
+ enableOverlayPackages(APP_OVERLAY_ONE_PKG, APP_OVERLAY_TWO_PKG, FRAMEWORK_OVERLAY_PKG);
+ }
+}
diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/WithOverlayTest.java b/core/tests/overlaytests/device/src/com/android/overlaytest/WithOverlayTest.java
new file mode 100644
index 0000000..037449f
--- /dev/null
+++ b/core/tests/overlaytests/device/src/com/android/overlaytest/WithOverlayTest.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.overlaytest;
+
+import android.support.test.filters.MediumTest;
+
+import org.junit.BeforeClass;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+@MediumTest
+public class WithOverlayTest extends OverlayBaseTest {
+ public WithOverlayTest() {
+ super(MODE_SINGLE_OVERLAY);
+ }
+
+ @BeforeClass
+ public static void enableOverlay() throws Exception {
+ disableOverlayPackages(APP_OVERLAY_TWO_PKG);
+ enableOverlayPackages(APP_OVERLAY_ONE_PKG, FRAMEWORK_OVERLAY_PKG);
+ }
+}
diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/WithoutOverlayTest.java b/core/tests/overlaytests/device/src/com/android/overlaytest/WithoutOverlayTest.java
new file mode 100644
index 0000000..f657b5c
--- /dev/null
+++ b/core/tests/overlaytests/device/src/com/android/overlaytest/WithoutOverlayTest.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.overlaytest;
+
+import android.support.test.filters.MediumTest;
+
+import org.junit.BeforeClass;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+@MediumTest
+public class WithoutOverlayTest extends OverlayBaseTest {
+ public WithoutOverlayTest() {
+ super(MODE_NO_OVERLAY);
+ }
+
+ @BeforeClass
+ public static void disableOverlays() throws Exception {
+ disableOverlayPackages(APP_OVERLAY_ONE_PKG, APP_OVERLAY_TWO_PKG, FRAMEWORK_OVERLAY_PKG);
+ }
+}
diff --git a/core/tests/overlaytests/device/test-apps/Android.mk b/core/tests/overlaytests/device/test-apps/Android.mk
new file mode 100644
index 0000000..9af9f444
--- /dev/null
+++ b/core/tests/overlaytests/device/test-apps/Android.mk
@@ -0,0 +1,15 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+include $(call all-subdir-makefiles)
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk b/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk
new file mode 100644
index 0000000..17e20ee
--- /dev/null
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk
@@ -0,0 +1,22 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := tests
+LOCAL_PACKAGE_NAME := OverlayDeviceTests_AppOverlayOne
+LOCAL_COMPATIBILITY_SUITE := device-tests
+LOCAL_CERTIFICATE := platform
+include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/AndroidManifest.xml b/core/tests/overlaytests/device/test-apps/AppOverlayOne/AndroidManifest.xml
new file mode 100644
index 0000000..1719158
--- /dev/null
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayOne/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.overlaytest.app_overlay_one"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <overlay android:targetPackage="com.android.overlaytest" android:priority="1" />
+</manifest>
diff --git a/core/tests/overlaytests/device/OverlayAppFirst/res/drawable-nodpi/drawable.jpg b/core/tests/overlaytests/device/test-apps/AppOverlayOne/res/drawable-nodpi/drawable.jpg
similarity index 100%
rename from core/tests/overlaytests/device/OverlayAppFirst/res/drawable-nodpi/drawable.jpg
rename to core/tests/overlaytests/device/test-apps/AppOverlayOne/res/drawable-nodpi/drawable.jpg
Binary files differ
diff --git a/core/tests/overlaytests/device/OverlayAppFirst/res/raw/lorem_ipsum.txt b/core/tests/overlaytests/device/test-apps/AppOverlayOne/res/raw/lorem_ipsum.txt
similarity index 100%
rename from core/tests/overlaytests/device/OverlayAppFirst/res/raw/lorem_ipsum.txt
rename to core/tests/overlaytests/device/test-apps/AppOverlayOne/res/raw/lorem_ipsum.txt
diff --git a/core/tests/overlaytests/device/OverlayAppFirst/res/values-sv/config.xml b/core/tests/overlaytests/device/test-apps/AppOverlayOne/res/values-sv/config.xml
similarity index 100%
rename from core/tests/overlaytests/device/OverlayAppFirst/res/values-sv/config.xml
rename to core/tests/overlaytests/device/test-apps/AppOverlayOne/res/values-sv/config.xml
diff --git a/core/tests/overlaytests/device/OverlayAppFirst/res/values/config.xml b/core/tests/overlaytests/device/test-apps/AppOverlayOne/res/values/config.xml
similarity index 100%
rename from core/tests/overlaytests/device/OverlayAppFirst/res/values/config.xml
rename to core/tests/overlaytests/device/test-apps/AppOverlayOne/res/values/config.xml
diff --git a/core/tests/overlaytests/device/OverlayAppFirst/res/xml/integer.xml b/core/tests/overlaytests/device/test-apps/AppOverlayOne/res/xml/integer.xml
similarity index 100%
rename from core/tests/overlaytests/device/OverlayAppFirst/res/xml/integer.xml
rename to core/tests/overlaytests/device/test-apps/AppOverlayOne/res/xml/integer.xml
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk
new file mode 100644
index 0000000..c24bea9
--- /dev/null
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk
@@ -0,0 +1,22 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := tests
+LOCAL_PACKAGE_NAME := OverlayDeviceTests_AppOverlayTwo
+LOCAL_COMPATIBILITY_SUITE := device-tests
+LOCAL_CERTIFICATE := platform
+include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/AndroidManifest.xml b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/AndroidManifest.xml
new file mode 100644
index 0000000..ae8307c
--- /dev/null
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.overlaytest.app_overlay_two"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <overlay android:targetPackage="com.android.overlaytest" android:priority="2" />
+</manifest>
diff --git a/core/tests/overlaytests/device/OverlayAppSecond/res/raw/lorem_ipsum.txt b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/res/raw/lorem_ipsum.txt
similarity index 100%
rename from core/tests/overlaytests/device/OverlayAppSecond/res/raw/lorem_ipsum.txt
rename to core/tests/overlaytests/device/test-apps/AppOverlayTwo/res/raw/lorem_ipsum.txt
diff --git a/core/tests/overlaytests/device/OverlayAppSecond/res/values-sv/config.xml b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/res/values-sv/config.xml
similarity index 100%
rename from core/tests/overlaytests/device/OverlayAppSecond/res/values-sv/config.xml
rename to core/tests/overlaytests/device/test-apps/AppOverlayTwo/res/values-sv/config.xml
diff --git a/core/tests/overlaytests/device/OverlayAppSecond/res/values/config.xml b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/res/values/config.xml
similarity index 100%
rename from core/tests/overlaytests/device/OverlayAppSecond/res/values/config.xml
rename to core/tests/overlaytests/device/test-apps/AppOverlayTwo/res/values/config.xml
diff --git a/core/tests/overlaytests/device/OverlayAppSecond/res/xml/integer.xml b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/res/xml/integer.xml
similarity index 100%
rename from core/tests/overlaytests/device/OverlayAppSecond/res/xml/integer.xml
rename to core/tests/overlaytests/device/test-apps/AppOverlayTwo/res/xml/integer.xml
diff --git a/core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.mk b/core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.mk
new file mode 100644
index 0000000..dc811c5
--- /dev/null
+++ b/core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.mk
@@ -0,0 +1,22 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := tests
+LOCAL_PACKAGE_NAME := OverlayDeviceTests_FrameworkOverlay
+LOCAL_COMPATIBILITY_SUITE := device-tests
+LOCAL_CERTIFICATE := platform
+include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/device/test-apps/FrameworkOverlay/AndroidManifest.xml b/core/tests/overlaytests/device/test-apps/FrameworkOverlay/AndroidManifest.xml
new file mode 100644
index 0000000..77ea16a
--- /dev/null
+++ b/core/tests/overlaytests/device/test-apps/FrameworkOverlay/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.overlaytest.framework"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <overlay android:targetPackage="android" android:priority="1" />
+</manifest>
diff --git a/core/tests/overlaytests/device/OverlayTestOverlay/res/values/config.xml b/core/tests/overlaytests/device/test-apps/FrameworkOverlay/res/values/config.xml
similarity index 100%
rename from core/tests/overlaytests/device/OverlayTestOverlay/res/values/config.xml
rename to core/tests/overlaytests/device/test-apps/FrameworkOverlay/res/values/config.xml
diff --git a/core/tests/overlaytests/host/test-apps/SignatureOverlay/AndroidManifest.xml b/core/tests/overlaytests/host/test-apps/SignatureOverlay/AndroidManifest.xml
index 2d68439..b08ac96 100644
--- a/core/tests/overlaytests/host/test-apps/SignatureOverlay/AndroidManifest.xml
+++ b/core/tests/overlaytests/host/test-apps/SignatureOverlay/AndroidManifest.xml
@@ -15,6 +15,6 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.om.hosttest.signature_overlay">
+ package="com.android.server.om.hosttest.signature_overlay">
<overlay android:targetPackage="android" />
</manifest>
diff --git a/core/tests/overlaytests/testrunner.py b/core/tests/overlaytests/testrunner.py
deleted file mode 100755
index e88805e..0000000
--- a/core/tests/overlaytests/testrunner.py
+++ /dev/null
@@ -1,732 +0,0 @@
-#!/usr/bin/python
-import hashlib
-import optparse
-import os
-import re
-import shlex
-import subprocess
-import sys
-import threading
-import time
-
-TASK_COMPILATION = 'compile'
-TASK_DISABLE_OVERLAYS = 'disable overlays'
-TASK_ENABLE_MULTIPLE_OVERLAYS = 'enable multiple overlays'
-TASK_ENABLE_SINGLE_OVERLAY = 'enable single overlay'
-TASK_ENABLE_FILTERED_OVERLAYS = 'enable filtered overlays'
-TASK_FILE_EXISTS_TEST = 'test (file exists)'
-TASK_GREP_IDMAP_TEST = 'test (grep idmap)'
-TASK_MD5_TEST = 'test (md5)'
-TASK_IDMAP_PATH = 'idmap --path'
-TASK_IDMAP_SCAN = 'idmap --scan'
-TASK_INSTRUMENTATION = 'instrumentation'
-TASK_INSTRUMENTATION_TEST = 'test (instrumentation)'
-TASK_MKDIR = 'mkdir'
-TASK_PUSH = 'push'
-TASK_ROOT = 'root'
-TASK_REMOUNT = 'remount'
-TASK_RM = 'rm'
-TASK_SETPROP = 'setprop'
-TASK_SETUP_IDMAP_PATH = 'setup idmap --path'
-TASK_SETUP_IDMAP_SCAN = 'setup idmap --scan'
-TASK_START = 'start'
-TASK_STOP = 'stop'
-
-adb = 'adb'
-
-def _adb_shell(cmd):
- argv = shlex.split(adb + " shell '" + cmd + "; echo $?'")
- proc = subprocess.Popen(argv, bufsize=1, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- (stdout, stderr) = proc.communicate()
- (stdout, stderr) = (stdout.replace('\r', ''), stderr.replace('\r', ''))
- tmp = stdout.rsplit('\n', 2)
- if len(tmp) == 2:
- stdout == ''
- returncode = int(tmp[0])
- else:
- stdout = tmp[0] + '\n'
- returncode = int(tmp[1])
- return returncode, stdout, stderr
-
-class VerbosePrinter:
- class Ticker(threading.Thread):
- def _print(self):
- s = '\r' + self.text + '[' + '.' * self.i + ' ' * (4 - self.i) + ']'
- sys.stdout.write(s)
- sys.stdout.flush()
- self.i = (self.i + 1) % 5
-
- def __init__(self, cond_var, text):
- threading.Thread.__init__(self)
- self.text = text
- self.setDaemon(True)
- self.cond_var = cond_var
- self.running = False
- self.i = 0
- self._print()
- self.running = True
-
- def run(self):
- self.cond_var.acquire()
- while True:
- self.cond_var.wait(0.25)
- running = self.running
- if not running:
- break
- self._print()
- self.cond_var.release()
-
- def stop(self):
- self.cond_var.acquire()
- self.running = False
- self.cond_var.notify_all()
- self.cond_var.release()
-
- def _start_ticker(self):
- self.ticker = VerbosePrinter.Ticker(self.cond_var, self.text)
- self.ticker.start()
-
- def _stop_ticker(self):
- self.ticker.stop()
- self.ticker.join()
- self.ticker = None
-
- def _format_begin(self, type, name):
- N = self.width - len(type) - len(' [ ] ')
- fmt = '%%s %%-%ds ' % N
- return fmt % (type, name)
-
- def __init__(self, use_color):
- self.cond_var = threading.Condition()
- self.ticker = None
- if use_color:
- self.color_RED = '\033[1;31m'
- self.color_red = '\033[0;31m'
- self.color_reset = '\033[0;37m'
- else:
- self.color_RED = ''
- self.color_red = ''
- self.color_reset = ''
-
- argv = shlex.split('stty size') # get terminal width
- proc = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- (stdout, stderr) = proc.communicate()
- if proc.returncode == 0:
- (h, w) = stdout.split()
- self.width = int(w)
- else:
- self.width = 72 # conservative guesstimate
-
- def begin(self, type, name):
- self.text = self._format_begin(type, name)
- sys.stdout.write(self.text + '[ ]')
- sys.stdout.flush()
- self._start_ticker()
-
- def end_pass(self, type, name):
- self._stop_ticker()
- sys.stdout.write('\r' + self.text + '[ OK ]\n')
- sys.stdout.flush()
-
- def end_fail(self, type, name, msg):
- self._stop_ticker()
- sys.stdout.write('\r' + self.color_RED + self.text + '[FAIL]\n')
- sys.stdout.write(self.color_red)
- sys.stdout.write(msg)
- sys.stdout.write(self.color_reset)
- sys.stdout.flush()
-
-class QuietPrinter:
- def begin(self, type, name):
- pass
-
- def end_pass(self, type, name):
- sys.stdout.write('PASS ' + type + ' ' + name + '\n')
- sys.stdout.flush()
-
- def end_fail(self, type, name, msg):
- sys.stdout.write('FAIL ' + type + ' ' + name + '\n')
- sys.stdout.flush()
-
-class CompilationTask:
- def __init__(self, makefile):
- self.makefile = makefile
-
- def get_type(self):
- return TASK_COMPILATION
-
- def get_name(self):
- return self.makefile
-
- def execute(self):
- os.putenv('ONE_SHOT_MAKEFILE', os.getcwd() + "/" + self.makefile)
- argv = shlex.split('make -C "../../../../../" files')
- proc = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- (stdout, stderr) = proc.communicate()
- return proc.returncode, stdout, stderr
-
-class InstrumentationTask:
- def __init__(self, instrumentation_class):
- self.instrumentation_class = instrumentation_class
-
- def get_type(self):
- return TASK_INSTRUMENTATION
-
- def get_name(self):
- return self.instrumentation_class
-
- def execute(self):
- return _adb_shell('am instrument -r -w -e class %s com.android.overlaytest/android.test.InstrumentationTestRunner' % self.instrumentation_class)
-
-class PushTask:
- def __init__(self, src, dest):
- self.src = src
- self.dest = dest
-
- def get_type(self):
- return TASK_PUSH
-
- def get_name(self):
- return "%s -> %s" % (self.src, self.dest)
-
- def execute(self):
- src = os.getenv('OUT')
- if (src is None):
- return 1, "", "Unable to proceed - $OUT environment var not set\n"
- src += "/" + self.src
- argv = shlex.split(adb + ' push %s %s' % (src, self.dest))
- proc = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- (stdout, stderr) = proc.communicate()
- return proc.returncode, stdout, stderr
-
-class MkdirTask:
- def __init__(self, path):
- self.path = path
-
- def get_type(self):
- return TASK_MKDIR
-
- def get_name(self):
- return self.path
-
- def execute(self):
- return _adb_shell('mkdir -p %s' % self.path)
-
-class RmTask:
- def __init__(self, path):
- self.path = path
-
- def get_type(self):
- return TASK_RM
-
- def get_name(self):
- return self.path
-
- def execute(self):
- returncode, stdout, stderr = _adb_shell('ls %s' % self.path)
- if returncode != 0 and stderr.endswith(': No such file or directory\n'):
- return 0, "", ""
- return _adb_shell('rm -r %s' % self.path)
-
-class SetPropTask:
- def __init__(self, prop, value):
- self.prop = prop
- self.value = value
-
- def get_type(self):
- return TASK_SETPROP
-
- def get_name(self):
- return self.prop
-
- def execute(self):
- return _adb_shell('setprop %s %s' % (self.prop, self.value))
-
-class IdmapPathTask:
- def __init__(self, path_target_apk, path_overlay_apk, path_idmap):
- self.path_target_apk = path_target_apk
- self.path_overlay_apk = path_overlay_apk
- self.path_idmap = path_idmap
-
- def get_type(self):
- return TASK_IDMAP_PATH
-
- def get_name(self):
- return self.path_idmap
-
- def execute(self):
- return _adb_shell('su system idmap --scan "%s" "%s" "%s" "%s"' % (self.target_pkg_name, self.target_pkg, self.idmap_dir, self.overlay_dir))
-
-class IdmapScanTask:
- def __init__(self, overlay_dir, target_pkg_name, target_pkg, idmap_dir, symlink_dir):
- self.overlay_dir = overlay_dir
- self.target_pkg_name = target_pkg_name
- self.target_pkg = target_pkg
- self.idmap_dir = idmap_dir
- self.symlink_dir = symlink_dir
-
- def get_type(self):
- return TASK_IDMAP_SCAN
-
- def get_name(self):
- return self.target_pkg_name
-
- def execute(self):
- return _adb_shell('su system idmap --scan "%s" "%s" "%s" "%s"' % (self.overlay_dir, self.target_pkg_name, self.target_pkg, self.idmap_dir))
-
-class FileExistsTest:
- def __init__(self, path):
- self.path = path
-
- def get_type(self):
- return TASK_FILE_EXISTS_TEST
-
- def get_name(self):
- return self.path
-
- def execute(self):
- return _adb_shell('ls %s' % self.path)
-
-class GrepIdmapTest:
- def __init__(self, path_idmap, pattern, expected_n):
- self.path_idmap = path_idmap
- self.pattern = pattern
- self.expected_n = expected_n
-
- def get_type(self):
- return TASK_GREP_IDMAP_TEST
-
- def get_name(self):
- return self.pattern
-
- def execute(self):
- returncode, stdout, stderr = _adb_shell('idmap --inspect %s' % self.path_idmap)
- if returncode != 0:
- return returncode, stdout, stderr
- all_matches = re.findall('\s' + self.pattern + '$', stdout, flags=re.MULTILINE)
- if len(all_matches) != self.expected_n:
- return 1, 'pattern=%s idmap=%s expected=%d found=%d\n' % (self.pattern, self.path_idmap, self.expected_n, len(all_matches)), ''
- return 0, "", ""
-
-class Md5Test:
- def __init__(self, path, expected_content):
- self.path = path
- self.expected_md5 = hashlib.md5(expected_content).hexdigest()
-
- def get_type(self):
- return TASK_MD5_TEST
-
- def get_name(self):
- return self.path
-
- def execute(self):
- returncode, stdout, stderr = _adb_shell('md5sum %s' % self.path)
- if returncode != 0:
- return returncode, stdout, stderr
- actual_md5 = stdout.split()[0]
- if actual_md5 != self.expected_md5:
- return 1, 'expected %s, got %s\n' % (self.expected_md5, actual_md5), ''
- return 0, "", ""
-
-class StartTask:
- def get_type(self):
- return TASK_START
-
- def get_name(self):
- return ""
-
- def execute(self):
- (returncode, stdout, stderr) = _adb_shell('start')
- if returncode != 0:
- return returncode, stdout, stderr
-
- while True:
- (returncode, stdout, stderr) = _adb_shell('getprop dev.bootcomplete')
- if returncode != 0:
- return returncode, stdout, stderr
- if stdout.strip() == "1":
- break
- time.sleep(0.5)
-
- return 0, "", ""
-
-class StopTask:
- def get_type(self):
- return TASK_STOP
-
- def get_name(self):
- return ""
-
- def execute(self):
- (returncode, stdout, stderr) = _adb_shell('stop')
- if returncode != 0:
- return returncode, stdout, stderr
- return _adb_shell('setprop dev.bootcomplete 0')
-
-class RootTask:
- def get_type(self):
- return TASK_ROOT
-
- def get_name(self):
- return ""
-
- def execute(self):
- (returncode, stdout, stderr) = _adb_shell('getprop service.adb.root 0')
- if returncode != 0:
- return returncode, stdout, stderr
- if stdout.strip() == '1': # already root
- return 0, "", ""
-
- argv = shlex.split(adb + ' root')
- proc = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- (stdout, stderr) = proc.communicate()
- if proc.returncode != 0:
- return proc.returncode, stdout, stderr
-
- argv = shlex.split(adb + ' wait-for-device')
- proc = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- (stdout, stderr) = proc.communicate()
- return proc.returncode, stdout, stderr
-
-class RemountTask:
- def get_type(self):
- return TASK_REMOUNT
-
- def get_name(self):
- return ""
-
- def execute(self):
- argv = shlex.split(adb + ' remount')
- proc = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- (stdout, stderr) = proc.communicate()
- # adb remount returns 0 even if the operation failed, so check stdout
- if stdout.startswith('remount failed:'):
- return 1, stdout, stderr
- return proc.returncode, stdout, stderr
-
-class CompoundTask:
- def __init__(self, type, tasks):
- self.type = type
- self.tasks = tasks
-
- def get_type(self):
- return self.type
-
- def get_name(self):
- return ""
-
- def execute(self):
- for t in self.tasks:
- (returncode, stdout, stderr) = t.execute()
- if returncode != 0:
- return returncode, stdout, stderr
- return 0, "", ""
-
-def _create_disable_overlays_task():
- tasks = [
- RmTask("/vendor/overlay/framework_a.apk"),
- RmTask("/vendor/overlay/framework_b.apk"),
- RmTask("/data/resource-cache/vendor@overlay@framework_a.apk@idmap"),
- RmTask("/data/resource-cache/vendor@overlay@framework_b.apk@idmap"),
- RmTask("/vendor/overlay/app_a.apk"),
- RmTask("/vendor/overlay/app_b.apk"),
- RmTask("/vendor/overlay/app_c.apk"),
- RmTask("/data/resource-cache/vendor@overlay@app_a.apk@idmap"),
- RmTask("/data/resource-cache/vendor@overlay@app_b.apk@idmap"),
- RmTask("/data/resource-cache/vendor@overlay@app_c.apk@idmap"),
- SetPropTask('persist.oem.overlay.test', '""'),
- RmTask("/data/property/persist.oem.overlay.test"),
- ]
- return CompoundTask(TASK_DISABLE_OVERLAYS, tasks)
-
-def _create_enable_single_overlay_task():
- tasks = [
- _create_disable_overlays_task(),
- MkdirTask('/system/vendor'),
- MkdirTask('/vendor/overlay'),
- PushTask('/data/app/com.android.overlaytest.overlay/com.android.overlaytest.overlay.apk', '/vendor/overlay/framework_a.apk'),
- PushTask('/data/app/com.android.overlaytest.first_app_overlay/com.android.overlaytest.first_app_overlay.apk', '/vendor/overlay/app_a.apk'),
- ]
- return CompoundTask(TASK_ENABLE_SINGLE_OVERLAY, tasks)
-
-def _create_enable_multiple_overlays_task():
- tasks = [
- _create_disable_overlays_task(),
- MkdirTask('/system/vendor'),
- MkdirTask('/vendor/overlay'),
-
- PushTask('/data/app/com.android.overlaytest.overlay/com.android.overlaytest.overlay.apk', '/vendor/overlay/framework_b.apk'),
- PushTask('/data/app/com.android.overlaytest.first_app_overlay/com.android.overlaytest.first_app_overlay.apk', '/vendor/overlay/app_a.apk'),
- PushTask('/data/app/com.android.overlaytest.second_app_overlay/com.android.overlaytest.second_app_overlay.apk', '/vendor/overlay/app_b.apk'),
- PushTask('/data/app/com.android.overlaytest.filtered_app_overlay/com.android.overlaytest.filtered_app_overlay.apk', '/vendor/overlay/app_c.apk'),
- ]
- return CompoundTask(TASK_ENABLE_MULTIPLE_OVERLAYS, tasks)
-
-def _create_enable_filtered_overlays_task():
- tasks = [
- _create_disable_overlays_task(),
- SetPropTask('persist.oem.overlay.test', 'foo'),
- MkdirTask('/system/vendor'),
- MkdirTask('/vendor/overlay'),
- PushTask('/data/app/com.android.overlaytest.overlay/com.android.overlaytest.overlay.apk', '/vendor/overlay/framework_b.apk'),
- PushTask('/data/app/com.android.overlaytest.first_app_overlay/com.android.overlaytest.first_app_overlay.apk', '/vendor/overlay/app_a.apk'),
- PushTask('/data/app/com.android.overlaytest.second_app_overlay/com.android.overlaytest.second_app_overlay.apk', '/vendor/overlay/app_b.apk'),
- PushTask('/data/app/com.android.overlaytest.filtered_app_overlay/com.android.overlaytest.filtered_app_overlay.apk', '/vendor/overlay/app_c.apk'),
- ]
- return CompoundTask(TASK_ENABLE_FILTERED_OVERLAYS, tasks)
-
-def _create_setup_idmap_path_task(idmaps, symlinks):
- tasks = [
- _create_enable_single_overlay_task(),
- RmTask(symlinks),
- RmTask(idmaps),
- MkdirTask(idmaps),
- MkdirTask(symlinks),
- ]
- return CompoundTask(TASK_SETUP_IDMAP_PATH, tasks)
-
-def _create_setup_idmap_scan_task(idmaps, symlinks):
- tasks = [
- _create_enable_filtered_overlays_task(),
- RmTask(symlinks),
- RmTask(idmaps),
- MkdirTask(idmaps),
- MkdirTask(symlinks),
- ]
- return CompoundTask(TASK_SETUP_IDMAP_SCAN, tasks)
-
-def _handle_instrumentation_task_output(stdout, printer):
- regex_status_code = re.compile(r'^INSTRUMENTATION_STATUS_CODE: -?(\d+)')
- regex_name = re.compile(r'^INSTRUMENTATION_STATUS: test=(.*)')
- regex_begin_stack = re.compile(r'^INSTRUMENTATION_STATUS: stack=(.*)')
- regex_end_stack = re.compile(r'^$')
-
- failed_tests = 0
- current_test = None
- current_stack = []
- mode_stack = False
- for line in stdout.split("\n"):
- line = line.rstrip() # strip \r from adb output
- m = regex_status_code.match(line)
- if m:
- c = int(m.group(1))
- if c == 1:
- printer.begin(TASK_INSTRUMENTATION_TEST, current_test)
- elif c == 0:
- printer.end_pass(TASK_INSTRUMENTATION_TEST, current_test)
- else:
- failed_tests += 1
- current_stack.append("\n")
- msg = "\n".join(current_stack)
- printer.end_fail(TASK_INSTRUMENTATION_TEST, current_test, msg.rstrip() + '\n')
- continue
-
- m = regex_name.match(line)
- if m:
- current_test = m.group(1)
- continue
-
- m = regex_begin_stack.match(line)
- if m:
- mode_stack = True
- current_stack = []
- current_stack.append(" " + m.group(1))
- continue
-
- m = regex_end_stack.match(line)
- if m:
- mode_stack = False
- continue
-
- if mode_stack:
- current_stack.append(" " + line.strip())
-
- return failed_tests
-
-def _set_adb_device(option, opt, value, parser):
- global adb
- if opt == '-d' or opt == '--device':
- adb = 'adb -d'
- if opt == '-e' or opt == '--emulator':
- adb = 'adb -e'
- if opt == '-s' or opt == '--serial':
- adb = 'adb -s ' + value
-
-def _create_opt_parser():
- parser = optparse.OptionParser()
- parser.add_option('-d', '--device', action='callback', callback=_set_adb_device,
- help='pass -d to adb')
- parser.add_option('-e', '--emulator', action='callback', callback=_set_adb_device,
- help='pass -e to adb')
- parser.add_option('-s', '--serial', type="str", action='callback', callback=_set_adb_device,
- help='pass -s <serical> to adb')
- parser.add_option('-C', '--no-color', action='store_false',
- dest='use_color', default=True,
- help='disable color escape sequences in output')
- parser.add_option('-q', '--quiet', action='store_true',
- dest='quiet_mode', default=False,
- help='quiet mode, output only results')
- parser.add_option('-b', '--no-build', action='store_false',
- dest='do_build', default=True,
- help='do not rebuild test projects')
- parser.add_option('-k', '--continue', action='store_true',
- dest='do_continue', default=False,
- help='do not rebuild test projects')
- parser.add_option('-i', '--test-idmap', action='store_true',
- dest='test_idmap', default=False,
- help='run tests for idmap')
- parser.add_option('-0', '--test-no-overlay', action='store_true',
- dest='test_no_overlay', default=False,
- help='run tests without any overlay')
- parser.add_option('-1', '--test-single-overlay', action='store_true',
- dest='test_single_overlay', default=False,
- help='run tests for single overlay')
- parser.add_option('-2', '--test-multiple-overlays', action='store_true',
- dest='test_multiple_overlays', default=False,
- help='run tests for multiple overlays')
- parser.add_option('-3', '--test-filtered-overlays', action='store_true',
- dest='test_filtered_overlays', default=False,
- help='run tests for filtered (sys prop) overlays')
- return parser
-
-if __name__ == '__main__':
- opt_parser = _create_opt_parser()
- opts, args = opt_parser.parse_args(sys.argv[1:])
- if not opts.test_idmap and not opts.test_no_overlay and not opts.test_single_overlay and not opts.test_multiple_overlays and not opts.test_filtered_overlays:
- opts.test_idmap = True
- opts.test_no_overlay = True
- opts.test_single_overlay = True
- opts.test_multiple_overlays = True
- opts.test_filtered_overlays = True
-
- if len(args) > 0:
- opt_parser.error("unexpected arguments: %s" % " ".join(args))
- # will never reach this: opt_parser.error will call sys.exit
-
- if opts.quiet_mode:
- printer = QuietPrinter()
- else:
- printer = VerbosePrinter(opts.use_color)
- tasks = []
-
- # must be in the same directory as this script for compilation tasks to work
- script = sys.argv[0]
- dirname = os.path.dirname(script)
- wd = os.path.realpath(dirname)
- os.chdir(wd)
-
- # build test cases
- if opts.do_build:
- tasks.append(CompilationTask('OverlayTest/Android.mk'))
- tasks.append(CompilationTask('OverlayTestOverlay/Android.mk'))
- tasks.append(CompilationTask('OverlayAppFirst/Android.mk'))
- tasks.append(CompilationTask('OverlayAppSecond/Android.mk'))
- tasks.append(CompilationTask('OverlayAppFiltered/Android.mk'))
-
- # remount filesystem, install test project
- tasks.append(RootTask())
- tasks.append(RemountTask())
- tasks.append(PushTask('/system/app/OverlayTest/OverlayTest.apk', '/system/app/OverlayTest.apk'))
-
- # test idmap
- if opts.test_idmap:
- idmaps='/data/local/tmp/idmaps'
- symlinks='/data/local/tmp/symlinks'
-
- # idmap --path
- tasks.append(StopTask())
- tasks.append(_create_setup_idmap_path_task(idmaps, symlinks))
- tasks.append(StartTask())
- tasks.append(IdmapPathTask('/vendor/overlay/framework_a.apk', '/system/framework/framework-res.apk', idmaps + '/a.idmap'))
- tasks.append(FileExistsTest(idmaps + '/a.idmap'))
- tasks.append(GrepIdmapTest(idmaps + '/a.idmap', 'bool/config_annoy_dianne', 1))
-
- # idmap --scan
- tasks.append(StopTask())
- tasks.append(_create_setup_idmap_scan_task(idmaps, symlinks))
- tasks.append(StartTask())
- tasks.append(IdmapScanTask('/vendor/overlay', 'android', '/system/framework/framework-res.apk', idmaps, symlinks))
- tasks.append(FileExistsTest(idmaps + '/vendor@overlay@framework_b.apk@idmap'))
- tasks.append(GrepIdmapTest(idmaps + '/vendor@overlay@framework_b.apk@idmap', 'bool/config_annoy_dianne', 1))
-
-
- # overlays.list
- overlays_list_path = idmaps + '/overlays.list'
- expected_content = '''\
-/vendor/overlay/framework_b.apk /data/local/tmp/idmaps/vendor@overlay@framework_b.apk@idmap
-'''
- tasks.append(FileExistsTest(overlays_list_path))
- tasks.append(Md5Test(overlays_list_path, expected_content))
-
- # idmap cleanup
- tasks.append(RmTask(symlinks))
- tasks.append(RmTask(idmaps))
-
- # test no overlay: all overlays cleared
- if opts.test_no_overlay:
- tasks.append(StopTask())
- tasks.append(_create_disable_overlays_task())
- tasks.append(StartTask())
- tasks.append(InstrumentationTask('com.android.overlaytest.WithoutOverlayTest'))
-
- # test single overlay: one overlay (a)
- if opts.test_single_overlay:
- tasks.append(StopTask())
- tasks.append(_create_enable_single_overlay_task())
- tasks.append(StartTask())
- tasks.append(InstrumentationTask('com.android.overlaytest.WithOverlayTest'))
-
- # test multiple overlays: all overlays - including 'disabled' filtered
- # overlay (system property unset) so expect 'b[p=2]' overrides 'a[p=1]' but
- # 'c[p=3]' should be ignored
- if opts.test_multiple_overlays:
- tasks.append(StopTask())
- tasks.append(_create_enable_multiple_overlays_task())
- tasks.append(StartTask())
- tasks.append(InstrumentationTask('com.android.overlaytest.WithMultipleOverlaysTest'))
-
- # test filtered overlays: all overlays - including 'enabled' filtered
- # overlay (system property set/matched) so expect c[p=3] to override both a
- # & b where applicable
- if opts.test_filtered_overlays:
- tasks.append(StopTask())
- tasks.append(_create_enable_filtered_overlays_task())
- tasks.append(StartTask())
- tasks.append(InstrumentationTask('com.android.overlaytest.WithFilteredOverlaysTest'))
-
- ignored_errors = 0
- for t in tasks:
- type = t.get_type()
- name = t.get_name()
- if type == TASK_INSTRUMENTATION:
- # InstrumentationTask will run several tests, but we want it
- # to appear as if each test was run individually. Calling
- # "am instrument" with a single test method is prohibitively
- # expensive, so let's instead post-process the output to
- # emulate individual calls.
- retcode, stdout, stderr = t.execute()
- if retcode != 0:
- printer.begin(TASK_INSTRUMENTATION, name)
- printer.end_fail(TASK_INSTRUMENTATION, name, stderr)
- sys.exit(retcode)
- retcode = _handle_instrumentation_task_output(stdout, printer)
- if retcode != 0:
- if not opts.do_continue:
- sys.exit(retcode)
- else:
- ignored_errors += retcode
- else:
- printer.begin(type, name)
- retcode, stdout, stderr = t.execute()
- if retcode == 0:
- printer.end_pass(type, name)
- if retcode != 0:
- if len(stderr) == 0:
- # hope for output from stdout instead (true for eg adb shell rm)
- stderr = stdout
- printer.end_fail(type, name, stderr)
- if not opts.do_continue:
- sys.exit(retcode)
- else:
- ignored_errors += retcode
- sys.exit(ignored_errors)
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 773d4d3..bb9b89b 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -158,6 +158,7 @@
<permission name="android.permission.LOCAL_MAC_ADDRESS"/>
<permission name="android.permission.MANAGE_USERS"/>
<permission name="android.permission.MODIFY_PHONE_STATE"/>
+ <permission name="android.permission.PACKAGE_USAGE_STATS"/>
<permission name="android.permission.PERFORM_CDMA_PROVISIONING"/>
<permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/>
<permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
@@ -228,6 +229,7 @@
<permission name="android.permission.CALL_PRIVILEGED"/>
<permission name="android.permission.INTERACT_ACROSS_USERS"/>
<permission name="android.permission.MANAGE_USERS"/>
+ <permission name="android.permission.MODIFY_AUDIO_ROUTING" />
<permission name="android.permission.MODIFY_PHONE_STATE"/>
<permission name="android.permission.STOP_APP_SWITCHES"/>
<permission name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"/>
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index dad24da..22867df 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -333,6 +333,9 @@
<family lang="und-Cari">
<font weight="400" style="normal">NotoSansCarian-Regular.ttf</font>
</family>
+ <family lang="und-Cakm">
+ <font weight="400" style="normal">NotoSansChakma-Regular.ttf</font>
+ </family>
<family lang="und-Cher">
<font weight="400" style="normal">NotoSansCherokee-Regular.ttf</font>
</family>
@@ -429,6 +432,9 @@
<family lang="und-Orkh">
<font weight="400" style="normal">NotoSansOldTurkic-Regular.ttf</font>
</family>
+ <family lang="und-Osge">
+ <font weight="400" style="normal">NotoSansOsage-Regular.ttf</font>
+ </family>
<family lang="und-Osma">
<font weight="400" style="normal">NotoSansOsmanya-Regular.ttf</font>
</family>
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index bbf2145..acefead 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -74,7 +74,7 @@
int getDensity() { return Bitmap.DENSITY_NONE; }
/* @hide */
- int computeDstDensity() {
+ final int computeDstDensity() {
Resources res = getResources();
if (res == null) {
return Bitmap.getDefaultDensity();
@@ -122,13 +122,19 @@
}
private static class ContentResolverSource extends Source {
- ContentResolverSource(@NonNull ContentResolver resolver, @NonNull Uri uri) {
+ ContentResolverSource(@NonNull ContentResolver resolver, @NonNull Uri uri,
+ @Nullable Resources res) {
mResolver = resolver;
mUri = uri;
+ mResources = res;
}
private final ContentResolver mResolver;
private final Uri mUri;
+ private final Resources mResources;
+
+ @Nullable
+ Resources getResources() { return mResources; }
@Override
public ImageDecoder createImageDecoder() throws IOException {
@@ -438,6 +444,7 @@
private boolean mPreferRamOverQuality = false;
private boolean mAsAlphaMask = false;
private Rect mCropRect;
+ private Rect mOutPaddingRect;
private Source mSource;
private PostProcessor mPostProcessor;
@@ -511,7 +518,18 @@
@NonNull
public static Source createSource(@NonNull ContentResolver cr,
@NonNull Uri uri) {
- return new ContentResolverSource(cr, uri);
+ return new ContentResolverSource(cr, uri, null);
+ }
+
+ /**
+ * Provide Resources for density scaling.
+ *
+ * @hide
+ */
+ @NonNull
+ public static Source createSource(@NonNull ContentResolver cr,
+ @NonNull Uri uri, @Nullable Resources res) {
+ return new ContentResolverSource(cr, uri, res);
}
/**
@@ -765,6 +783,18 @@
}
/**
+ * Set a Rect for retrieving nine patch padding.
+ *
+ * If the image is a nine patch, this Rect will be set to the padding
+ * rectangle during decode. Otherwise it will not be modified.
+ *
+ * @hide
+ */
+ public void setOutPaddingRect(@NonNull Rect outPadding) {
+ mOutPaddingRect = outPadding;
+ }
+
+ /**
* Specify whether the {@link Bitmap} should be mutable.
*
* <p>By default, a {@link Bitmap} created will be immutable, but that can
@@ -875,7 +905,6 @@
postProcessPtr, mDesiredWidth, mDesiredHeight, mCropRect,
mMutable, mAllocator, mRequireUnpremultiplied,
mPreferRamOverQuality, mAsAlphaMask);
-
}
private void callHeaderDecoded(@Nullable OnHeaderDecodedListener listener,
@@ -948,7 +977,10 @@
if (np != null && NinePatch.isNinePatchChunk(np)) {
Rect opticalInsets = new Rect();
bm.getOpticalInsets(opticalInsets);
- Rect padding = new Rect();
+ Rect padding = decoder.mOutPaddingRect;
+ if (padding == null) {
+ padding = new Rect();
+ }
nGetPadding(decoder.mNativePtr, padding);
return new NinePatchDrawable(res, bm, np, padding,
opticalInsets, null);
@@ -991,6 +1023,15 @@
final int srcDensity = computeDensity(src, decoder);
Bitmap bm = decoder.decodeBitmap();
bm.setDensity(srcDensity);
+
+ Rect padding = decoder.mOutPaddingRect;
+ if (padding != null) {
+ byte[] np = bm.getNinePatchChunk();
+ if (np != null && NinePatch.isNinePatchChunk(np)) {
+ nGetPadding(decoder.mNativePtr, padding);
+ }
+ }
+
return bm;
}
}
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index 7ad062a..44b783b 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -27,6 +27,7 @@
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
+import android.graphics.ImageDecoder;
import android.graphics.Insets;
import android.graphics.Matrix;
import android.graphics.Outline;
@@ -49,6 +50,7 @@
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -111,7 +113,7 @@
*/
@Deprecated
public BitmapDrawable() {
- mBitmapState = new BitmapState((Bitmap) null);
+ init(new BitmapState((Bitmap) null), null);
}
/**
@@ -124,8 +126,7 @@
@SuppressWarnings("unused")
@Deprecated
public BitmapDrawable(Resources res) {
- mBitmapState = new BitmapState((Bitmap) null);
- mBitmapState.mTargetDensity = mTargetDensity;
+ init(new BitmapState((Bitmap) null), res);
}
/**
@@ -135,7 +136,7 @@
*/
@Deprecated
public BitmapDrawable(Bitmap bitmap) {
- this(new BitmapState(bitmap), null);
+ init(new BitmapState(bitmap), null);
}
/**
@@ -143,8 +144,7 @@
* the display metrics of the resources.
*/
public BitmapDrawable(Resources res, Bitmap bitmap) {
- this(new BitmapState(bitmap), res);
- mBitmapState.mTargetDensity = mTargetDensity;
+ init(new BitmapState(bitmap), res);
}
/**
@@ -154,10 +154,7 @@
*/
@Deprecated
public BitmapDrawable(String filepath) {
- this(new BitmapState(BitmapFactory.decodeFile(filepath)), null);
- if (mBitmapState.mBitmap == null) {
- android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
- }
+ this(null, filepath);
}
/**
@@ -165,10 +162,21 @@
*/
@SuppressWarnings({ "unused", "ChainingConstructorIgnoresParameter" })
public BitmapDrawable(Resources res, String filepath) {
- this(new BitmapState(BitmapFactory.decodeFile(filepath)), null);
- mBitmapState.mTargetDensity = mTargetDensity;
- if (mBitmapState.mBitmap == null) {
- android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
+ Bitmap bitmap = null;
+ try (FileInputStream stream = new FileInputStream(filepath)) {
+ bitmap = ImageDecoder.decodeBitmap(ImageDecoder.createSource(res, stream),
+ (decoder, info, src) -> {
+ decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+ });
+ } catch (Exception e) {
+ /* do nothing. This matches the behavior of BitmapFactory.decodeFile()
+ If the exception happened on decode, mBitmapState.mBitmap will be null.
+ */
+ } finally {
+ init(new BitmapState(bitmap), res);
+ if (mBitmapState.mBitmap == null) {
+ android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
+ }
}
}
@@ -179,10 +187,7 @@
*/
@Deprecated
public BitmapDrawable(java.io.InputStream is) {
- this(new BitmapState(BitmapFactory.decodeStream(is)), null);
- if (mBitmapState.mBitmap == null) {
- android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
- }
+ this(null, is);
}
/**
@@ -190,10 +195,21 @@
*/
@SuppressWarnings({ "unused", "ChainingConstructorIgnoresParameter" })
public BitmapDrawable(Resources res, java.io.InputStream is) {
- this(new BitmapState(BitmapFactory.decodeStream(is)), null);
- mBitmapState.mTargetDensity = mTargetDensity;
- if (mBitmapState.mBitmap == null) {
- android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
+ Bitmap bitmap = null;
+ try {
+ bitmap = ImageDecoder.decodeBitmap(ImageDecoder.createSource(res, is),
+ (decoder, info, src) -> {
+ decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+ });
+ } catch (Exception e) {
+ /* do nothing. This matches the behavior of BitmapFactory.decodeStream()
+ If the exception happened on decode, mBitmapState.mBitmap will be null.
+ */
+ } finally {
+ init(new BitmapState(bitmap), res);
+ if (mBitmapState.mBitmap == null) {
+ android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
+ }
}
}
@@ -812,9 +828,19 @@
}
}
+ int density = Bitmap.DENSITY_NONE;
+ if (value.density == TypedValue.DENSITY_DEFAULT) {
+ density = DisplayMetrics.DENSITY_DEFAULT;
+ } else if (value.density != TypedValue.DENSITY_NONE) {
+ density = value.density;
+ }
+
Bitmap bitmap = null;
try (InputStream is = r.openRawResource(srcResId, value)) {
- bitmap = BitmapFactory.decodeResourceStream(r, value, is, null, null);
+ ImageDecoder.Source source = ImageDecoder.createSource(r, is, density);
+ bitmap = ImageDecoder.decodeBitmap(source, (decoder, info, src) -> {
+ decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+ });
} catch (Exception e) {
// Do nothing and pick up the error below.
}
@@ -1013,14 +1039,21 @@
}
}
+ private BitmapDrawable(BitmapState state, Resources res) {
+ init(state, res);
+ }
+
/**
- * The one constructor to rule them all. This is called by all public
+ * The one helper to rule them all. This is called by all public & private
* constructors to set the state and initialize local properties.
*/
- private BitmapDrawable(BitmapState state, Resources res) {
+ private void init(BitmapState state, Resources res) {
mBitmapState = state;
-
updateLocalState(res);
+
+ if (mBitmapState != null && res != null) {
+ mBitmapState.mTargetDensity = mTargetDensity;
+ }
}
/**
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index f17cd76..36a4d26 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -37,6 +37,7 @@
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
+import android.graphics.ImageDecoder;
import android.graphics.Insets;
import android.graphics.NinePatch;
import android.graphics.Outline;
@@ -50,11 +51,13 @@
import android.os.Trace;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
+import android.util.Log;
import android.util.StateSet;
import android.util.TypedValue;
import android.util.Xml;
import android.view.View;
+import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
@@ -1175,6 +1178,10 @@
return null;
}
+ if (opts == null) {
+ return getBitmapDrawable(res, value, is);
+ }
+
/* ugh. The decodeStream contract is that we have already allocated
the pad rect, but if the bitmap does not had a ninepatch chunk,
then the pad will be ignored. If we could change this to lazily
@@ -1207,6 +1214,33 @@
return null;
}
+ private static Drawable getBitmapDrawable(Resources res, TypedValue value, InputStream is) {
+ try {
+ ImageDecoder.Source source = null;
+ if (value != null) {
+ int density = Bitmap.DENSITY_NONE;
+ if (value.density == TypedValue.DENSITY_DEFAULT) {
+ density = DisplayMetrics.DENSITY_DEFAULT;
+ } else if (value.density != TypedValue.DENSITY_NONE) {
+ density = value.density;
+ }
+ source = ImageDecoder.createSource(res, is, density);
+ } else {
+ source = ImageDecoder.createSource(res, is);
+ }
+
+ return ImageDecoder.decodeDrawable(source, (decoder, info, src) -> {
+ decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+ });
+ } catch (IOException e) {
+ /* do nothing.
+ If the exception happened on decode, the drawable will be null.
+ */
+ Log.e("Drawable", "Unable to decode stream: " + e);
+ }
+ return null;
+ }
+
/**
* Create a drawable from an XML document. For more information on how to
* create resources in XML, see
@@ -1306,11 +1340,10 @@
}
Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, pathName);
- try {
- Bitmap bm = BitmapFactory.decodeFile(pathName);
- if (bm != null) {
- return drawableFromBitmap(null, bm, null, null, null, pathName);
- }
+ try (FileInputStream stream = new FileInputStream(pathName)) {
+ return getBitmapDrawable(null, null, stream);
+ } catch(IOException e) {
+ // Do nothing; we will just return null if the FileInputStream had an error
} finally {
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
}
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index 1790020..a56e8d1 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -24,9 +24,9 @@
import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
+import android.graphics.ImageDecoder;
import android.graphics.Insets;
import android.graphics.NinePatch;
import android.graphics.Outline;
@@ -211,7 +211,8 @@
restoreAlpha = -1;
}
- final boolean needsDensityScaling = canvas.getDensity() == 0;
+ final boolean needsDensityScaling = canvas.getDensity() == 0
+ && Bitmap.DENSITY_NONE != state.mNinePatch.getDensity();
if (needsDensityScaling) {
restoreToCount = restoreToCount >= 0 ? restoreToCount : canvas.save();
@@ -421,10 +422,6 @@
final int srcResId = a.getResourceId(R.styleable.NinePatchDrawable_src, 0);
if (srcResId != 0) {
- final BitmapFactory.Options options = new BitmapFactory.Options();
- options.inDither = !state.mDither;
- options.inScreenDensity = r.getDisplayMetrics().noncompatDensityDpi;
-
final Rect padding = new Rect();
final Rect opticalInsets = new Rect();
Bitmap bitmap = null;
@@ -433,7 +430,17 @@
final TypedValue value = new TypedValue();
final InputStream is = r.openRawResource(srcResId, value);
- bitmap = BitmapFactory.decodeResourceStream(r, value, is, padding, options);
+ int density = Bitmap.DENSITY_NONE;
+ if (value.density == TypedValue.DENSITY_DEFAULT) {
+ density = DisplayMetrics.DENSITY_DEFAULT;
+ } else if (value.density != TypedValue.DENSITY_NONE) {
+ density = value.density;
+ }
+ ImageDecoder.Source source = ImageDecoder.createSource(r, is, density);
+ bitmap = ImageDecoder.decodeBitmap(source, (decoder, info, src) -> {
+ decoder.setOutPaddingRect(padding);
+ decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+ });
is.close();
} catch (IOException e) {
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 3323bce..24d819e 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -134,6 +134,8 @@
name: "libhwui_defaults",
defaults: ["hwui_defaults"],
+ shared_libs: ["libstatslog"],
+
whole_static_libs: ["libskia"],
srcs: [
@@ -318,7 +320,10 @@
"libgmock",
"libhwui_static_debug",
],
- shared_libs: ["libmemunreachable"],
+ shared_libs: [
+ "libmemunreachable",
+ "libstatslog",
+ ],
cflags: [
"-include debug/wrap_gles.h",
"-DHWUI_NULL_GPU",
@@ -383,7 +388,10 @@
// set to libhwui_static_debug to skip actual GL commands
whole_static_libs: ["libhwui"],
- shared_libs: ["libmemunreachable"],
+ shared_libs: [
+ "libmemunreachable",
+ "libstatslog",
+ ],
srcs: [
"tests/macrobench/TestSceneRunner.cpp",
@@ -405,7 +413,10 @@
],
whole_static_libs: ["libhwui_static_debug"],
- shared_libs: ["libmemunreachable"],
+ shared_libs: [
+ "libmemunreachable",
+ "libstatslog",
+ ],
srcs: [
"tests/microbench/main.cpp",
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index f41956c..ab27a0d 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -18,6 +18,7 @@
#include <errno.h>
#include <inttypes.h>
+#include <statslog.h>
#include <sys/mman.h>
#include <algorithm>
@@ -164,6 +165,7 @@
ALOGI("%s", ss.str().c_str());
// Just so we have something that counts up, the value is largely irrelevant
ATRACE_INT(ss.str().c_str(), ++sDaveyCount);
+ android::util::stats_write(android::util::DAVEY_OCCURRED, ns2ms(totalDuration));
}
}
diff --git a/libs/hwui/hwui/Typeface.cpp b/libs/hwui/hwui/Typeface.cpp
index ebc14c8..091b526 100644
--- a/libs/hwui/hwui/Typeface.cpp
+++ b/libs/hwui/hwui/Typeface.cpp
@@ -182,10 +182,11 @@
std::shared_ptr<minikin::MinikinFont> font = std::make_shared<MinikinFontSkia>(
std::move(typeface), data, st.st_size, 0, std::vector<minikin::FontVariation>());
- std::shared_ptr<minikin::FontFamily> family = std::make_shared<minikin::FontFamily>(
- std::vector<minikin::Font>({minikin::Font(std::move(font), minikin::FontStyle())}));
- std::shared_ptr<minikin::FontCollection> collection =
- std::make_shared<minikin::FontCollection>(std::move(family));
+ std::vector<minikin::Font> fonts;
+ fonts.push_back(minikin::Font(std::move(font), minikin::FontStyle()));
+
+ std::shared_ptr<minikin::FontCollection> collection = std::make_shared<minikin::FontCollection>(
+ std::make_shared<minikin::FontFamily>(std::move(fonts)));
Typeface* hwTypeface = new Typeface();
hwTypeface->fFontCollection = collection;
diff --git a/libs/hwui/tests/unit/TypefaceTests.cpp b/libs/hwui/tests/unit/TypefaceTests.cpp
index 66d6f52..2232c25 100644
--- a/libs/hwui/tests/unit/TypefaceTests.cpp
+++ b/libs/hwui/tests/unit/TypefaceTests.cpp
@@ -56,8 +56,9 @@
LOG_ALWAYS_FATAL_IF(typeface == nullptr, "Failed to make typeface from %s", fileName);
std::shared_ptr<minikin::MinikinFont> font = std::make_shared<MinikinFontSkia>(
std::move(typeface), data, st.st_size, 0, std::vector<minikin::FontVariation>());
- return std::make_shared<minikin::FontFamily>(
- std::vector<minikin::Font>({minikin::Font(std::move(font), minikin::FontStyle())}));
+ std::vector<minikin::Font> fonts;
+ fonts.push_back(minikin::Font(std::move(font), minikin::FontStyle()));
+ return std::make_shared<minikin::FontFamily>(std::move(fonts));
}
std::vector<std::shared_ptr<minikin::FontFamily>> makeSingleFamlyVector(const char* fileName) {
diff --git a/libs/protoutil/src/ProtoOutputStream.cpp b/libs/protoutil/src/ProtoOutputStream.cpp
index 1904d40..f24abae 100644
--- a/libs/protoutil/src/ProtoOutputStream.cpp
+++ b/libs/protoutil/src/ProtoOutputStream.cpp
@@ -249,15 +249,15 @@
}
uint32_t id = (uint32_t)fieldId;
+ size_t prevPos = mBuffer.wp()->pos();
mBuffer.writeHeader(id, WIRE_TYPE_LENGTH_DELIMITED);
-
size_t sizePos = mBuffer.wp()->pos();
mDepth++;
mObjectId++;
mBuffer.writeRawFixed64(mExpectedObjectToken); // push previous token into stack.
- mExpectedObjectToken = makeToken(get_varint_size(id),
+ mExpectedObjectToken = makeToken(sizePos - prevPos,
(bool)(fieldId & FIELD_COUNT_REPEATED), mDepth, mObjectId, sizePos);
return mExpectedObjectToken;
}
diff --git a/media/java/android/media/MediaController2.java b/media/java/android/media/MediaController2.java
index b32e539..fcdecba 100644
--- a/media/java/android/media/MediaController2.java
+++ b/media/java/android/media/MediaController2.java
@@ -172,6 +172,14 @@
}
/**
+ * @hide
+ */
+ @SystemApi
+ public PlaybackInfoProvider getProvider() {
+ return mProvider;
+ }
+
+ /**
* Get the type of playback which affects volume handling. One of:
* <ul>
* <li>{@link #PLAYBACK_TYPE_LOCAL}</li>
@@ -199,9 +207,9 @@
/**
* Get the type of volume control that can be used. One of:
* <ul>
- * <li>{@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}</li>
- * <li>{@link VolumeProvider#VOLUME_CONTROL_RELATIVE}</li>
- * <li>{@link VolumeProvider#VOLUME_CONTROL_FIXED}</li>
+ * <li>{@link VolumeProvider2#VOLUME_CONTROL_ABSOLUTE}</li>
+ * <li>{@link VolumeProvider2#VOLUME_CONTROL_RELATIVE}</li>
+ * <li>{@link VolumeProvider2#VOLUME_CONTROL_FIXED}</li>
* </ul>
*
* @return The type of volume control that may be used with this session.
@@ -472,7 +480,7 @@
/**
* Set the volume of the output this session is playing on. The command will be ignored if it
- * does not support {@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}.
+ * does not support {@link VolumeProvider2#VOLUME_CONTROL_ABSOLUTE}.
* <p>
* If the session is local playback, this changes the device's volume with the stream that
* session's player is using. Flags will be specified for the {@link AudioManager}.
@@ -494,8 +502,8 @@
* must be one of {@link AudioManager#ADJUST_LOWER},
* {@link AudioManager#ADJUST_RAISE}, or {@link AudioManager#ADJUST_SAME}.
* The command will be ignored if the session does not support
- * {@link VolumeProvider#VOLUME_CONTROL_RELATIVE} or
- * {@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}.
+ * {@link VolumeProvider2#VOLUME_CONTROL_RELATIVE} or
+ * {@link VolumeProvider2#VOLUME_CONTROL_ABSOLUTE}.
* <p>
* If the session is local playback, this changes the device's volume with the stream that
* session's player is using. Flags will be specified for the {@link AudioManager}.
diff --git a/media/java/android/media/MediaLibraryService2.java b/media/java/android/media/MediaLibraryService2.java
index f88f9f2..a11768e 100644
--- a/media/java/android/media/MediaLibraryService2.java
+++ b/media/java/android/media/MediaLibraryService2.java
@@ -27,7 +27,6 @@
import android.media.update.ApiLoader;
import android.media.update.MediaLibraryService2Provider.LibraryRootProvider;
import android.media.update.MediaLibraryService2Provider.MediaLibrarySessionProvider;
-import android.media.update.MediaSession2Provider;
import android.media.update.MediaSessionService2Provider;
import android.os.Bundle;
@@ -63,7 +62,8 @@
public static final String SERVICE_INTERFACE = "android.media.MediaLibraryService2";
/**
- * Session for the media library service.
+ * Session for the {@link MediaLibraryService2}. Build this object with
+ * {@link MediaLibrarySessionBuilder} and return in {@link #onCreateSession(String)}.
*/
public static class MediaLibrarySession extends MediaSession2 {
private final MediaLibrarySessionProvider mProvider;
@@ -101,6 +101,9 @@
}
}
+ /**
+ * Callback for the {@link MediaLibrarySession}.
+ */
public static class MediaLibrarySessionCallback extends MediaSession2.SessionCallback {
public MediaLibrarySessionCallback(Context context) {
@@ -200,6 +203,8 @@
/**
* Builder for {@link MediaLibrarySession}.
*/
+ // Override all methods just to show them with the type instead of generics in Javadoc.
+ // This workarounds javadoc issue described in the MediaSession2.BuilderBase.
public class MediaLibrarySessionBuilder extends BuilderBase<MediaLibrarySession,
MediaLibrarySessionBuilder, MediaLibrarySessionCallback> {
public MediaLibrarySessionBuilder(
@@ -210,6 +215,38 @@
context, (MediaLibrarySessionBuilder) instance, player, callbackExecutor,
callback));
}
+
+ @Override
+ public MediaLibrarySessionBuilder setVolumeProvider(
+ @Nullable VolumeProvider2 volumeProvider) {
+ return super.setVolumeProvider(volumeProvider);
+ }
+
+ @Override
+ public MediaLibrarySessionBuilder setRatingType(int type) {
+ return super.setRatingType(type);
+ }
+
+ @Override
+ public MediaLibrarySessionBuilder setSessionActivity(@Nullable PendingIntent pi) {
+ return super.setSessionActivity(pi);
+ }
+
+ @Override
+ public MediaLibrarySessionBuilder setId(String id) {
+ return super.setId(id);
+ }
+
+ @Override
+ public MediaLibrarySessionBuilder setSessionCallback(
+ @NonNull Executor executor, @NonNull MediaLibrarySessionCallback callback) {
+ return super.setSessionCallback(executor, callback);
+ }
+
+ @Override
+ public MediaLibrarySession build() {
+ return super.build();
+ }
}
@Override
@@ -229,7 +266,7 @@
* This method will be called on the main thread.
*
* @param sessionId session id written in the AndroidManifest.xml.
- * @return a new browser session
+ * @return a new library session
* @see MediaLibrarySessionBuilder
* @see #getSession()
* @throws RuntimeException if returned session is invalid
diff --git a/media/java/android/media/MediaPlayer2.java b/media/java/android/media/MediaPlayer2.java
index d84eedf..e331b2c 100644
--- a/media/java/android/media/MediaPlayer2.java
+++ b/media/java/android/media/MediaPlayer2.java
@@ -1671,35 +1671,6 @@
public abstract void deselectTrack(int index);
/**
- * Sets the target UDP re-transmit endpoint for the low level player.
- * Generally, the address portion of the endpoint is an IP multicast
- * address, although a unicast address would be equally valid. When a valid
- * retransmit endpoint has been set, the media player will not decode and
- * render the media presentation locally. Instead, the player will attempt
- * to re-multiplex its media data using the Android@Home RTP profile and
- * re-transmit to the target endpoint. Receiver devices (which may be
- * either the same as the transmitting device or different devices) may
- * instantiate, prepare, and start a receiver player using a setDataSource
- * URL of the form...
- *
- * aahRX://<multicastIP>:<port>
- *
- * to receive, decode and render the re-transmitted content.
- *
- * setRetransmitEndpoint may only be called before setDataSource has been
- * called; while the player is in the Idle state.
- *
- * @param endpoint the address and UDP port of the re-transmission target or
- * null if no re-transmission is to be performed.
- * @throws IllegalStateException if it is called in an invalid state
- * @throws IllegalArgumentException if the retransmit endpoint is supplied,
- * but invalid.
- *
- * {@hide} pending API council
- */
- public void setRetransmitEndpoint(InetSocketAddress endpoint) { }
-
- /**
* Releases the resources held by this {@code MediaPlayer2} object.
*
* It is considered good practice to call this method when you're
diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java
index 222c66e..e3d5ac0 100644
--- a/media/java/android/media/MediaPlayer2Impl.java
+++ b/media/java/android/media/MediaPlayer2Impl.java
@@ -2964,53 +2964,6 @@
}
/**
- * Sets the target UDP re-transmit endpoint for the low level player.
- * Generally, the address portion of the endpoint is an IP multicast
- * address, although a unicast address would be equally valid. When a valid
- * retransmit endpoint has been set, the media player will not decode and
- * render the media presentation locally. Instead, the player will attempt
- * to re-multiplex its media data using the Android@Home RTP profile and
- * re-transmit to the target endpoint. Receiver devices (which may be
- * either the same as the transmitting device or different devices) may
- * instantiate, prepare, and start a receiver player using a setDataSource
- * URL of the form...
- *
- * aahRX://<multicastIP>:<port>
- *
- * to receive, decode and render the re-transmitted content.
- *
- * setRetransmitEndpoint may only be called before setDataSource has been
- * called; while the player is in the Idle state.
- *
- * @param endpoint the address and UDP port of the re-transmission target or
- * null if no re-transmission is to be performed.
- * @throws IllegalStateException if it is called in an invalid state
- * @throws IllegalArgumentException if the retransmit endpoint is supplied,
- * but invalid.
- *
- * {@hide} pending API council
- */
- @Override
- public void setRetransmitEndpoint(InetSocketAddress endpoint)
- throws IllegalStateException, IllegalArgumentException
- {
- String addrString = null;
- int port = 0;
-
- if (null != endpoint) {
- addrString = endpoint.getAddress().getHostAddress();
- port = endpoint.getPort();
- }
-
- int ret = native_setRetransmitEndpoint(addrString, port);
- if (ret != 0) {
- throw new IllegalArgumentException("Illegal re-transmit endpoint; native ret " + ret);
- }
- }
-
- private native final int native_setRetransmitEndpoint(String addrString, int port);
-
- /**
* Releases the resources held by this {@code MediaPlayer2} object.
*
* It is considered good practice to call this method when you're
diff --git a/media/java/android/media/MediaSession2.java b/media/java/android/media/MediaSession2.java
index 5670bd8..ae2649a 100644
--- a/media/java/android/media/MediaSession2.java
+++ b/media/java/android/media/MediaSession2.java
@@ -580,8 +580,20 @@
};
/**
- * Base builder class for MediaSession2 and its subclass.
- *
+ * Base builder class for MediaSession2 and its subclass. Any change in this class should be
+ * also applied to the subclasses {@link MediaSession2.Builder} and
+ * {@link MediaLibraryService2.MediaLibrarySessionBuilder}.
+ * <p>
+ * APIs here should be package private, but should have documentations for developers.
+ * Otherwise, javadoc will generate documentation with the generic types such as follows.
+ * <pre>U extends BuilderBase<T, U, C> setSessionCallback(Executor executor, C callback)</pre>
+ * <p>
+ * This class is hidden to prevent from generating test stub, which fails with
+ * 'unexpected bound' because it tries to auto generate stub class as follows.
+ * <pre>abstract static class BuilderBase<
+ * T extends android.media.MediaSession2,
+ * U extends android.media.MediaSession2.BuilderBase<
+ * T, U, C extends android.media.MediaSession2.SessionCallback>, C></pre>
* @hide
*/
static abstract class BuilderBase
@@ -599,9 +611,9 @@
* <p>
* Set {@code null} to reset.
*
- * @param volumeProvider The provider that will handle volume changes. Can be {@code null}
+ * @param volumeProvider The provider that will handle volume changes. Can be {@code null}.
*/
- public U setVolumeProvider(@Nullable VolumeProvider volumeProvider) {
+ U setVolumeProvider(@Nullable VolumeProvider2 volumeProvider) {
mProvider.setVolumeProvider_impl(volumeProvider);
return (U) this;
}
@@ -619,7 +631,7 @@
* <li>{@link Rating2#RATING_THUMB_UP_DOWN}</li>
* </ul>
*/
- public U setRatingType(@Rating2.Style int type) {
+ U setRatingType(@Rating2.Style int type) {
mProvider.setRatingType_impl(type);
return (U) this;
}
@@ -631,7 +643,7 @@
*
* @param pi The intent to launch to show UI for this session.
*/
- public U setSessionActivity(@Nullable PendingIntent pi) {
+ U setSessionActivity(@Nullable PendingIntent pi) {
mProvider.setSessionActivity_impl(pi);
return (U) this;
}
@@ -646,7 +658,7 @@
* @throws IllegalArgumentException if id is {@code null}
* @return
*/
- public U setId(@NonNull String id) {
+ U setId(@NonNull String id) {
mProvider.setId_impl(id);
return (U) this;
}
@@ -658,7 +670,7 @@
* @param callback session callback.
* @return
*/
- public U setSessionCallback(@NonNull @CallbackExecutor Executor executor,
+ U setSessionCallback(@NonNull @CallbackExecutor Executor executor,
@NonNull C callback) {
mProvider.setSessionCallback_impl(executor, callback);
return (U) this;
@@ -671,7 +683,7 @@
* @throws IllegalStateException if the session with the same id is already exists for the
* package.
*/
- public T build() {
+ T build() {
return mProvider.build_impl();
}
}
@@ -682,13 +694,44 @@
* Any incoming event from the {@link MediaController2} will be handled on the thread
* that created session with the {@link Builder#build()}.
*/
- // TODO(jaewan): Add setRatingType()
- // TODO(jaewan): Add setSessionActivity()
+ // Override all methods just to show them with the type instead of generics in Javadoc.
+ // This workarounds javadoc issue described in the MediaSession2.BuilderBase.
public static final class Builder extends BuilderBase<MediaSession2, Builder, SessionCallback> {
public Builder(Context context, @NonNull MediaPlayerInterface player) {
super((instance) -> ApiLoader.getProvider(context).createMediaSession2Builder(
context, (Builder) instance, player));
}
+
+ @Override
+ public Builder setVolumeProvider(@Nullable VolumeProvider2 volumeProvider) {
+ return super.setVolumeProvider(volumeProvider);
+ }
+
+ @Override
+ public Builder setRatingType(@Rating2.Style int type) {
+ return super.setRatingType(type);
+ }
+
+ @Override
+ public Builder setSessionActivity(@Nullable PendingIntent pi) {
+ return super.setSessionActivity(pi);
+ }
+
+ @Override
+ public Builder setId(@NonNull String id) {
+ return super.setId(id);
+ }
+
+ @Override
+ public Builder setSessionCallback(@NonNull Executor executor,
+ @Nullable SessionCallback callback) {
+ return super.setSessionCallback(executor, callback);
+ }
+
+ @Override
+ public MediaSession2 build() {
+ return super.build();
+ }
}
/**
@@ -1035,8 +1078,8 @@
* If the new player is successfully set, {@link PlaybackListener}
* will be called to tell the current playback state of the new player.
* <p>
- * You can also specify a volume provider. If so, playback in the player is considered as
- * remote playback.
+ * For the remote playback case which you want to handle volume by yourself, use
+ * {@link #setPlayer(MediaPlayerInterface, VolumeProvider2)}.
*
* @param player a {@link MediaPlayerInterface} that handles actual media playback in your app.
* @throws IllegalArgumentException if the player is {@code null}.
@@ -1051,10 +1094,10 @@
* @param player a {@link MediaPlayerInterface} that handles actual media playback in your app.
* @param volumeProvider a volume provider
* @see #setPlayer(MediaPlayerInterface)
- * @see Builder#setVolumeProvider(VolumeProvider)
+ * @see Builder#setVolumeProvider(VolumeProvider2)
*/
public void setPlayer(@NonNull MediaPlayerInterface player,
- @NonNull VolumeProvider volumeProvider) {
+ @NonNull VolumeProvider2 volumeProvider) {
mProvider.setPlayer_impl(player, volumeProvider);
}
diff --git a/media/java/android/media/MicrophoneInfo.java b/media/java/android/media/MicrophoneInfo.java
index 21f9171..131e37b 100644
--- a/media/java/android/media/MicrophoneInfo.java
+++ b/media/java/android/media/MicrophoneInfo.java
@@ -55,7 +55,7 @@
/**
* Unknown microphone directionality.
*/
- public static final int DIRECTIONALITY_UNKNOW = 0;
+ public static final int DIRECTIONALITY_UNKNOWN = 0;
/**
* Microphone directionality type: omni.
@@ -104,7 +104,7 @@
/** @hide */
@IntDef(flag = true, prefix = { "DIRECTIONALITY_" }, value = {
- DIRECTIONALITY_UNKNOW,
+ DIRECTIONALITY_UNKNOWN,
DIRECTIONALITY_OMNI,
DIRECTIONALITY_BI_DIRECTIONAL,
DIRECTIONALITY_CARDIOID,
@@ -309,7 +309,7 @@
/**
* Returns the directionality of microphone. The return value is one of
- * {@link #DIRECTIONALITY_UNKNOW}, {@link #DIRECTIONALITY_OMNI},
+ * {@link #DIRECTIONALITY_UNKNOWN}, {@link #DIRECTIONALITY_OMNI},
* {@link #DIRECTIONALITY_BI_DIRECTIONAL}, {@link #DIRECTIONALITY_CARDIOID},
* {@link #DIRECTIONALITY_HYPER_CARDIOID}, or {@link #DIRECTIONALITY_SUPER_CARDIOID}.
*
diff --git a/media/java/android/media/VolumeProvider2.java b/media/java/android/media/VolumeProvider2.java
index 00746e2..53ba466 100644
--- a/media/java/android/media/VolumeProvider2.java
+++ b/media/java/android/media/VolumeProvider2.java
@@ -32,7 +32,7 @@
* {@link #setCurrentVolume(int)} each time the volume being provided changes.
* <p>
* You can set a volume provider on a session by calling
- * {@link MediaSession2#setPlayer(MediaPlayerInterface, VolumeProvider)}.
+ * {@link MediaSession2#setPlayer(MediaPlayerInterface, VolumeProvider2)}.
*
* @hide
*/
diff --git a/media/java/android/media/audiofx/Visualizer.java b/media/java/android/media/audiofx/Visualizer.java
index 0fe7246..f2b4fe0 100644
--- a/media/java/android/media/audiofx/Visualizer.java
+++ b/media/java/android/media/audiofx/Visualizer.java
@@ -546,22 +546,39 @@
/**
* Method called when a new waveform capture is available.
* <p>Data in the waveform buffer is valid only within the scope of the callback.
- * Applications which needs access to the waveform data after returning from the callback
+ * Applications which need access to the waveform data after returning from the callback
* should make a copy of the data instead of holding a reference.
* @param visualizer Visualizer object on which the listener is registered.
* @param waveform array of bytes containing the waveform representation.
- * @param samplingRate sampling rate of the audio visualized.
+ * @param samplingRate sampling rate of the visualized audio.
*/
void onWaveFormDataCapture(Visualizer visualizer, byte[] waveform, int samplingRate);
/**
* Method called when a new frequency capture is available.
* <p>Data in the fft buffer is valid only within the scope of the callback.
- * Applications which needs access to the fft data after returning from the callback
+ * Applications which need access to the fft data after returning from the callback
* should make a copy of the data instead of holding a reference.
+ *
+ * <p>In order to obtain magnitude and phase values the following formulas can
+ * be used:
+ * <pre class="prettyprint">
+ * for (int i = 0; i < fft.size(); i += 2) {
+ * float magnitude = (float)Math.hypot(fft[i], fft[i + 1]);
+ * float phase = (float)Math.atan2(fft[i + 1], fft[i]);
+ * }</pre>
* @param visualizer Visualizer object on which the listener is registered.
* @param fft array of bytes containing the frequency representation.
- * @param samplingRate sampling rate of the audio visualized.
+ * The fft array only contains the first half of the actual
+ * FFT spectrum (frequencies up to Nyquist frequency), exploiting
+ * the symmetry of the spectrum. For each frequencies bin <code>i</code>:
+ * <ul>
+ * <li>the element at index <code>2*i</code> in the array contains
+ * the real part of a complex number,</li>
+ * <li>the element at index <code>2*i+1</code> contains the imaginary
+ * part of the complex number.</li>
+ * </ul>
+ * @param samplingRate sampling rate of the visualized audio.
*/
void onFftDataCapture(Visualizer visualizer, byte[] fft, int samplingRate);
}
diff --git a/media/java/android/media/update/FrameLayoutHelper.java b/media/java/android/media/update/FrameLayoutHelper.java
deleted file mode 100644
index 983dc70..0000000
--- a/media/java/android/media/update/FrameLayoutHelper.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.media.update;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.widget.FrameLayout;
-
-/**
- * Helper class for connecting the public API to an updatable implementation.
- *
- * @see ViewProvider
- *
- * @hide
- */
-public abstract class FrameLayoutHelper<T extends ViewProvider> extends FrameLayout {
- /** @hide */
- final public T mProvider;
-
- /** @hide */
- public FrameLayoutHelper(ProviderCreator<T> creator,
- Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
-
- mProvider = creator.createProvider(this, new SuperProvider());
- }
-
- /** @hide */
- // TODO @SystemApi
- public T getProvider() {
- return mProvider;
- }
-
- @Override
- public CharSequence getAccessibilityClassName() {
- return mProvider.getAccessibilityClassName_impl();
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- return mProvider.onTouchEvent_impl(ev);
- }
-
- @Override
- public boolean onTrackballEvent(MotionEvent ev) {
- return mProvider.onTrackballEvent_impl(ev);
- }
-
- @Override
- public void onFinishInflate() {
- mProvider.onFinishInflate_impl();
- }
-
- @Override
- public void setEnabled(boolean enabled) {
- mProvider.setEnabled_impl(enabled);
- }
-
- @Override
- protected void onAttachedToWindow() {
- mProvider.onAttachedToWindow_impl();
- }
-
- @Override
- protected void onDetachedFromWindow() {
- mProvider.onDetachedFromWindow_impl();
- }
-
- /** @hide */
- public class SuperProvider implements ViewProvider {
- @Override
- public CharSequence getAccessibilityClassName_impl() {
- return FrameLayoutHelper.super.getAccessibilityClassName();
- }
-
- @Override
- public boolean onTouchEvent_impl(MotionEvent ev) {
- return FrameLayoutHelper.super.onTouchEvent(ev);
- }
-
- @Override
- public boolean onTrackballEvent_impl(MotionEvent ev) {
- return FrameLayoutHelper.super.onTrackballEvent(ev);
- }
-
- @Override
- public void onFinishInflate_impl() {
- FrameLayoutHelper.super.onFinishInflate();
- }
-
- @Override
- public void setEnabled_impl(boolean enabled) {
- FrameLayoutHelper.super.setEnabled(enabled);
- }
-
- @Override
- public void onAttachedToWindow_impl() {
- FrameLayoutHelper.super.onAttachedToWindow();
- }
-
- @Override
- public void onDetachedFromWindow_impl() {
- FrameLayoutHelper.super.onDetachedFromWindow();
- }
- }
-
- /** @hide */
- @FunctionalInterface
- public interface ProviderCreator<U extends ViewProvider> {
- U createProvider(FrameLayoutHelper<U> instance, ViewProvider superProvider);
- }
-}
diff --git a/media/java/android/media/update/MediaControlView2Provider.java b/media/java/android/media/update/MediaControlView2Provider.java
index 95fe363..e155e5f 100644
--- a/media/java/android/media/update/MediaControlView2Provider.java
+++ b/media/java/android/media/update/MediaControlView2Provider.java
@@ -18,6 +18,7 @@
import android.annotation.SystemApi;
import android.media.session.MediaController;
+import android.util.AttributeSet;
import android.view.View;
/**
@@ -34,12 +35,12 @@
* @hide
*/
// TODO @SystemApi
-public interface MediaControlView2Provider extends ViewProvider {
+public interface MediaControlView2Provider extends ViewGroupProvider {
+ void initialize(AttributeSet attrs, int defStyleAttr, int defStyleRes);
+
void setController_impl(MediaController controller);
- boolean isShowing_impl();
void setButtonVisibility_impl(int button, int visibility);
void requestPlayButtonFocus_impl();
- void onVisibilityAggregated_impl(boolean isVisible);
void setTimeout_impl(long timeout);
long getTimeout_impl();
}
diff --git a/media/java/android/media/update/MediaSession2Provider.java b/media/java/android/media/update/MediaSession2Provider.java
index 9abf34a..41162e0 100644
--- a/media/java/android/media/update/MediaSession2Provider.java
+++ b/media/java/android/media/update/MediaSession2Provider.java
@@ -30,7 +30,7 @@
import android.media.MediaSession2.PlaylistParams;
import android.media.MediaSession2.SessionCallback;
import android.media.SessionToken2;
-import android.media.VolumeProvider;
+import android.media.VolumeProvider2;
import android.os.Bundle;
import android.os.ResultReceiver;
@@ -44,7 +44,7 @@
public interface MediaSession2Provider extends TransportControlProvider {
void close_impl();
void setPlayer_impl(MediaPlayerInterface player);
- void setPlayer_impl(MediaPlayerInterface player, VolumeProvider volumeProvider);
+ void setPlayer_impl(MediaPlayerInterface player, VolumeProvider2 volumeProvider);
MediaPlayerInterface getPlayer_impl();
SessionToken2 getToken_impl();
List<ControllerInfo> getConnectedControllers_impl();
@@ -116,7 +116,7 @@
}
interface BuilderBaseProvider<T extends MediaSession2, C extends SessionCallback> {
- void setVolumeProvider_impl(VolumeProvider volumeProvider);
+ void setVolumeProvider_impl(VolumeProvider2 volumeProvider);
void setRatingType_impl(int type);
void setSessionActivity_impl(PendingIntent pi);
void setId_impl(String id);
diff --git a/media/java/android/media/update/StaticProvider.java b/media/java/android/media/update/StaticProvider.java
index 862a402..57f04cc 100644
--- a/media/java/android/media/update/StaticProvider.java
+++ b/media/java/android/media/update/StaticProvider.java
@@ -67,10 +67,11 @@
* @hide
*/
public interface StaticProvider {
- MediaControlView2Provider createMediaControlView2(
- MediaControlView2 instance, ViewProvider superProvider);
- VideoView2Provider createVideoView2(
- VideoView2 instance, ViewProvider superProvider,
+ MediaControlView2Provider createMediaControlView2(MediaControlView2 instance,
+ ViewGroupProvider superProvider, ViewGroupProvider privateProvider,
+ @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes);
+ VideoView2Provider createVideoView2(VideoView2 instance,
+ ViewGroupProvider superProvider, ViewGroupProvider privateProvider,
@Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes);
CommandProvider createMediaSession2Command(MediaSession2.Command instance,
diff --git a/media/java/android/media/update/VideoView2Provider.java b/media/java/android/media/update/VideoView2Provider.java
index 10f03d2..7251180 100644
--- a/media/java/android/media/update/VideoView2Provider.java
+++ b/media/java/android/media/update/VideoView2Provider.java
@@ -16,12 +16,14 @@
package android.media.update;
+import android.annotation.SystemApi;
import android.media.AudioAttributes;
import android.media.MediaPlayerInterface;
import android.media.session.MediaController;
import android.media.session.PlaybackState;
import android.media.session.MediaSession;
import android.net.Uri;
+import android.util.AttributeSet;
import android.widget.MediaControlView2;
import android.widget.VideoView2;
@@ -43,7 +45,9 @@
* @hide
*/
// TODO @SystemApi
-public interface VideoView2Provider extends ViewProvider {
+public interface VideoView2Provider extends ViewGroupProvider {
+ void initialize(AttributeSet attrs, int defStyleAttr, int defStyleRes);
+
void setMediaControlView2_impl(MediaControlView2 mediaControlView);
MediaController getMediaController_impl();
MediaControlView2 getMediaControlView2_impl();
@@ -52,6 +56,9 @@
void setSpeed_impl(float speed);
void setAudioFocusRequest_impl(int focusGain);
void setAudioAttributes_impl(AudioAttributes attributes);
+ /**
+ * @hide
+ */
void setRouteAttributes_impl(List<String> routeCategories, MediaPlayerInterface player);
// TODO: remove setRouteAttributes_impl with MediaSession.Callback once MediaSession2 is ready.
void setRouteAttributes_impl(List<String> routeCategories, MediaSession.Callback sessionPlayer);
diff --git a/media/java/android/media/update/ViewGroupHelper.java b/media/java/android/media/update/ViewGroupHelper.java
new file mode 100644
index 0000000..2c4f9b9
--- /dev/null
+++ b/media/java/android/media/update/ViewGroupHelper.java
@@ -0,0 +1,354 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.update;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Helper class for connecting the public API to an updatable implementation.
+ *
+ * @see ViewGroupProvider
+ *
+ * @hide
+ */
+public abstract class ViewGroupHelper<T extends ViewGroupProvider> extends ViewGroup {
+ /** @hide */
+ final public T mProvider;
+
+ /** @hide */
+ public ViewGroupHelper(ProviderCreator<T> creator,
+ Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+
+ mProvider = creator.createProvider(this, new SuperProvider(),
+ new PrivateProvider());
+ }
+
+ /** @hide */
+ // TODO @SystemApi
+ public T getProvider() {
+ return mProvider;
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ mProvider.onAttachedToWindow_impl();
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ mProvider.onDetachedFromWindow_impl();
+ }
+
+ @Override
+ public CharSequence getAccessibilityClassName() {
+ return mProvider.getAccessibilityClassName_impl();
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ return mProvider.onTouchEvent_impl(ev);
+ }
+
+ @Override
+ public boolean onTrackballEvent(MotionEvent ev) {
+ return mProvider.onTrackballEvent_impl(ev);
+ }
+
+ @Override
+ public void onFinishInflate() {
+ mProvider.onFinishInflate_impl();
+ }
+
+ @Override
+ public void setEnabled(boolean enabled) {
+ mProvider.setEnabled_impl(enabled);
+ }
+
+ @Override
+ public void onVisibilityAggregated(boolean isVisible) {
+ mProvider.onVisibilityAggregated_impl(isVisible);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ mProvider.onLayout_impl(changed, left, top, right, bottom);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ mProvider.onMeasure_impl(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ @Override
+ protected int getSuggestedMinimumWidth() {
+ return mProvider.getSuggestedMinimumWidth_impl();
+ }
+
+ @Override
+ protected int getSuggestedMinimumHeight() {
+ return mProvider.getSuggestedMinimumHeight_impl();
+ }
+
+ // setMeasuredDimension is final
+
+ @Override
+ protected boolean checkLayoutParams(LayoutParams p) {
+ return mProvider.checkLayoutParams_impl(p);
+ }
+
+ @Override
+ protected LayoutParams generateDefaultLayoutParams() {
+ return mProvider.generateDefaultLayoutParams_impl();
+ }
+
+ @Override
+ public LayoutParams generateLayoutParams(AttributeSet attrs) {
+ return mProvider.generateLayoutParams_impl(attrs);
+ }
+
+ @Override
+ protected LayoutParams generateLayoutParams(LayoutParams lp) {
+ return mProvider.generateLayoutParams_impl(lp);
+ }
+
+ @Override
+ public boolean shouldDelayChildPressedState() {
+ return mProvider.shouldDelayChildPressedState_impl();
+ }
+
+ @Override
+ protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed,
+ int parentHeightMeasureSpec, int heightUsed) {
+ mProvider.measureChildWithMargins_impl(child,
+ parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed);
+ }
+
+ /** @hide */
+ public class SuperProvider implements ViewGroupProvider {
+ @Override
+ public CharSequence getAccessibilityClassName_impl() {
+ return ViewGroupHelper.super.getAccessibilityClassName();
+ }
+
+ @Override
+ public boolean onTouchEvent_impl(MotionEvent ev) {
+ return ViewGroupHelper.super.onTouchEvent(ev);
+ }
+
+ @Override
+ public boolean onTrackballEvent_impl(MotionEvent ev) {
+ return ViewGroupHelper.super.onTrackballEvent(ev);
+ }
+
+ @Override
+ public void onFinishInflate_impl() {
+ ViewGroupHelper.super.onFinishInflate();
+ }
+
+ @Override
+ public void setEnabled_impl(boolean enabled) {
+ ViewGroupHelper.super.setEnabled(enabled);
+ }
+
+ @Override
+ public void onAttachedToWindow_impl() {
+ ViewGroupHelper.super.onAttachedToWindow();
+ }
+
+ @Override
+ public void onDetachedFromWindow_impl() {
+ ViewGroupHelper.super.onDetachedFromWindow();
+ }
+
+ @Override
+ public void onVisibilityAggregated_impl(boolean isVisible) {
+ ViewGroupHelper.super.onVisibilityAggregated(isVisible);
+ }
+
+ @Override
+ public void onLayout_impl(boolean changed, int left, int top, int right, int bottom) {
+ // abstract method; no super
+ }
+
+ @Override
+ public void onMeasure_impl(int widthMeasureSpec, int heightMeasureSpec) {
+ ViewGroupHelper.super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ @Override
+ public int getSuggestedMinimumWidth_impl() {
+ return ViewGroupHelper.super.getSuggestedMinimumWidth();
+ }
+
+ @Override
+ public int getSuggestedMinimumHeight_impl() {
+ return ViewGroupHelper.super.getSuggestedMinimumHeight();
+ }
+
+ @Override
+ public void setMeasuredDimension_impl(int measuredWidth, int measuredHeight) {
+ ViewGroupHelper.super.setMeasuredDimension(measuredWidth, measuredHeight);
+ }
+
+ @Override
+ public boolean checkLayoutParams_impl(LayoutParams p) {
+ return ViewGroupHelper.super.checkLayoutParams(p);
+ }
+
+ @Override
+ public LayoutParams generateDefaultLayoutParams_impl() {
+ return ViewGroupHelper.super.generateDefaultLayoutParams();
+ }
+
+ @Override
+ public LayoutParams generateLayoutParams_impl(AttributeSet attrs) {
+ return ViewGroupHelper.super.generateLayoutParams(attrs);
+ }
+
+ @Override
+ public LayoutParams generateLayoutParams_impl(LayoutParams lp) {
+ return ViewGroupHelper.super.generateLayoutParams(lp);
+ }
+
+ @Override
+ public boolean shouldDelayChildPressedState_impl() {
+ return ViewGroupHelper.super.shouldDelayChildPressedState();
+ }
+
+ @Override
+ public void measureChildWithMargins_impl(View child,
+ int parentWidthMeasureSpec, int widthUsed,
+ int parentHeightMeasureSpec, int heightUsed) {
+ ViewGroupHelper.super.measureChildWithMargins(child,
+ parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed);
+ }
+ }
+
+ /** @hide */
+ public class PrivateProvider implements ViewGroupProvider {
+ @Override
+ public CharSequence getAccessibilityClassName_impl() {
+ return ViewGroupHelper.this.getAccessibilityClassName();
+ }
+
+ @Override
+ public boolean onTouchEvent_impl(MotionEvent ev) {
+ return ViewGroupHelper.this.onTouchEvent(ev);
+ }
+
+ @Override
+ public boolean onTrackballEvent_impl(MotionEvent ev) {
+ return ViewGroupHelper.this.onTrackballEvent(ev);
+ }
+
+ @Override
+ public void onFinishInflate_impl() {
+ ViewGroupHelper.this.onFinishInflate();
+ }
+
+ @Override
+ public void setEnabled_impl(boolean enabled) {
+ ViewGroupHelper.this.setEnabled(enabled);
+ }
+
+ @Override
+ public void onAttachedToWindow_impl() {
+ ViewGroupHelper.this.onAttachedToWindow();
+ }
+
+ @Override
+ public void onDetachedFromWindow_impl() {
+ ViewGroupHelper.this.onDetachedFromWindow();
+ }
+
+ @Override
+ public void onVisibilityAggregated_impl(boolean isVisible) {
+ ViewGroupHelper.this.onVisibilityAggregated(isVisible);
+ }
+
+ @Override
+ public void onLayout_impl(boolean changed, int left, int top, int right, int bottom) {
+ ViewGroupHelper.this.onLayout(changed, left, top, right, bottom);
+ }
+
+ @Override
+ public void onMeasure_impl(int widthMeasureSpec, int heightMeasureSpec) {
+ ViewGroupHelper.this.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ @Override
+ public int getSuggestedMinimumWidth_impl() {
+ return ViewGroupHelper.this.getSuggestedMinimumWidth();
+ }
+
+ @Override
+ public int getSuggestedMinimumHeight_impl() {
+ return ViewGroupHelper.this.getSuggestedMinimumHeight();
+ }
+
+ @Override
+ public void setMeasuredDimension_impl(int measuredWidth, int measuredHeight) {
+ ViewGroupHelper.this.setMeasuredDimension(measuredWidth, measuredHeight);
+ }
+
+ @Override
+ public boolean checkLayoutParams_impl(LayoutParams p) {
+ return ViewGroupHelper.this.checkLayoutParams(p);
+ }
+
+ @Override
+ public LayoutParams generateDefaultLayoutParams_impl() {
+ return ViewGroupHelper.this.generateDefaultLayoutParams();
+ }
+
+ @Override
+ public LayoutParams generateLayoutParams_impl(AttributeSet attrs) {
+ return ViewGroupHelper.this.generateLayoutParams(attrs);
+ }
+
+ @Override
+ public LayoutParams generateLayoutParams_impl(LayoutParams lp) {
+ return ViewGroupHelper.this.generateLayoutParams(lp);
+ }
+
+ @Override
+ public boolean shouldDelayChildPressedState_impl() {
+ return ViewGroupHelper.this.shouldDelayChildPressedState();
+ }
+
+ @Override
+ public void measureChildWithMargins_impl(View child,
+ int parentWidthMeasureSpec, int widthUsed,
+ int parentHeightMeasureSpec, int heightUsed) {
+ ViewGroupHelper.this.measureChildWithMargins(child,
+ parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed);
+ }
+ }
+
+ /** @hide */
+ @FunctionalInterface
+ public interface ProviderCreator<T extends ViewGroupProvider> {
+ T createProvider(ViewGroupHelper<T> instance, ViewGroupProvider superProvider,
+ ViewGroupProvider privateProvider);
+ }
+}
diff --git a/media/java/android/media/update/ViewGroupProvider.java b/media/java/android/media/update/ViewGroupProvider.java
new file mode 100644
index 0000000..5f12529
--- /dev/null
+++ b/media/java/android/media/update/ViewGroupProvider.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.update;
+
+import android.annotation.SystemApi;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+
+/**
+ * Interface for connecting the public API to an updatable implementation.
+ *
+ * Each instance object is connected to one corresponding updatable object which implements the
+ * runtime behavior of that class. There should a corresponding provider method for all public
+ * methods.
+ *
+ * All methods behave as per their namesake in the public API.
+ *
+ * @see android.view.View
+ *
+ * @hide
+ */
+// TODO @SystemApi
+public interface ViewGroupProvider {
+ // View methods
+ void onAttachedToWindow_impl();
+ void onDetachedFromWindow_impl();
+ CharSequence getAccessibilityClassName_impl();
+ boolean onTouchEvent_impl(MotionEvent ev);
+ boolean onTrackballEvent_impl(MotionEvent ev);
+ void onFinishInflate_impl();
+ void setEnabled_impl(boolean enabled);
+ void onVisibilityAggregated_impl(boolean isVisible);
+ void onLayout_impl(boolean changed, int left, int top, int right, int bottom);
+ void onMeasure_impl(int widthMeasureSpec, int heightMeasureSpec);
+ int getSuggestedMinimumWidth_impl();
+ int getSuggestedMinimumHeight_impl();
+ void setMeasuredDimension_impl(int measuredWidth, int measuredHeight);
+
+ // ViewGroup methods
+ boolean checkLayoutParams_impl(LayoutParams p);
+ LayoutParams generateDefaultLayoutParams_impl();
+ LayoutParams generateLayoutParams_impl(AttributeSet attrs);
+ LayoutParams generateLayoutParams_impl(LayoutParams lp);
+ boolean shouldDelayChildPressedState_impl();
+ void measureChildWithMargins_impl(View child, int parentWidthMeasureSpec, int widthUsed,
+ int parentHeightMeasureSpec, int heightUsed);
+
+ // ViewManager methods
+ // ViewParent methods
+}
diff --git a/media/java/android/media/update/ViewProvider.java b/media/java/android/media/update/ViewProvider.java
deleted file mode 100644
index 0dd8f38..0000000
--- a/media/java/android/media/update/ViewProvider.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.media.update;
-
-import android.annotation.SystemApi;
-import android.view.MotionEvent;
-
-/**
- * Interface for connecting the public API to an updatable implementation.
- *
- * Each instance object is connected to one corresponding updatable object which implements the
- * runtime behavior of that class. There should a corresponding provider method for all public
- * methods.
- *
- * All methods behave as per their namesake in the public API.
- *
- * @see android.view.View
- *
- * @hide
- */
-// TODO @SystemApi
-public interface ViewProvider {
- // TODO Add more (all?) methods from View
- void onAttachedToWindow_impl();
- void onDetachedFromWindow_impl();
- CharSequence getAccessibilityClassName_impl();
- boolean onTouchEvent_impl(MotionEvent ev);
- boolean onTrackballEvent_impl(MotionEvent ev);
- void onFinishInflate_impl();
- void setEnabled_impl(boolean enabled);
-}
diff --git a/media/jni/android_media_MediaPlayer2.cpp b/media/jni/android_media_MediaPlayer2.cpp
index 90ee8a6..27eaed0 100644
--- a/media/jni/android_media_MediaPlayer2.cpp
+++ b/media/jni/android_media_MediaPlayer2.cpp
@@ -19,12 +19,16 @@
#define LOG_TAG "MediaPlayer2-JNI"
#include "utils/Log.h"
+#include <sys/stat.h>
+
#include <media/mediaplayer2.h>
#include <media/AudioResamplerPublic.h>
+#include <media/DataSourceDesc.h>
#include <media/MediaHTTPService.h>
#include <media/MediaPlayer2Interface.h>
#include <media/MediaAnalyticsItem.h>
#include <media/NdkWrapper.h>
+#include <media/stagefright/Utils.h>
#include <media/stagefright/foundation/ByteUtils.h> // for FOURCC definition
#include <stdio.h>
#include <assert.h>
@@ -234,7 +238,8 @@
// event to the client application; otherwise, if exception is not NULL and
// opStatus is not OK, this method throws the given exception to the client
// application.
-static void process_media_player_call(JNIEnv *env, jobject thiz, status_t opStatus, const char* exception, const char *message)
+static void process_media_player_call(
+ JNIEnv *env, jobject thiz, status_t opStatus, const char* exception, const char *message)
{
if (exception == NULL) { // Don't throw exception. Instead, send an event.
if (opStatus != (status_t) OK) {
@@ -268,7 +273,7 @@
jobjectArray keys, jobjectArray values) {
sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
- if (mp == NULL ) {
+ if (mp == NULL) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
return;
}
@@ -282,16 +287,25 @@
if (tmp == NULL) { // Out of memory
return;
}
- ALOGV("setDataSource: path %s", tmp);
+ ALOGV("setDataSourceAndHeaders: path %s", tmp);
- String8 pathStr(tmp);
+ if (strncmp(tmp, "content://", 10) == 0) {
+ ALOGE("setDataSourceAndHeaders: content scheme is not supported in native code");
+ jniThrowException(env, "java/io/IOException",
+ "content scheme is not supported in native code");
+ return;
+ }
+
+ sp<DataSourceDesc> dsd = new DataSourceDesc();
+ dsd->mType = DataSourceDesc::TYPE_URL;
+ dsd->mUrl = tmp;
+
env->ReleaseStringUTFChars(path, tmp);
tmp = NULL;
// We build a KeyedVector out of the key and val arrays
- KeyedVector<String8, String8> headersVector;
if (!ConvertKeyValueArraysToKeyedVector(
- env, keys, values, &headersVector)) {
+ env, keys, values, &dsd->mHeaders)) {
return;
}
@@ -299,20 +313,16 @@
if (httpServiceObj != NULL) {
httpService = new JMedia2HTTPService(env, httpServiceObj);
}
-
- status_t opStatus =
- mp->setDataSource(
- httpService,
- pathStr,
- headersVector.size() > 0? &headersVector : NULL);
+ dsd->mHttpService = httpService;
process_media_player_call(
- env, thiz, opStatus, "java/io/IOException",
- "setDataSource failed." );
+ env, thiz, mp->setDataSource(dsd), "java/io/IOException",
+ "setDataSourceAndHeaders failed." );
}
static void
-android_media_MediaPlayer2_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length)
+android_media_MediaPlayer2_setDataSourceFD(
+ JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length)
{
sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
if (mp == NULL ) {
@@ -325,12 +335,46 @@
return;
}
int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
- ALOGV("setDataSourceFD: fd %d", fd);
- process_media_player_call( env, thiz, mp->setDataSource(fd, offset, length), "java/io/IOException", "setDataSourceFD failed." );
+ ALOGV("setDataSourceFD: fd=%d (%s), offset=%lld, length=%lld",
+ fd, nameForFd(fd).c_str(), (long long)offset, (long long)length);
+
+ struct stat sb;
+ int ret = fstat(fd, &sb);
+ if (ret != 0) {
+ ALOGE("setDataSourceFD: fstat(%d) failed: %d, %s", fd, ret, strerror(errno));
+ jniThrowException(env, "java/io/IOException", "setDataSourceFD failed fstat");
+ return;
+ }
+
+ ALOGV("st_dev = %llu", static_cast<unsigned long long>(sb.st_dev));
+ ALOGV("st_mode = %u", sb.st_mode);
+ ALOGV("st_uid = %lu", static_cast<unsigned long>(sb.st_uid));
+ ALOGV("st_gid = %lu", static_cast<unsigned long>(sb.st_gid));
+ ALOGV("st_size = %llu", static_cast<unsigned long long>(sb.st_size));
+
+ if (offset >= sb.st_size) {
+ ALOGE("setDataSourceFD: offset is out of range");
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "setDataSourceFD failed, offset is out of range.");
+ return;
+ }
+ if (offset + length > sb.st_size) {
+ length = sb.st_size - offset;
+ ALOGV("setDataSourceFD: adjusted length = %lld", (long long)length);
+ }
+
+ sp<DataSourceDesc> dsd = new DataSourceDesc();
+ dsd->mType = DataSourceDesc::TYPE_FD;
+ dsd->mFD = fd;
+ dsd->mFDOffset = offset;
+ dsd->mFDLength = length;
+ process_media_player_call(env, thiz, mp->setDataSource(dsd),
+ "java/io/IOException", "setDataSourceFD failed." );
}
static void
-android_media_MediaPlayer2_setDataSourceCallback(JNIEnv *env, jobject thiz, jobject dataSource)
+android_media_MediaPlayer2_setDataSourceCallback(
+ JNIEnv *env, jobject thiz, jobject dataSource)
{
sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
if (mp == NULL ) {
@@ -343,7 +387,11 @@
return;
}
sp<DataSource> callbackDataSource = new JMedia2DataSource(env, dataSource);
- process_media_player_call(env, thiz, mp->setDataSource(callbackDataSource), "java/lang/RuntimeException", "setDataSourceCallback failed." );
+ sp<DataSourceDesc> dsd = new DataSourceDesc();
+ dsd->mType = DataSourceDesc::TYPE_CALLBACK;
+ dsd->mCallbackSource = callbackDataSource;
+ process_media_player_call(env, thiz, mp->setDataSource(dsd),
+ "java/lang/RuntimeException", "setDataSourceCallback failed." );
}
static sp<ANativeWindowWrapper>
@@ -1099,45 +1147,6 @@
process_media_player_call( env, thiz, mp->attachAuxEffect(effectId), NULL, NULL );
}
-static jint
-android_media_MediaPlayer2_setRetransmitEndpoint(JNIEnv *env, jobject thiz,
- jstring addrString, jint port) {
- sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
- if (mp == NULL ) {
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
- return INVALID_OPERATION;
- }
-
- const char *cAddrString = NULL;
-
- if (NULL != addrString) {
- cAddrString = env->GetStringUTFChars(addrString, NULL);
- if (cAddrString == NULL) { // Out of memory
- return NO_MEMORY;
- }
- }
- ALOGV("setRetransmitEndpoint: %s:%d",
- cAddrString ? cAddrString : "(null)", port);
-
- status_t ret;
- if (cAddrString && (port > 0xFFFF)) {
- ret = BAD_VALUE;
- } else {
- ret = mp->setRetransmitEndpoint(cAddrString,
- static_cast<uint16_t>(port));
- }
-
- if (NULL != addrString) {
- env->ReleaseStringUTFChars(addrString, cAddrString);
- }
-
- if (ret == INVALID_OPERATION ) {
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
- }
-
- return (jint) ret;
-}
-
static void
android_media_MediaPlayer2_setNextMediaPlayer(JNIEnv *env, jobject thiz, jobject java_player)
{
@@ -1418,7 +1427,6 @@
{"setAudioSessionId", "(I)V", (void *)android_media_MediaPlayer2_set_audio_session_id},
{"_setAuxEffectSendLevel", "(F)V", (void *)android_media_MediaPlayer2_setAuxEffectSendLevel},
{"attachAuxEffect", "(I)V", (void *)android_media_MediaPlayer2_attachAuxEffect},
- {"native_setRetransmitEndpoint", "(Ljava/lang/String;I)I", (void *)android_media_MediaPlayer2_setRetransmitEndpoint},
{"setNextMediaPlayer", "(Landroid/media/MediaPlayer2;)V", (void *)android_media_MediaPlayer2_setNextMediaPlayer},
// Modular DRM
{ "_prepareDrm", "([B[B)V", (void *)android_media_MediaPlayer2_prepareDrm },
diff --git a/native/android/Android.bp b/native/android/Android.bp
index 00fe638..4fb5e74 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -48,6 +48,7 @@
"sensor.cpp",
"sharedmem.cpp",
"storage_manager.cpp",
+ "surface_texture.cpp",
"trace.cpp",
],
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index 3d5ee39..d6dcd72 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -205,6 +205,14 @@
AStorageManager_mountObb;
AStorageManager_new;
AStorageManager_unmountObb;
+ ASurfaceTexture_acquireANativeWindow; # introduced=28
+ ASurfaceTexture_attachToGLContext; # introduced=28
+ ASurfaceTexture_detachFromGLContext; # introduced=28
+ ASurfaceTexture_fromSurfaceTexture; # introduced=28
+ ASurfaceTexture_getTimestamp; # introduced=28
+ ASurfaceTexture_getTransformMatrix; # introduced=28
+ ASurfaceTexture_release; # introduced=28
+ ASurfaceTexture_updateTexImage; # introduced=28
ATrace_beginSection; # introduced=23
ATrace_endSection; # introduced=23
ATrace_isEnabled; # introduced=23
diff --git a/native/android/surface_texture.cpp b/native/android/surface_texture.cpp
new file mode 100644
index 0000000..b266881
--- /dev/null
+++ b/native/android/surface_texture.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/surface_texture.h>
+#include <android/surface_texture_jni.h>
+
+#define LOG_TAG "ASurfaceTexture"
+
+#include <utils/Log.h>
+
+#include <gui/GLConsumer.h>
+#include <gui/Surface.h>
+
+#include <android_runtime/android_graphics_SurfaceTexture.h>
+
+using namespace android;
+
+struct ASurfaceTexture {
+ sp<GLConsumer> consumer;
+ sp<IGraphicBufferProducer> producer;
+};
+
+ASurfaceTexture* ASurfaceTexture_fromSurfaceTexture(JNIEnv* env, jobject surfacetexture) {
+ if (!surfacetexture || !android_SurfaceTexture_isInstanceOf(env, surfacetexture)) {
+ return nullptr;
+ }
+ ASurfaceTexture* ast = new ASurfaceTexture;
+ ast->consumer = SurfaceTexture_getSurfaceTexture(env, surfacetexture);
+ ast->producer = SurfaceTexture_getProducer(env, surfacetexture);
+ return ast;
+}
+
+ANativeWindow* ASurfaceTexture_acquireANativeWindow(ASurfaceTexture* st) {
+ sp<Surface> surface = new Surface(st->producer);
+ ANativeWindow* win(surface.get());
+ ANativeWindow_acquire(win);
+ return win;
+}
+
+void ASurfaceTexture_release(ASurfaceTexture* st) {
+ delete st;
+}
+
+int ASurfaceTexture_attachToGLContext(ASurfaceTexture* st, uint32_t tex) {
+ return st->consumer->attachToContext(tex);
+}
+
+int ASurfaceTexture_detachFromGLContext(ASurfaceTexture* st) {
+ return st->consumer->detachFromContext();
+}
+
+int ASurfaceTexture_updateTexImage(ASurfaceTexture* st) {
+ return st->consumer->updateTexImage();
+}
+
+void ASurfaceTexture_getTransformMatrix(ASurfaceTexture* st, float mtx[16]) {
+ st->consumer->getTransformMatrix(mtx);
+}
+
+int64_t ASurfaceTexture_getTimestamp(ASurfaceTexture* st) {
+ return st->consumer->getTimestamp();
+}
diff --git a/packages/ExtServices/src/android/ext/services/notification/Assistant.java b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
index 6fe8975..9a66b07 100644
--- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java
+++ b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
@@ -94,7 +94,7 @@
infile = mFile.openRead();
readXml(infile);
} catch (FileNotFoundException e) {
- // No data yet
+ Log.d(TAG, "File doesn't exist or isn't readable yet");
} catch (IOException e) {
Log.e(TAG, "Unable to read channel impressions", e);
} catch (NumberFormatException | XmlPullParserException e) {
diff --git a/packages/ExtServices/tests/src/android/ext/services/notification/AssistantTest.java b/packages/ExtServices/tests/src/android/ext/services/notification/AssistantTest.java
index 7c35b48..db48f61 100644
--- a/packages/ExtServices/tests/src/android/ext/services/notification/AssistantTest.java
+++ b/packages/ExtServices/tests/src/android/ext/services/notification/AssistantTest.java
@@ -325,7 +325,8 @@
int dismiss2 = 777;
String key2 = mAssistant.getKey("pkg2", 2, "channel2");
- String xml = "<assistant version=\"1\">\n"
+ String xml = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<assistant version=\"1\">\n"
+ "<impression-set key=\"" + key1 + "\" "
+ "dismisses=\"" + dismiss1 + "\" views=\"" + views1
+ "\" streak=\"" + streak1 + "\"/>\n"
@@ -377,7 +378,6 @@
mAssistant.insertImpressions(key2, ci2);
mAssistant.insertImpressions(key3, ci3);
-
XmlSerializer serializer = new FastXmlSerializer();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index e11017c..f699440 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -622,6 +622,19 @@
return builder.toString();
}
+ public static String getKey(WifiConfiguration config) {
+ StringBuilder builder = new StringBuilder();
+
+ if (TextUtils.isEmpty(config.SSID)) {
+ builder.append(config.BSSID);
+ } else {
+ builder.append(removeDoubleQuotes(config.SSID));
+ }
+
+ builder.append(',').append(getSecurity(config));
+ return builder.toString();
+ }
+
public String getKey() {
return mKey;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 1ac56a9..fac585e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -92,8 +92,6 @@
* and used so as to assist with in-the-field WiFi connectivity debugging */
public static boolean sVerboseLogging;
- // TODO(b/36733768): Remove flag includeSaved
-
// TODO: Allow control of this?
// Combo scans can take 5-6s to complete - set to 10s.
private static final int WIFI_RESCAN_INTERVAL_MS = 10 * 1000;
@@ -106,8 +104,6 @@
private final NetworkRequest mNetworkRequest;
private final AtomicBoolean mConnected = new AtomicBoolean(false);
private final WifiListener mListener;
- private final boolean mIncludeSaved;
- private final boolean mIncludeScans;
@VisibleForTesting MainHandler mMainHandler;
@VisibleForTesting WorkHandler mWorkHandler;
private HandlerThread mWorkThread;
@@ -150,7 +146,6 @@
// TODO(sghuman): Change this to be keyed on AccessPoint.getKey
private final HashMap<String, ScanResult> mScanResultCache = new HashMap<>();
- private Integer mScanId = 0;
private NetworkInfo mLastNetworkInfo;
private WifiInfo mLastInfo;
@@ -189,16 +184,18 @@
@Deprecated
public WifiTracker(Context context, WifiListener wifiListener,
boolean includeSaved, boolean includeScans) {
- this(context, wifiListener, includeSaved, includeScans,
+ this(context, wifiListener,
context.getSystemService(WifiManager.class),
context.getSystemService(ConnectivityManager.class),
context.getSystemService(NetworkScoreManager.class),
newIntentFilter());
}
+ // TODO(Sghuman): Clean up includeSaved and includeScans from all constructors and linked
+ // calling apps once IC window is complete
public WifiTracker(Context context, WifiListener wifiListener,
@NonNull Lifecycle lifecycle, boolean includeSaved, boolean includeScans) {
- this(context, wifiListener, includeSaved, includeScans,
+ this(context, wifiListener,
context.getSystemService(WifiManager.class),
context.getSystemService(ConnectivityManager.class),
context.getSystemService(NetworkScoreManager.class),
@@ -208,19 +205,13 @@
@VisibleForTesting
WifiTracker(Context context, WifiListener wifiListener,
- boolean includeSaved, boolean includeScans,
WifiManager wifiManager, ConnectivityManager connectivityManager,
NetworkScoreManager networkScoreManager,
IntentFilter filter) {
- if (!includeSaved && !includeScans) {
- throw new IllegalArgumentException("Must include either saved or scans");
- }
mContext = context;
mMainHandler = new MainHandler(Looper.getMainLooper());
mWifiManager = wifiManager;
- mIncludeSaved = includeSaved;
- mIncludeScans = includeScans;
- mListener = wifiListener;
+ mListener = new WifiListenerWrapper(wifiListener);
mConnectivityManager = connectivityManager;
// check if verbose logging has been turned on or off
@@ -458,7 +449,6 @@
private void handleResume() {
mScanResultCache.clear();
mSeenBssids.clear();
- mScanId = 0;
}
private Collection<ScanResult> updateScanResultCache(final List<ScanResult> newResults) {
@@ -533,7 +523,7 @@
/**
* Update the internal list of access points.
*
- * <p>Do not called directly (except for forceUpdate), use {@link #updateAccessPoints()} which
+ * <p>Do not call directly (except for forceUpdate), use {@link #updateAccessPoints()} which
* respects {@link #mStaleScanResults}.
*/
@GuardedBy("mLock")
@@ -542,7 +532,7 @@
WifiConfiguration connectionConfig = null;
if (mLastInfo != null) {
connectionConfig = getWifiConfigurationForNetworkId(
- mLastInfo.getNetworkId(), mWifiManager.getConfiguredNetworks());
+ mLastInfo.getNetworkId(), configs);
}
// Swap the current access points into a cached list.
@@ -554,43 +544,12 @@
accessPoint.clearConfig();
}
- /* Lookup table to more quickly update AccessPoints by only considering objects with the
- * correct SSID. Maps SSID -> List of AccessPoints with the given SSID. */
- Multimap<String, AccessPoint> existingApMap = new Multimap<String, AccessPoint>();
-
final Collection<ScanResult> results = updateScanResultCache(newScanResults);
- // TODO(sghuman): This entire block only exists to populate the WifiConfiguration for
- // APs, remove and refactor
+ final Map<String, WifiConfiguration> configsByKey = new ArrayMap(configs.size());
if (configs != null) {
for (WifiConfiguration config : configs) {
- if (config.selfAdded && config.numAssociation == 0) {
- continue;
- }
- AccessPoint accessPoint = getCachedOrCreate(config, cachedAccessPoints);
- if (mLastInfo != null && mLastNetworkInfo != null) {
- accessPoint.update(connectionConfig, mLastInfo, mLastNetworkInfo);
- }
- if (mIncludeSaved) {
- // If saved network not present in scan result then set its Rssi to
- // UNREACHABLE_RSSI
- boolean apFound = false;
- for (ScanResult result : results) {
- if (result.SSID.equals(accessPoint.getSsidStr())) {
- apFound = true;
- break;
- }
- }
- if (!apFound) {
- accessPoint.setUnreachable();
- }
- accessPoints.add(accessPoint);
- existingApMap.put(accessPoint.getSsidStr(), accessPoint);
- } else {
- // If we aren't using saved networks, drop them into the cache so that
- // we have access to their saved info.
- cachedAccessPoints.add(accessPoint);
- }
+ configsByKey.put(AccessPoint.getKey(config), config);
}
}
@@ -626,40 +585,20 @@
for (Map.Entry<String, List<ScanResult>> entry : scanResultsByApKey.entrySet()) {
// List can not be empty as it is dynamically constructed on each iteration
ScanResult firstResult = entry.getValue().get(0);
- boolean found = false;
- for (AccessPoint accessPoint : existingApMap.getAll(firstResult.SSID)) {
- accessPoint.setScanResults(entry.getValue());
- found = true;
- break;
+
+ AccessPoint accessPoint =
+ getCachedOrCreate(entry.getValue(), cachedAccessPoints);
+ if (mLastInfo != null && mLastNetworkInfo != null) {
+ accessPoint.update(connectionConfig, mLastInfo, mLastNetworkInfo);
}
- // Only create a new AP / add to the list if it wasn't already in the saved configs
- if (!found) {
- AccessPoint accessPoint =
- getCachedOrCreate(entry.getValue(), cachedAccessPoints);
- if (mLastInfo != null && mLastNetworkInfo != null) {
- accessPoint.update(connectionConfig, mLastInfo, mLastNetworkInfo);
- }
-
- // TODO(sghuman): Move isPasspointNetwork logic into AccessPoint.java
- if (firstResult.isPasspointNetwork()) {
- // Retrieve a WifiConfiguration for a Passpoint provider that matches
- // the given ScanResult. This is used for showing that a given AP
- // (ScanResult) is available via a Passpoint provider (provider friendly
- // name).
- try {
- WifiConfiguration config =
- mWifiManager.getMatchingWifiConfig(firstResult);
- if (config != null) {
- accessPoint.update(config);
- }
- } catch (UnsupportedOperationException e) {
- // Passpoint not supported on the device.
- }
- }
-
- accessPoints.add(accessPoint);
+ // Update the matching config if there is one, to populate saved network info
+ WifiConfiguration config = configsByKey.get(entry.getKey());
+ if (config != null) {
+ accessPoint.update(config);
}
+
+ accessPoints.add(accessPoint);
}
}
@@ -1052,6 +991,39 @@
}
}
+ /**
+ * Wraps the given {@link WifiListener} instance and executes it's methods on the Main Thread.
+ *
+ * <p>This mechanism allows us to no longer need a separate MainHandler and WorkHandler, which
+ * were previously both performing work, while avoiding errors which occur from executing
+ * callbacks which manipulate UI elements from a different thread than the MainThread.
+ */
+ private static class WifiListenerWrapper implements WifiListener {
+
+ private final Handler mHandler;
+ private final WifiListener mDelegatee;
+
+ public WifiListenerWrapper(WifiListener listener) {
+ mHandler = new Handler(Looper.getMainLooper());
+ mDelegatee = listener;
+ }
+
+ @Override
+ public void onWifiStateChanged(int state) {
+ mHandler.post(() -> mDelegatee.onWifiStateChanged(state));
+ }
+
+ @Override
+ public void onConnectedChanged() {
+ mHandler.post(() -> mDelegatee.onConnectedChanged());
+ }
+
+ @Override
+ public void onAccessPointsChanged() {
+ mHandler.post(() -> mDelegatee.onAccessPointsChanged());
+ }
+ }
+
public interface WifiListener {
/**
* Called when the state of Wifi has changed, the state will be one of
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
index b36dda9..6be4936 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
@@ -281,8 +281,6 @@
final WifiTracker wifiTracker = new WifiTracker(
mContext,
mockWifiListener,
- true,
- true,
mockWifiManager,
mockConnectivityManager,
mockNetworkScoreManager,
@@ -687,6 +685,7 @@
*/
@Test
public void trackPasspointApWithPasspointDisabled() throws Exception {
+ // TODO(sghuman): Delete this test and replace with a passpoint test
WifiTracker tracker = createMockedWifiTracker();
// Add a Passpoint AP to the scan results.
@@ -709,10 +708,7 @@
when(mockWifiManager.getConfiguredNetworks())
.thenReturn(new ArrayList<WifiConfiguration>());
when(mockWifiManager.getScanResults()).thenReturn(results);
- doThrow(new UnsupportedOperationException())
- .when(mockWifiManager).getMatchingWifiConfig(any(ScanResult.class));
tracker.forceUpdate();
- verify(mockWifiManager).getMatchingWifiConfig(any(ScanResult.class));
}
@Test
@@ -758,7 +754,7 @@
tracker.forceUpdate();
verify(mockWifiManager).getConnectionInfo();
- verify(mockWifiManager, times(2)).getConfiguredNetworks();
+ verify(mockWifiManager, times(1)).getConfiguredNetworks();
verify(mockConnectivityManager).getNetworkInfo(any(Network.class));
verify(mockWifiListener, never()).onAccessPointsChanged(); // mStaleAccessPoints is true
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index b286f89..537e8dc 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -523,9 +523,6 @@
Settings.Global.WIFI_WAKEUP_ENABLED,
GlobalSettingsProto.WIFI_WAKEUP_ENABLED);
dumpSetting(s, p,
- Settings.Global.WIFI_WAKEUP_AVAILABLE,
- GlobalSettingsProto.WIFI_WAKEUP_AVAILABLE);
- dumpSetting(s, p,
Settings.Global.NETWORK_SCORING_UI_ENABLED,
GlobalSettingsProto.NETWORK_SCORING_UI_ENABLED);
dumpSetting(s, p,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index d1459bb..adb4dbf 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -2328,7 +2328,9 @@
// Get all uids for the user's packages.
final List<PackageInfo> packages;
try {
- packages = mPackageManager.getInstalledPackages(0, user.id).getList();
+ packages = mPackageManager.getInstalledPackages(
+ PackageManager.MATCH_UNINSTALLED_PACKAGES,
+ user.id).getList();
} catch (RemoteException e) {
throw new IllegalStateException("Package manager not available");
}
@@ -3015,7 +3017,7 @@
}
private final class UpgradeController {
- private static final int SETTINGS_VERSION = 152;
+ private static final int SETTINGS_VERSION = 153;
private final int mUserId;
@@ -3401,7 +3403,9 @@
// Fill each uid with the legacy ssaid to be backwards compatible.
final List<PackageInfo> packages;
try {
- packages = mPackageManager.getInstalledPackages(0, userId).getList();
+ packages = mPackageManager.getInstalledPackages(
+ PackageManager.MATCH_UNINSTALLED_PACKAGES,
+ userId).getList();
} catch (RemoteException e) {
throw new IllegalStateException("Package manager not available");
}
@@ -3416,6 +3420,9 @@
// Android Id doesn't exist for this package so create it.
ssaidSettings.insertSettingLocked(uid, legacySsaid, null, true,
info.packageName);
+ if (DEBUG) {
+ Slog.d(LOG_TAG, "Keep the legacy ssaid for uid=" + uid);
+ }
}
}
}
@@ -3540,21 +3547,9 @@
}
if (currentVersion == 146) {
- // Version 147: Set the default value for WIFI_WAKEUP_AVAILABLE.
- if (userId == UserHandle.USER_SYSTEM) {
- final SettingsState globalSettings = getGlobalSettingsLocked();
- final Setting currentSetting = globalSettings.getSettingLocked(
- Settings.Global.WIFI_WAKEUP_AVAILABLE);
- if (currentSetting.getValue() == null) {
- final int defaultValue = getContext().getResources().getInteger(
- com.android.internal.R.integer.config_wifi_wakeup_available);
- globalSettings.insertSettingLocked(
- Settings.Global.WIFI_WAKEUP_AVAILABLE,
- String.valueOf(defaultValue),
- null, true, SettingsState.SYSTEM_PACKAGE_NAME);
- }
- }
-
+ // Version 147: Removed. (This version previously allowed showing the
+ // "wifi_wakeup_available" setting).
+ // The setting that was added here is deleted in 153.
currentVersion = 147;
}
@@ -3621,18 +3616,17 @@
}
if (currentVersion == 151) {
- // Version 152: Reset wifi wake available for upgrading users
- final SettingsState globalSettings = getGlobalSettingsLocked();
- final int defaultValue = getContext().getResources().getInteger(
- com.android.internal.R.integer.config_wifi_wakeup_available);
- globalSettings.insertSettingLocked(
- Settings.Global.WIFI_WAKEUP_AVAILABLE,
- String.valueOf(defaultValue),
- null, true, SettingsState.SYSTEM_PACKAGE_NAME);
-
+ // Version 152: Removed. (This version made the setting for wifi_wakeup enabled
+ // by default but it is now no longer configurable).
+ // The setting updated here is deleted in 153.
currentVersion = 152;
}
+ if (currentVersion == 152) {
+ getGlobalSettingsLocked().deleteSettingLocked("wifi_wakeup_available");
+ currentVersion = 153;
+ }
+
// vXXX: Add new settings above this point.
if (currentVersion != newVersion) {
diff --git a/packages/SystemUI/res/layout/screen_pinning_request_buttons.xml b/packages/SystemUI/res/layout/screen_pinning_request_buttons.xml
index c2b1009..a3118b0 100644
--- a/packages/SystemUI/res/layout/screen_pinning_request_buttons.xml
+++ b/packages/SystemUI/res/layout/screen_pinning_request_buttons.xml
@@ -84,7 +84,25 @@
android:layout_height="@dimen/screen_pinning_request_button_height"
android:layout_weight="0"
android:paddingStart="@dimen/screen_pinning_request_frame_padding"
- android:paddingEnd="@dimen/screen_pinning_request_frame_padding" >
+ android:paddingEnd="@dimen/screen_pinning_request_frame_padding"
+ android:theme="@*android:style/ThemeOverlay.DeviceDefault.Accent">
+
+ <ImageView
+ android:id="@+id/screen_pinning_home_bg_light"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:scaleType="matrix"
+ android:src="@drawable/screen_pinning_light_bg_circ" />
+
+ <ImageView
+ android:id="@+id/screen_pinning_home_bg"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingEnd="@dimen/screen_pinning_request_inner_padding"
+ android:paddingStart="@dimen/screen_pinning_request_inner_padding"
+ android:paddingTop="@dimen/screen_pinning_request_inner_padding"
+ android:scaleType="matrix"
+ android:src="@drawable/screen_pinning_bg_circ" />
<ImageView
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/screen_pinning_request_buttons_land.xml b/packages/SystemUI/res/layout/screen_pinning_request_buttons_land.xml
index b5ef1d7..61fe906 100644
--- a/packages/SystemUI/res/layout/screen_pinning_request_buttons_land.xml
+++ b/packages/SystemUI/res/layout/screen_pinning_request_buttons_land.xml
@@ -78,7 +78,25 @@
android:id="@+id/screen_pinning_home_group"
android:layout_height="@dimen/screen_pinning_request_button_width"
android:layout_width="@dimen/screen_pinning_request_button_height"
- android:layout_weight="0" >
+ android:layout_weight="0"
+ android:theme="@*android:style/ThemeOverlay.DeviceDefault.Accent">
+
+ <ImageView
+ android:id="@+id/screen_pinning_home_bg_light"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:scaleType="matrix"
+ android:src="@drawable/screen_pinning_light_bg_circ" />
+
+ <ImageView
+ android:id="@+id/screen_pinning_home_bg"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:scaleType="matrix"
+ android:paddingLeft="@dimen/screen_pinning_request_inner_padding"
+ android:paddingTop="@dimen/screen_pinning_request_inner_padding"
+ android:paddingBottom="@dimen/screen_pinning_request_inner_padding"
+ android:src="@drawable/screen_pinning_bg_circ" />
<ImageView
android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/screen_pinning_request_buttons_sea.xml b/packages/SystemUI/res/layout/screen_pinning_request_buttons_sea.xml
index f3a6d44..d1ca2ce 100644
--- a/packages/SystemUI/res/layout/screen_pinning_request_buttons_sea.xml
+++ b/packages/SystemUI/res/layout/screen_pinning_request_buttons_sea.xml
@@ -80,7 +80,27 @@
android:id="@+id/screen_pinning_home_group"
android:layout_height="@dimen/screen_pinning_request_button_width"
android:layout_width="@dimen/screen_pinning_request_button_height"
- android:layout_weight="0" >
+ android:layout_weight="0"
+ android:theme="@*android:style/ThemeOverlay.DeviceDefault.Accent" >
+
+ <ImageView
+ android:id="@+id/screen_pinning_home_bg_light"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:scaleType="matrix"
+ android:layout_marginLeft="@dimen/screen_pinning_request_seascape_padding_negative"
+ android:src="@drawable/screen_pinning_light_bg_circ" />
+
+ <ImageView
+ android:id="@+id/screen_pinning_home_bg"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:scaleType="matrix"
+ android:layout_marginLeft="@dimen/screen_pinning_request_seascape_button_offset"
+ android:paddingRight="@dimen/screen_pinning_request_inner_padding"
+ android:paddingTop="@dimen/screen_pinning_request_inner_padding"
+ android:paddingBottom="@dimen/screen_pinning_request_inner_padding"
+ android:src="@drawable/screen_pinning_bg_circ" />
<ImageView
android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index 53dff05..36298ca 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -20,14 +20,15 @@
android:background="@android:color/transparent"
android:theme="@style/qs_theme"
android:clipChildren="false" >
+ <!-- right-aligned to be physically near volume button -->
<LinearLayout
android:id="@+id/volume_dialog"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center_vertical|end"
+ android:layout_gravity="center_vertical|right"
android:minWidth="@dimen/volume_dialog_panel_width"
android:background="@android:color/transparent"
- android:layout_margin="12dp"
+ android:layout_margin="@dimen/volume_dialog_base_margin"
android:translationZ="8dp"
android:orientation="vertical"
android:clipChildren="false" >
@@ -38,8 +39,8 @@
android:layout_height="wrap_content"
android:clipChildren="false"
android:clipToPadding="false"
- android:paddingTop="12dp"
- android:paddingBottom="12dp"
+ android:paddingTop="10dp"
+ android:paddingBottom="10dp"
android:background="@drawable/rounded_bg_full"
android:translationZ="8dp"
android:orientation="horizontal" >
@@ -71,7 +72,7 @@
android:maxLines="1"
android:layout_centerVertical="true"
android:textColor="?android:attr/colorControlNormal"
- android:textAppearance="?android:attr/textAppearanceSmall" />
+ android:textAppearance="@style/TextAppearance.Volume.Header" />
<com.android.keyguard.AlphaOptimizedImageButton
android:id="@+id/ringer_icon"
@@ -89,7 +90,7 @@
android:ellipsize="end"
android:maxLines="1"
android:textColor="?android:attr/colorControlNormal"
- android:textAppearance="?android:attr/textAppearanceSmall" />
+ android:textAppearance="@style/TextAppearance.Volume.Header.Secondary" />
</LinearLayout>
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/volume_dialog_row.xml b/packages/SystemUI/res/layout/volume_dialog_row.xml
index a9e5adf..70654a8 100644
--- a/packages/SystemUI/res/layout/volume_dialog_row.xml
+++ b/packages/SystemUI/res/layout/volume_dialog_row.xml
@@ -29,15 +29,16 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
- android:padding="10dp">
+ android:padding="5dp">
<TextView
android:id="@+id/volume_row_header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
+ android:maxLength="10"
android:maxLines="1"
android:textColor="?android:attr/colorControlNormal"
- android:textAppearance="?android:attr/textAppearanceSmall" />
+ android:textAppearance="@style/TextAppearance.Volume.Header" />
<LinearLayout
android:id="@+id/output_chooser"
android:orientation="vertical"
@@ -53,9 +54,10 @@
android:visibility="gone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:maxLength="10"
android:ellipsize="end"
android:maxLines="1"
- android:textAppearance="@style/TextAppearance.QS.DetailItemSecondary" />
+ android:textAppearance="@style/TextAppearance.Volume.Header.Secondary" />
<com.android.keyguard.AlphaOptimizedImageButton
android:id="@+id/output_chooser_button"
android:layout_width="24dp"
@@ -73,15 +75,18 @@
android:id="@+id/volume_row_slider_frame"
android:padding="0dp"
android:layout_width="@dimen/volume_dialog_panel_width"
- android:layout_height="150dp">
+ android:layoutDirection="rtl"
+ android:layout_height="@dimen/volume_dialog_panel_width">
<SeekBar
android:id="@+id/volume_row_slider"
+ android:clickable="true"
android:padding="0dp"
android:layout_margin="0dp"
- android:layout_width="150dp"
+ android:layout_width="@dimen/volume_dialog_panel_width"
android:layout_height="@dimen/volume_dialog_panel_width"
+ android:layoutDirection="rtl"
android:layout_gravity="center"
- android:rotation="270" />
+ android:rotation="90" />
</FrameLayout>
<com.android.keyguard.AlphaOptimizedImageButton
diff --git a/packages/SystemUI/res/values-af/config.xml b/packages/SystemUI/res/values-af/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-af/config.xml
+++ b/packages/SystemUI/res/values-af/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-am/config.xml b/packages/SystemUI/res/values-am/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-am/config.xml
+++ b/packages/SystemUI/res/values-am/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-ar/config.xml b/packages/SystemUI/res/values-ar/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-ar/config.xml
+++ b/packages/SystemUI/res/values-ar/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-az/config.xml b/packages/SystemUI/res/values-az/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-az/config.xml
+++ b/packages/SystemUI/res/values-az/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/config.xml b/packages/SystemUI/res/values-b+sr+Latn/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/config.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-be/config.xml b/packages/SystemUI/res/values-be/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-be/config.xml
+++ b/packages/SystemUI/res/values-be/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-bg/config.xml b/packages/SystemUI/res/values-bg/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-bg/config.xml
+++ b/packages/SystemUI/res/values-bg/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-bn/config.xml b/packages/SystemUI/res/values-bn/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-bn/config.xml
+++ b/packages/SystemUI/res/values-bn/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-bs/config.xml b/packages/SystemUI/res/values-bs/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-bs/config.xml
+++ b/packages/SystemUI/res/values-bs/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-ca/config.xml b/packages/SystemUI/res/values-ca/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-ca/config.xml
+++ b/packages/SystemUI/res/values-ca/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-cs/config.xml b/packages/SystemUI/res/values-cs/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-cs/config.xml
+++ b/packages/SystemUI/res/values-cs/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-da/config.xml b/packages/SystemUI/res/values-da/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-da/config.xml
+++ b/packages/SystemUI/res/values-da/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-de/config.xml b/packages/SystemUI/res/values-de/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-de/config.xml
+++ b/packages/SystemUI/res/values-de/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-el/config.xml b/packages/SystemUI/res/values-el/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-el/config.xml
+++ b/packages/SystemUI/res/values-el/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/config.xml b/packages/SystemUI/res/values-en-rAU/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-en-rAU/config.xml
+++ b/packages/SystemUI/res/values-en-rAU/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rCA/config.xml b/packages/SystemUI/res/values-en-rCA/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-en-rCA/config.xml
+++ b/packages/SystemUI/res/values-en-rCA/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/config.xml b/packages/SystemUI/res/values-en-rGB/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-en-rGB/config.xml
+++ b/packages/SystemUI/res/values-en-rGB/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/config.xml b/packages/SystemUI/res/values-en-rIN/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-en-rIN/config.xml
+++ b/packages/SystemUI/res/values-en-rIN/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rXC/config.xml b/packages/SystemUI/res/values-en-rXC/config.xml
index f015d9b..5309563 100644
--- a/packages/SystemUI/res/values-en-rXC/config.xml
+++ b/packages/SystemUI/res/values-en-rXC/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/config.xml b/packages/SystemUI/res/values-es-rUS/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-es-rUS/config.xml
+++ b/packages/SystemUI/res/values-es-rUS/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-es/config.xml b/packages/SystemUI/res/values-es/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-es/config.xml
+++ b/packages/SystemUI/res/values-es/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-et/config.xml b/packages/SystemUI/res/values-et/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-et/config.xml
+++ b/packages/SystemUI/res/values-et/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-eu/config.xml b/packages/SystemUI/res/values-eu/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-eu/config.xml
+++ b/packages/SystemUI/res/values-eu/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-fa/config.xml b/packages/SystemUI/res/values-fa/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-fa/config.xml
+++ b/packages/SystemUI/res/values-fa/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-fi/config.xml b/packages/SystemUI/res/values-fi/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-fi/config.xml
+++ b/packages/SystemUI/res/values-fi/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/config.xml b/packages/SystemUI/res/values-fr-rCA/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-fr-rCA/config.xml
+++ b/packages/SystemUI/res/values-fr-rCA/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-fr/config.xml b/packages/SystemUI/res/values-fr/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-fr/config.xml
+++ b/packages/SystemUI/res/values-fr/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-gl/config.xml b/packages/SystemUI/res/values-gl/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-gl/config.xml
+++ b/packages/SystemUI/res/values-gl/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-gu/config.xml b/packages/SystemUI/res/values-gu/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-gu/config.xml
+++ b/packages/SystemUI/res/values-gu/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-hi/config.xml b/packages/SystemUI/res/values-hi/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-hi/config.xml
+++ b/packages/SystemUI/res/values-hi/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-hr/config.xml b/packages/SystemUI/res/values-hr/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-hr/config.xml
+++ b/packages/SystemUI/res/values-hr/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-hu/config.xml b/packages/SystemUI/res/values-hu/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-hu/config.xml
+++ b/packages/SystemUI/res/values-hu/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-hy/config.xml b/packages/SystemUI/res/values-hy/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-hy/config.xml
+++ b/packages/SystemUI/res/values-hy/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-in/config.xml b/packages/SystemUI/res/values-in/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-in/config.xml
+++ b/packages/SystemUI/res/values-in/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-is/config.xml b/packages/SystemUI/res/values-is/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-is/config.xml
+++ b/packages/SystemUI/res/values-is/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-it/config.xml b/packages/SystemUI/res/values-it/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-it/config.xml
+++ b/packages/SystemUI/res/values-it/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-iw/config.xml b/packages/SystemUI/res/values-iw/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-iw/config.xml
+++ b/packages/SystemUI/res/values-iw/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-ja/config.xml b/packages/SystemUI/res/values-ja/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-ja/config.xml
+++ b/packages/SystemUI/res/values-ja/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-ka/config.xml b/packages/SystemUI/res/values-ka/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-ka/config.xml
+++ b/packages/SystemUI/res/values-ka/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-kk/config.xml b/packages/SystemUI/res/values-kk/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-kk/config.xml
+++ b/packages/SystemUI/res/values-kk/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-km/config.xml b/packages/SystemUI/res/values-km/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-km/config.xml
+++ b/packages/SystemUI/res/values-km/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-kn/config.xml b/packages/SystemUI/res/values-kn/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-kn/config.xml
+++ b/packages/SystemUI/res/values-kn/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-ko/config.xml b/packages/SystemUI/res/values-ko/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-ko/config.xml
+++ b/packages/SystemUI/res/values-ko/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-ky/config.xml b/packages/SystemUI/res/values-ky/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-ky/config.xml
+++ b/packages/SystemUI/res/values-ky/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-lo/config.xml b/packages/SystemUI/res/values-lo/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-lo/config.xml
+++ b/packages/SystemUI/res/values-lo/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-lt/config.xml b/packages/SystemUI/res/values-lt/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-lt/config.xml
+++ b/packages/SystemUI/res/values-lt/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-lv/config.xml b/packages/SystemUI/res/values-lv/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-lv/config.xml
+++ b/packages/SystemUI/res/values-lv/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-mk/config.xml b/packages/SystemUI/res/values-mk/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-mk/config.xml
+++ b/packages/SystemUI/res/values-mk/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-ml/config.xml b/packages/SystemUI/res/values-ml/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-ml/config.xml
+++ b/packages/SystemUI/res/values-ml/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-mn/config.xml b/packages/SystemUI/res/values-mn/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-mn/config.xml
+++ b/packages/SystemUI/res/values-mn/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-mr/config.xml b/packages/SystemUI/res/values-mr/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-mr/config.xml
+++ b/packages/SystemUI/res/values-mr/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-ms/config.xml b/packages/SystemUI/res/values-ms/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-ms/config.xml
+++ b/packages/SystemUI/res/values-ms/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-my/config.xml b/packages/SystemUI/res/values-my/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-my/config.xml
+++ b/packages/SystemUI/res/values-my/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-nb/config.xml b/packages/SystemUI/res/values-nb/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-nb/config.xml
+++ b/packages/SystemUI/res/values-nb/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-ne/config.xml b/packages/SystemUI/res/values-ne/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-ne/config.xml
+++ b/packages/SystemUI/res/values-ne/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-nl/config.xml b/packages/SystemUI/res/values-nl/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-nl/config.xml
+++ b/packages/SystemUI/res/values-nl/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-pa/config.xml b/packages/SystemUI/res/values-pa/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-pa/config.xml
+++ b/packages/SystemUI/res/values-pa/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-pl/config.xml b/packages/SystemUI/res/values-pl/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-pl/config.xml
+++ b/packages/SystemUI/res/values-pl/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/config.xml b/packages/SystemUI/res/values-pt-rBR/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-pt-rBR/config.xml
+++ b/packages/SystemUI/res/values-pt-rBR/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/config.xml b/packages/SystemUI/res/values-pt-rPT/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-pt-rPT/config.xml
+++ b/packages/SystemUI/res/values-pt-rPT/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-pt/config.xml b/packages/SystemUI/res/values-pt/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-pt/config.xml
+++ b/packages/SystemUI/res/values-pt/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-ro/config.xml b/packages/SystemUI/res/values-ro/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-ro/config.xml
+++ b/packages/SystemUI/res/values-ro/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-ru/config.xml b/packages/SystemUI/res/values-ru/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-ru/config.xml
+++ b/packages/SystemUI/res/values-ru/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-si/config.xml b/packages/SystemUI/res/values-si/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-si/config.xml
+++ b/packages/SystemUI/res/values-si/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-sk/config.xml b/packages/SystemUI/res/values-sk/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-sk/config.xml
+++ b/packages/SystemUI/res/values-sk/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-sl/config.xml b/packages/SystemUI/res/values-sl/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-sl/config.xml
+++ b/packages/SystemUI/res/values-sl/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-sq/config.xml b/packages/SystemUI/res/values-sq/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-sq/config.xml
+++ b/packages/SystemUI/res/values-sq/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-sr/config.xml b/packages/SystemUI/res/values-sr/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-sr/config.xml
+++ b/packages/SystemUI/res/values-sr/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-sv/config.xml b/packages/SystemUI/res/values-sv/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-sv/config.xml
+++ b/packages/SystemUI/res/values-sv/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-sw/config.xml b/packages/SystemUI/res/values-sw/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-sw/config.xml
+++ b/packages/SystemUI/res/values-sw/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-ta/config.xml b/packages/SystemUI/res/values-ta/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-ta/config.xml
+++ b/packages/SystemUI/res/values-ta/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-te/config.xml b/packages/SystemUI/res/values-te/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-te/config.xml
+++ b/packages/SystemUI/res/values-te/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-th/config.xml b/packages/SystemUI/res/values-th/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-th/config.xml
+++ b/packages/SystemUI/res/values-th/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-tl/config.xml b/packages/SystemUI/res/values-tl/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-tl/config.xml
+++ b/packages/SystemUI/res/values-tl/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-tr/config.xml b/packages/SystemUI/res/values-tr/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-tr/config.xml
+++ b/packages/SystemUI/res/values-tr/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-uk/config.xml b/packages/SystemUI/res/values-uk/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-uk/config.xml
+++ b/packages/SystemUI/res/values-uk/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-ur/config.xml b/packages/SystemUI/res/values-ur/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-ur/config.xml
+++ b/packages/SystemUI/res/values-ur/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-uz/config.xml b/packages/SystemUI/res/values-uz/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-uz/config.xml
+++ b/packages/SystemUI/res/values-uz/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-vi/config.xml b/packages/SystemUI/res/values-vi/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-vi/config.xml
+++ b/packages/SystemUI/res/values-vi/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/config.xml b/packages/SystemUI/res/values-zh-rCN/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-zh-rCN/config.xml
+++ b/packages/SystemUI/res/values-zh-rCN/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/config.xml b/packages/SystemUI/res/values-zh-rHK/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-zh-rHK/config.xml
+++ b/packages/SystemUI/res/values-zh-rHK/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/config.xml b/packages/SystemUI/res/values-zh-rTW/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-zh-rTW/config.xml
+++ b/packages/SystemUI/res/values-zh-rTW/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-zu/config.xml b/packages/SystemUI/res/values-zu/config.xml
index 477f219..5309563 100644
--- a/packages/SystemUI/res/values-zu/config.xml
+++ b/packages/SystemUI/res/values-zu/config.xml
@@ -22,6 +22,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="config_overviewServiceComponent" msgid="2288311504315574053">"com.android.launcher3/com.android.quickstep.TouchInteractionService"</string>
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index ae910fe..f2e5d3b 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -46,7 +46,7 @@
<string name="config_statusBarComponent" translatable="false">com.android.systemui.statusbar.phone.StatusBar</string>
<!-- Component name of launcher service for overview to connect to -->
- <string name="config_overviewServiceComponent" translateable="false">com.android.launcher3/com.android.quickstep.TouchInteractionService</string>
+ <string name="config_overviewServiceComponent" translatable="false">com.android.launcher3/com.android.quickstep.TouchInteractionService</string>
<!-- Whether or not we show the number in the bar. -->
<bool name="config_statusBarShowNumber">false</bool>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 3db79d7..e55c65a 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -262,7 +262,11 @@
<!-- The width of the panel that holds the quick settings. -->
<dimen name="qs_panel_width">@dimen/notification_panel_width</dimen>
- <dimen name="volume_dialog_panel_width">120dp</dimen>
+ <!-- the amount the volume panel should be offset at the end from the view next to it (or
+ the scren edge, in portrait-->
+ <dimen name="volume_dialog_base_margin">12dp</dimen>
+
+ <dimen name="volume_dialog_panel_width">100dp</dimen>
<dimen name="output_chooser_panel_width">320dp</dimen>
@@ -332,6 +336,8 @@
<dimen name="qs_footer_padding_start">16dp</dimen>
<dimen name="qs_footer_padding_end">24dp</dimen>
<dimen name="qs_footer_icon_size">16dp</dimen>
+ <!-- Difference between drag handle margin in QQS and expanded QS -->
+ <dimen name="qs_footer_drag_handle_offset">6dp</dimen>
<dimen name="qs_notif_collapsed_space">64dp</dimen>
@@ -902,4 +908,11 @@
<dimen name="config_batteryLevelTextSizeEnd" format="float">32.0</dimen>
<!-- Wireless Charging battery level text animation duration -->
<integer name="config_batteryLevelTextAnimationDuration">400</integer>
+
+ <!-- Wired charging on AOD, text animation duration -->
+ <integer name="wired_charging_aod_text_animation_duration_down">500</integer>
+ <!-- Wired charging on AOD, text animation duration -->
+ <integer name="wired_charging_aod_text_animation_duration_up">300</integer>
+ <!-- Wired charging on AOD, text animation distance -->
+ <integer name="wired_charging_aod_text_animation_distance">-30</integer>
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 5557f8e..fadcbcd 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1281,12 +1281,23 @@
<string name="screen_pinning_title">Screen is pinned</string>
<!-- Screen pinning dialog description. -->
<string name="screen_pinning_description">This keeps it in view until you unpin. Touch & hold Back and Overview to unpin.</string>
+ <string name="screen_pinning_description_recents_invisible">This keeps it in view until you unpin. Touch & hold Back and Home to unpin.</string>
<!-- Screen pinning dialog description. -->
<string name="screen_pinning_description_accessible">This keeps it in view until you unpin. Touch & hold Overview to unpin.</string>
+ <string name="screen_pinning_description_recents_invisible_accessible">This keeps it in view until you unpin. Touch & hold Home to unpin.</string>
+ <!-- Notify use that they are in Lock-to-app -->
+ <string name="screen_pinning_toast">To unpin this screen, touch & hold Back and Overview
+ buttons</string>
+ <string name="screen_pinning_toast_recents_invisible">To unpin this screen, touch & hold Back
+ and Home buttons</string>
<!-- Screen pinning positive response. -->
<string name="screen_pinning_positive">Got it</string>
<!-- Screen pinning negative response. -->
<string name="screen_pinning_negative">No thanks</string>
+ <!-- Enter/Exiting screen pinning indication. -->
+ <string name="screen_pinning_start">Screen pinned</string>
+ <string name="screen_pinning_exit">Screen unpinned</string>
+
<!-- Hide quick settings tile confirmation title -->
<string name="quick_settings_reset_confirmation_title">Hide <xliff:g id="tile_label" example="Hotspot">%1$s</xliff:g>?</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 2497d20..d2ed4d1 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -410,16 +410,11 @@
<item name="android:textColor">?android:attr/textColorSecondary</item>
</style>
- <style name="TextAppearance.Volume.ZenSummary">
- <item name="android:textSize">14sp</item>
- <item name="android:fontFamily">sans-serif-medium</item>
+ <style name="TextAppearance.Volume.Header.Secondary">
+ <item name="android:textSize">12sp</item>
+ <item name="android:textColor">?android:attr/textColorTertiary</item>
</style>
- <style name="TextAppearance.Volume.ZenDetail">
- <item name="android:textSize">14sp</item>
- <item name="android:fontFamily">sans-serif</item>
- <item name="android:textColor">?android:attr/textColorSecondary</item>
- </style>
<style name="VolumeButtons" parent="@android:style/Widget.Material.Button.Borderless">
<item name="android:background">@drawable/btn_borderless_rect</item>
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 f9e1069..90e3b1e 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
@@ -16,6 +16,8 @@
package com.android.systemui.shared.system;
+import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
+import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED;
import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
@@ -31,6 +33,7 @@
import android.app.AppGlobals;
import android.app.IAssistDataReceiver;
import android.app.WindowConfiguration.ActivityType;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
@@ -47,6 +50,7 @@
import android.os.Looper;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.provider.Settings;
import android.util.IconDrawableFactory;
import android.util.Log;
import android.view.IRecentsAnimationController;
@@ -436,4 +440,23 @@
Log.w(TAG, "Failed to cancel window transition for task=" + taskId, e);
}
}
+
+ /**
+ * @return whether there is currently a locked task (ie. in screen pinning).
+ */
+ public boolean isLockToAppActive() {
+ try {
+ return ActivityManager.getService().getLockTaskModeState() != LOCK_TASK_MODE_NONE;
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ /**
+ * @return whether screen pinning is enabled.
+ */
+ public boolean isLockToAppEnabled() {
+ final ContentResolver cr = AppGlobals.getInitialApplication().getContentResolver();
+ return Settings.System.getInt(cr, Settings.System.LOCK_TO_APP_ENABLED, 0) != 0;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/Interpolators.java b/packages/SystemUI/src/com/android/systemui/Interpolators.java
index b8cfa3e..aeef496 100644
--- a/packages/SystemUI/src/com/android/systemui/Interpolators.java
+++ b/packages/SystemUI/src/com/android/systemui/Interpolators.java
@@ -18,6 +18,7 @@
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.AccelerateInterpolator;
+import android.view.animation.BounceInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
@@ -43,6 +44,7 @@
public static final Interpolator ICON_OVERSHOT = new PathInterpolator(0.4f, 0f, 0.2f, 1.4f);
public static final Interpolator PANEL_CLOSE_ACCELERATED
= new PathInterpolator(0.3f, 0, 0.5f, 1);
+ public static final Interpolator BOUNCE = new BounceInterpolator();
/**
* Interpolator to be used when animating a move based on a click. Pair with enough duration.
diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
index 8d8b726..b7e1d67 100644
--- a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
@@ -199,7 +199,7 @@
launcherServiceIntent.setComponent(mLauncherComponentName);
boolean bound = mContext.bindServiceAsUser(launcherServiceIntent,
mOverviewServiceConnection, Context.BIND_AUTO_CREATE,
- UserHandle.getUserHandleForUid(mDeviceProvisionedController.getCurrentUser()));
+ UserHandle.of(mDeviceProvisionedController.getCurrentUser()));
if (!bound) {
// Retry after exponential backoff timeout
final long timeoutMs = (long) Math.scalb(BACKOFF_MILLIS, mConnectionBackoffAttempts);
diff --git a/packages/SystemUI/src/com/android/systemui/SysUIToast.java b/packages/SystemUI/src/com/android/systemui/SysUIToast.java
index 89bc82f..43b918d 100644
--- a/packages/SystemUI/src/com/android/systemui/SysUIToast.java
+++ b/packages/SystemUI/src/com/android/systemui/SysUIToast.java
@@ -15,13 +15,19 @@
*/
package com.android.systemui;
+import android.annotation.StringRes;
import android.content.Context;
import android.view.WindowManager;
import android.widget.Toast;
+import static android.widget.Toast.Duration;
public class SysUIToast {
- public static Toast makeText(Context context, CharSequence text, int duration) {
+ public static Toast makeText(Context context, @StringRes int resId, @Duration int duration) {
+ return makeText(context, context.getString(resId), duration);
+ }
+
+ public static Toast makeText(Context context, CharSequence text, @Duration int duration) {
Toast toast = Toast.makeText(context, text, duration);
toast.getWindowParams().privateFlags |=
WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index e661fa7..ea2a432 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -142,8 +142,12 @@
final int lowPowerModeTriggerLevel = Settings.Global.getInt(resolver,
Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, defWarnLevel);
- // NOTE: Keep the logic in sync with BatteryService.
- // TODO: Propagate this value from BatteryService to system UI, really.
+ // Note LOW_POWER_MODE_TRIGGER_LEVEL can take any value between 0 and 100, but
+ // for the UI purposes, let's cap it at 15% -- i.e. even if the trigger level is higher
+ // like 50%, let's not show the "low battery" notification until it hits
+ // config_lowBatteryWarningLevel, which is 15% by default.
+ // LOW_POWER_MODE_TRIGGER_LEVEL is still used in other places as-is. For example, if it's
+ // 50, then battery saver kicks in when the battery level hits 50%.
int warnLevel = Math.min(defWarnLevel, lowPowerModeTriggerLevel);
if (warnLevel == 0) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index 9c87e1b..7f34acb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -21,7 +21,6 @@
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
-import android.content.res.Resources;
import android.graphics.PorterDuff.Mode;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.RippleDrawable;
@@ -47,7 +46,6 @@
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.qs.TouchAnimator.Builder;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.phone.ExpandableIndicator;
import com.android.systemui.statusbar.phone.MultiUserSwitch;
import com.android.systemui.statusbar.phone.SettingsButton;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -61,6 +59,7 @@
public class QSFooterImpl extends FrameLayout implements QSFooter,
OnClickListener, OnUserInfoChangedListener, EmergencyListener,
SignalCallback, CommandQueue.Callbacks {
+
private ActivityStarter mActivityStarter;
private UserInfoController mUserInfoController;
private SettingsButton mSettingsButton;
@@ -79,16 +78,22 @@
protected MultiUserSwitch mMultiUserSwitch;
private ImageView mMultiUserAvatar;
- protected TouchAnimator mSettingsAlpha;
+ protected TouchAnimator mFooterAnimator;
private float mExpansionAmount;
protected View mEdit;
- private TouchAnimator mAnimator;
+ private TouchAnimator mSettingsCogAnimator;
private View mActionsContainer;
+ private View mDragHandle;
+ private final int mDragHandleExpandOffset;
public QSFooterImpl(Context context, AttributeSet attrs) {
super(context, attrs);
+
+ mDragHandleExpandOffset = getResources().
+ getDimensionPixelSize(R.dimen.qs_footer_drag_handle_offset);
+
}
@Override
@@ -109,6 +114,7 @@
mMultiUserSwitch = findViewById(R.id.multi_user_switch);
mMultiUserAvatar = mMultiUserSwitch.findViewById(R.id.multi_user_avatar);
+ mDragHandle = findViewById(R.id.qs_drag_handle_view);
mActionsContainer = findViewById(R.id.qs_footer_actions_container);
// RenderThread is doing more harm than good when touching the header (to expand quick
@@ -130,7 +136,7 @@
int remaining = (width - numTiles * size) / (numTiles - 1);
int defSpace = mContext.getResources().getDimensionPixelOffset(R.dimen.default_gear_space);
- mAnimator = new Builder()
+ mSettingsCogAnimator = new Builder()
.addFloat(mSettingsContainer, "translationX",
isLayoutRtl() ? (remaining - defSpace) : -(remaining - defSpace), 0)
.addFloat(mSettingsButton, "rotation", -120, 0)
@@ -152,19 +158,20 @@
}
private void updateResources() {
- updateSettingsAnimator();
+ updateFooterAnimator();
}
- private void updateSettingsAnimator() {
- mSettingsAlpha = createSettingsAlphaAnimator();
+ private void updateFooterAnimator() {
+ mFooterAnimator = createFooterAnimator();
}
@Nullable
- private TouchAnimator createSettingsAlphaAnimator() {
+ private TouchAnimator createFooterAnimator() {
return new TouchAnimator.Builder()
.addFloat(mDivider, "alpha", 0, 1)
.addFloat(mCarrierText, "alpha", 0, 1)
.addFloat(mActionsContainer, "alpha", 0, 1)
+ .addFloat(mDragHandle, "translationY", 0, -mDragHandleExpandOffset)
.build();
}
@@ -183,10 +190,10 @@
@Override
public void setExpansion(float headerExpansionFraction) {
mExpansionAmount = headerExpansionFraction;
- if (mAnimator != null) mAnimator.setPosition(headerExpansionFraction);
+ if (mSettingsCogAnimator != null) mSettingsCogAnimator.setPosition(headerExpansionFraction);
- if (mSettingsAlpha != null) {
- mSettingsAlpha.setPosition(headerExpansionFraction);
+ if (mFooterAnimator != null) {
+ mFooterAnimator.setPosition(headerExpansionFraction);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index aaf6ef5..6205e9a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -19,8 +19,6 @@
import static android.provider.Settings.Global.ZEN_MODE_ALARMS;
import static android.provider.Settings.Global.ZEN_MODE_OFF;
-import android.app.AlarmManager;
-import android.app.AlarmManager.AlarmClockInfo;
import android.app.Dialog;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -30,11 +28,9 @@
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
-import android.net.Uri;
import android.os.UserManager;
import android.provider.Settings;
import android.provider.Settings.Global;
-import android.service.notification.ScheduleCalendar;
import android.service.notification.ZenModeConfig;
import android.service.notification.ZenModeConfig.ZenRule;
import android.service.quicksettings.Tile;
@@ -56,7 +52,6 @@
import com.android.systemui.SysUIToast;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.DetailAdapter;
-import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.qs.QSTile.BooleanState;
import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.tileimpl.QSTileImpl;
@@ -197,7 +192,8 @@
state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
state.slash.isSlashed = !state.value;
state.label = getTileLabel();
- state.secondaryLabel = getSecondaryLabel(zen != Global.ZEN_MODE_OFF);
+ state.secondaryLabel = ZenModeConfig.getDescription(mContext,zen != Global.ZEN_MODE_OFF,
+ mController.getConfig());
state.icon = ResourceIcon.get(R.drawable.ic_qs_dnd_on);
checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_ADJUST_VOLUME);
switch (zen) {
@@ -226,102 +222,6 @@
state.expandedAccessibilityClassName = Switch.class.getName();
}
- /**
- * Returns the secondary label to use for the given instance of do not disturb.
- * - If turned on manually and end time is known, returns end time.
- * - If turned on by an automatic rule, returns the automatic rule name.
- * - If on due to an app, returns the app name.
- * - If there's a combination of rules/apps that trigger, then shows the one that will
- * last the longest if applicable.
- * @return null if do not disturb is off.
- */
- private String getSecondaryLabel(boolean zenOn) {
- if (!zenOn) {
- return null;
- }
-
- ZenModeConfig config = mController.getConfig();
- String secondaryText = "";
- long latestEndTime = -1;
-
- // DND turned on by manual rule
- if (config.manualRule != null) {
- final Uri id = config.manualRule.conditionId;
- if (config.manualRule.enabler != null) {
- // app triggered manual rule
- String appName = ZenModeConfig.getOwnerCaption(mContext, config.manualRule.enabler);
- if (!appName.isEmpty()) {
- secondaryText = appName;
- }
- } else {
- if (id == null) {
- // Do not disturb manually triggered to remain on forever until turned off
- // No subtext
- return null;
- } else {
- latestEndTime = ZenModeConfig.tryParseCountdownConditionId(id);
- if (latestEndTime > 0) {
- final CharSequence formattedTime = ZenModeConfig.getFormattedTime(mContext,
- latestEndTime, ZenModeConfig.isToday(latestEndTime),
- mContext.getUserId());
- secondaryText = mContext.getString(R.string.qs_dnd_until, formattedTime);
- }
- }
- }
- }
-
- // DND turned on by an automatic rule
- for (ZenModeConfig.ZenRule automaticRule : config.automaticRules.values()) {
- if (automaticRule.isAutomaticActive()) {
- if (ZenModeConfig.isValidEventConditionId(automaticRule.conditionId) ||
- ZenModeConfig.isValidScheduleConditionId(automaticRule.conditionId)) {
- // set text if automatic rule end time is the latest active rule end time
- long endTime = parseAutomaticRuleEndTime(automaticRule.conditionId);
- if (endTime > latestEndTime) {
- latestEndTime = endTime;
- secondaryText = automaticRule.name;
- }
- } else {
- // set text if 3rd party rule
- return automaticRule.name;
- }
- }
- }
-
- return !secondaryText.equals("") ? secondaryText : null;
- }
-
- private long parseAutomaticRuleEndTime(Uri id) {
- if (ZenModeConfig.isValidEventConditionId(id)) {
- // cannot look up end times for events
- return Long.MAX_VALUE;
- }
-
- if (ZenModeConfig.isValidScheduleConditionId(id)) {
- ScheduleCalendar schedule = ZenModeConfig.toScheduleCalendar(id);
- long endTimeMs = schedule.getNextChangeTime(System.currentTimeMillis());
-
- // check if automatic rule will end on next alarm
- if (schedule.exitAtAlarm()) {
- long nextAlarm = getNextAlarm(mContext);
- schedule.maybeSetNextAlarm(System.currentTimeMillis(), nextAlarm);
- if (schedule.shouldExitForAlarm(endTimeMs)) {
- return nextAlarm;
- }
- }
-
- return endTimeMs;
- }
-
- return -1;
- }
-
- private long getNextAlarm(Context context) {
- final AlarmManager alarms = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
- final AlarmClockInfo info = alarms.getNextAlarmClock(mContext.getUserId());
- return info != null ? info.getTriggerTime() : 0;
- }
-
@Override
public int getMetricsCategory() {
return MetricsEvent.QS_DND;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index 8bdbf28..d7f2a26 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -102,7 +102,7 @@
state.value = locationEnabled;
checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_SHARE_LOCATION);
if (state.disabledByPolicy == false) {
- checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_CONFIG_LOCATION_MODE);
+ checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_CONFIG_LOCATION);
}
state.icon = mIcon;
state.slash.isSlashed = !state.value;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 1da4deb..409c753 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -415,7 +415,7 @@
final int activityType = runningTask != null
? runningTask.configuration.windowConfiguration.getActivityType()
: ACTIVITY_TYPE_UNDEFINED;
- boolean screenPinningActive = sSystemServicesProxy.isScreenPinningActive();
+ boolean screenPinningActive = ActivityManagerWrapper.getInstance().isLockToAppActive();
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 ee1b091..3f6f30b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -386,8 +386,7 @@
public void toggleRecents(int growTarget) {
// Skip preloading if the task is locked
- SystemServicesProxy ssp = Recents.getSystemServices();
- if (ssp.isScreenPinningActive()) {
+ if (ActivityManagerWrapper.getInstance().isLockToAppActive()) {
return;
}
@@ -409,8 +408,8 @@
MutableBoolean isHomeStackVisible = new MutableBoolean(true);
long elapsedTime = SystemClock.elapsedRealtime() - mLastToggleTime;
+ SystemServicesProxy ssp = Recents.getSystemServices();
if (ssp.isRecentsActivityVisible(isHomeStackVisible)) {
- RecentsDebugFlags debugFlags = Recents.getDebugFlags();
RecentsConfiguration config = Recents.getConfiguration();
RecentsActivityLaunchState launchState = config.getLaunchState();
if (!launchState.launchedWithAltTab) {
@@ -466,8 +465,7 @@
public void preloadRecents() {
// Skip preloading if the task is locked
- SystemServicesProxy ssp = Recents.getSystemServices();
- if (ssp.isScreenPinningActive()) {
+ if (ActivityManagerWrapper.getInstance().isLockToAppActive()) {
return;
}
@@ -481,6 +479,7 @@
// RecentsActivity) only if there is a task to animate to. Post this to ensure that we
// don't block the touch feedback on the nav bar button which triggers this.
mHandler.post(() -> {
+ SystemServicesProxy ssp = Recents.getSystemServices();
if (!ssp.isRecentsActivityVisible(null)) {
ActivityManager.RunningTaskInfo runningTask =
ActivityManagerWrapper.getInstance().getRunningTask();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
index 316ad16..57f7818 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
@@ -23,15 +23,12 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.res.Configuration;
import android.graphics.PixelFormat;
-import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.os.Binder;
import android.os.RemoteException;
import android.util.DisplayMetrics;
import android.view.Gravity;
-import android.view.Surface;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
@@ -43,6 +40,9 @@
import android.widget.TextView;
import com.android.systemui.R;
+import com.android.systemui.SysUiServiceProvider;
+import com.android.systemui.statusbar.phone.NavigationBarView;
+import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.util.leak.RotationUtils;
import java.util.ArrayList;
@@ -233,11 +233,30 @@
.setVisibility(View.INVISIBLE);
}
+ StatusBar statusBar = SysUiServiceProvider.getComponent(mContext, StatusBar.class);
+ NavigationBarView navigationBarView = statusBar.getNavigationBarView();
+ final boolean recentsVisible = navigationBarView != null
+ && navigationBarView.isRecentsButtonVisible();
boolean touchExplorationEnabled = mAccessibilityService.isTouchExplorationEnabled();
+ int descriptionStringResId;
+ if (recentsVisible) {
+ mLayout.findViewById(R.id.screen_pinning_recents_group).setVisibility(VISIBLE);
+ mLayout.findViewById(R.id.screen_pinning_home_bg_light).setVisibility(INVISIBLE);
+ mLayout.findViewById(R.id.screen_pinning_home_bg).setVisibility(INVISIBLE);
+ descriptionStringResId = touchExplorationEnabled
+ ? R.string.screen_pinning_description_accessible
+ : R.string.screen_pinning_description;
+ } else {
+ mLayout.findViewById(R.id.screen_pinning_recents_group).setVisibility(INVISIBLE);
+ mLayout.findViewById(R.id.screen_pinning_home_bg_light).setVisibility(VISIBLE);
+ mLayout.findViewById(R.id.screen_pinning_home_bg).setVisibility(VISIBLE);
+ descriptionStringResId = touchExplorationEnabled
+ ? R.string.screen_pinning_description_recents_invisible_accessible
+ : R.string.screen_pinning_description_recents_invisible;
+ }
+
((TextView) mLayout.findViewById(R.id.screen_pinning_description))
- .setText(touchExplorationEnabled
- ? R.string.screen_pinning_description_accessible
- : R.string.screen_pinning_description);
+ .setText(descriptionStringResId);
final int backBgVisibility = touchExplorationEnabled ? View.INVISIBLE : View.VISIBLE;
mLayout.findViewById(R.id.screen_pinning_back_bg).setVisibility(backBgVisibility);
mLayout.findViewById(R.id.screen_pinning_back_bg_light).setVisibility(backBgVisibility);
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 613d9fb..93fd34a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -379,29 +379,6 @@
}
/**
- * Returns a global setting.
- */
- public int getGlobalSetting(Context context, String setting) {
- ContentResolver cr = context.getContentResolver();
- return Settings.Global.getInt(cr, setting, 0);
- }
-
- /**
- * Returns a system setting.
- */
- public int getSystemSetting(Context context, String setting) {
- ContentResolver cr = context.getContentResolver();
- return Settings.System.getInt(cr, setting, 0);
- }
-
- /**
- * Returns a system property.
- */
- public String getSystemProperty(String key) {
- return SystemProperties.get(key);
- }
-
- /**
* Returns the smallest width/height.
*/
public int getDeviceSmallestWidth() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 5be2900..3cc3273 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -95,6 +95,7 @@
import com.android.systemui.recents.views.grid.TaskGridLayoutAlgorithm;
import com.android.systemui.recents.views.grid.TaskViewFocusFrame;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -2187,8 +2188,7 @@
private void readSystemFlags() {
SystemServicesProxy ssp = Recents.getSystemServices();
mTouchExplorationEnabled = ssp.isTouchExplorationEnabled();
- mScreenPinningEnabled = ssp.getSystemSetting(getContext(),
- Settings.System.LOCK_TO_APP_ENABLED) != 0;
+ mScreenPinningEnabled = ActivityManagerWrapper.getInstance().isLockToAppEnabled();
}
private void updateStackActionButtonVisibility() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 79e9f7b..11bdf6b3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -24,6 +24,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.RemoteException;
import android.support.annotation.VisibleForTesting;
import android.util.Pair;
@@ -90,6 +91,8 @@
private static final int MSG_FINGERPRINT_ERROR = 42 << MSG_SHIFT;
private static final int MSG_FINGERPRINT_HIDE = 43 << MSG_SHIFT;
private static final int MSG_SHOW_CHARGING_ANIMATION = 44 << MSG_SHIFT;
+ private static final int MSG_SHOW_PINNING_TOAST_ENTER_EXIT = 45 << MSG_SHIFT;
+ private static final int MSG_SHOW_PINNING_TOAST_ESCAPE = 46 << MSG_SHIFT;
public static final int FLAG_EXCLUDE_NONE = 0;
public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
@@ -148,6 +151,8 @@
default void clickTile(ComponentName tile) { }
default void handleSystemKey(int arg1) { }
+ default void showPinningEnterExitToast(boolean entering) { }
+ default void showPinningEscapeToast() { }
default void handleShowGlobalActionsMenu() { }
default void handleShowShutdownUi(boolean isReboot, String reason) { }
@@ -453,6 +458,21 @@
}
@Override
+ public void showPinningEnterExitToast(boolean entering) {
+ synchronized (mLock) {
+ mHandler.obtainMessage(MSG_SHOW_PINNING_TOAST_ENTER_EXIT, entering).sendToTarget();
+ }
+ }
+
+ @Override
+ public void showPinningEscapeToast() {
+ synchronized (mLock) {
+ mHandler.obtainMessage(MSG_SHOW_PINNING_TOAST_ESCAPE).sendToTarget();
+ }
+ }
+
+
+ @Override
public void showGlobalActionsMenu() {
synchronized (mLock) {
mHandler.removeMessages(MSG_SHOW_GLOBAL_ACTIONS);
@@ -767,6 +787,16 @@
mCallbacks.get(i).showChargingAnimation(msg.arg1);
}
break;
+ case MSG_SHOW_PINNING_TOAST_ENTER_EXIT:
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ mCallbacks.get(i).showPinningEnterExitToast((Boolean) msg.obj);
+ }
+ break;
+ case MSG_SHOW_PINNING_TOAST_ESCAPE:
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ mCallbacks.get(i).showPinningEscapeToast();
+ }
+ break;
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 0a12be4..b7a1500 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -44,6 +46,7 @@
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
import com.android.systemui.statusbar.phone.LockIcon;
@@ -192,7 +195,7 @@
if (!mHandler.hasMessages(MSG_HIDE_TRANSIENT)) {
hideTransientIndication();
}
- updateIndication();
+ updateIndication(false);
} else if (!visible) {
// If we unlock and return to keyguard quickly, previous error should not be shown
hideTransientIndication();
@@ -204,7 +207,7 @@
*/
public void setRestingIndication(String restingIndication) {
mRestingIndication = restingIndication;
- updateIndication();
+ updateIndication(false);
}
/**
@@ -265,7 +268,8 @@
mWakeLock.setAcquired(true);
hideTransientIndicationDelayed(BaseKeyguardCallback.HIDE_DELAY_MS);
}
- updateIndication();
+
+ updateIndication(false);
}
/**
@@ -275,11 +279,11 @@
if (mTransientIndication != null) {
mTransientIndication = null;
mHandler.removeMessages(MSG_HIDE_TRANSIENT);
- updateIndication();
+ updateIndication(false);
}
}
- protected final void updateIndication() {
+ protected final void updateIndication(boolean animate) {
if (TextUtils.isEmpty(mTransientIndication)) {
mWakeLock.setAcquired(false);
}
@@ -295,7 +299,35 @@
mTextView.switchIndication(mTransientIndication);
} else if (mPowerPluggedIn) {
String indication = computePowerIndication();
- mTextView.switchIndication(indication);
+ if (animate) {
+ int yTranslation = mContext.getResources().getInteger(
+ R.integer.wired_charging_aod_text_animation_distance);
+ int animateUpDuration = mContext.getResources().getInteger(
+ R.integer.wired_charging_aod_text_animation_duration_up);
+ int animateDownDuration = mContext.getResources().getInteger(
+ R.integer.wired_charging_aod_text_animation_duration_down);
+ mTextView.animate()
+ .translationYBy(yTranslation)
+ .setInterpolator(Interpolators.LINEAR)
+ .setDuration(animateUpDuration)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mTextView.switchIndication(indication);
+ }
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mTextView.animate()
+ .setDuration(animateDownDuration)
+ .setInterpolator(Interpolators.BOUNCE)
+ .translationYBy(-1 * yTranslation)
+ .setListener(null);
+ }
+ });
+ } else {
+ mTextView.switchIndication(indication);
+ }
+
} else {
String percentage = NumberFormat.getPercentInstance()
.format(mBatteryLevel / 100f);
@@ -390,7 +422,7 @@
public void onReceive(Context context, Intent intent) {
mHandler.post(() -> {
if (mVisible) {
- updateIndication();
+ updateIndication(false);
}
});
}
@@ -412,7 +444,7 @@
return;
}
mDozing = dozing;
- updateIndication();
+ updateIndication(false);
updateDisclosure();
}
@@ -445,7 +477,7 @@
mChargingWattage = status.maxChargingWattage;
mChargingSpeed = status.getChargingSpeed(mSlowThreshold, mFastThreshold);
mBatteryLevel = status.level;
- updateIndication();
+ updateIndication(!wasPluggedIn && mPowerPluggedIn);
if (mDozing) {
if (!wasPluggedIn && mPowerPluggedIn) {
showTransientIndication(computePowerIndication());
@@ -551,7 +583,7 @@
@Override
public void onUserUnlocked() {
if (mVisible) {
- updateIndication();
+ updateIndication(false);
}
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 65c45a3..1239a9e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -22,11 +22,13 @@
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
import static com.android.systemui.statusbar.phone.StatusBar.DEBUG_WINDOW_STATE;
import static com.android.systemui.statusbar.phone.StatusBar.dumpBarTransitions;
+import static com.android.systemui.OverviewProxyService.OverviewProxyListener;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
+import android.annotation.IdRes;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
@@ -69,6 +71,7 @@
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener;
+import android.widget.Button;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -153,6 +156,18 @@
private Animator mRotateShowAnimator;
private Animator mRotateHideAnimator;
+ private final OverviewProxyListener mOverviewProxyListener = new OverviewProxyListener() {
+ @Override
+ public void onConnectionChanged(boolean isConnected) {
+ mNavigationBarView.onOverviewProxyConnectionChanged(isConnected);
+ updateScreenPinningGestures();
+ }
+
+ @Override
+ public void onRecentsAnimationStarted() {
+ mNavigationBarView.setRecentsAnimationStarted(true);
+ }
+ };
// ----- Fragment Lifecycle Callbacks -----
@@ -239,12 +254,14 @@
filter.addAction(Intent.ACTION_SCREEN_ON);
getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
notifyNavigationBarScreenOn();
+ mOverviewProxyService.addCallback(mOverviewProxyListener);
}
@Override
public void onDestroyView() {
super.onDestroyView();
mNavigationBarView.getLightTransitionsController().destroy(getContext());
+ mOverviewProxyService.removeCallback(mOverviewProxyListener);
getContext().unregisterReceiver(mBroadcastReceiver);
}
@@ -514,6 +531,7 @@
if (masked != mDisabledFlags1) {
mDisabledFlags1 = masked;
if (mNavigationBarView != null) mNavigationBarView.setDisabledFlags(state1);
+ updateScreenPinningGestures();
}
}
@@ -528,7 +546,7 @@
private boolean shouldDisableNavbarGestures() {
return !mStatusBar.isDeviceProvisioned()
|| (mDisabledFlags1 & StatusBarManager.DISABLE_SEARCH) != 0
- || mOverviewProxyService.getProxy() != null;
+ || mNavigationBarView.getRecentsButton().getVisibility() != View.VISIBLE;
}
private void repositionNavigationBar() {
@@ -540,6 +558,24 @@
((View) mNavigationBarView.getParent()).getLayoutParams());
}
+ private void updateScreenPinningGestures() {
+ if (mNavigationBarView == null) {
+ return;
+ }
+
+ // Change the cancel pin gesture to home and back if recents button is invisible
+ boolean recentsVisible = mNavigationBarView.isRecentsButtonVisible();
+ ButtonDispatcher homeButton = mNavigationBarView.getHomeButton();
+ ButtonDispatcher backButton = mNavigationBarView.getBackButton();
+ if (recentsVisible) {
+ homeButton.setOnLongClickListener(this::onHomeLongClick);
+ backButton.setOnLongClickListener(this::onLongPressBackRecents);
+ } else {
+ homeButton.setOnLongClickListener(this::onLongPressBackHome);
+ backButton.setOnLongClickListener(this::onLongPressBackHome);
+ }
+ }
+
private void notifyNavigationBarScreenOn() {
mNavigationBarView.notifyScreenOn();
}
@@ -555,11 +591,9 @@
ButtonDispatcher backButton = mNavigationBarView.getBackButton();
backButton.setLongClickable(true);
- backButton.setOnLongClickListener(this::onLongPressBackRecents);
ButtonDispatcher homeButton = mNavigationBarView.getHomeButton();
homeButton.setOnTouchListener(this::onHomeTouch);
- homeButton.setOnLongClickListener(this::onHomeLongClick);
ButtonDispatcher accessibilityButton = mNavigationBarView.getAccessibilityButton();
accessibilityButton.setOnClickListener(this::onAccessibilityClick);
@@ -569,6 +603,7 @@
ButtonDispatcher rotateSuggestionButton = mNavigationBarView.getRotateSuggestionButton();
rotateSuggestionButton.setOnClickListener(this::onRotateSuggestionClick);
rotateSuggestionButton.setOnHoverListener(this::onRotateSuggestionHover);
+ updateScreenPinningGestures();
}
private boolean onHomeTouch(View v, MotionEvent event) {
@@ -649,20 +684,29 @@
mCommandQueue.toggleRecentApps();
}
+ private boolean onLongPressBackHome(View v) {
+ return onLongPressNavigationButtons(v, R.id.back, R.id.home);
+ }
+
+ private boolean onLongPressBackRecents(View v) {
+ return onLongPressNavigationButtons(v, R.id.back, R.id.recent_apps);
+ }
+
/**
- * This handles long-press of both back and recents. They are
- * handled together to capture them both being long-pressed
+ * This handles long-press of both back and recents/home. Back is the common button with
+ * combination of recents if it is visible or home if recents is invisible.
+ * They are handled together to capture them both being long-pressed
* at the same time to exit screen pinning (lock task).
*
- * When accessibility mode is on, only a long-press from recents
+ * When accessibility mode is on, only a long-press from recents/home
* is required to exit.
*
* In all other circumstances we try to pass through long-press events
* for Back, so that apps can still use it. Which can be from two things.
* 1) Not currently in screen pinning (lock task).
- * 2) Back is long-pressed without recents.
+ * 2) Back is long-pressed without recents/home.
*/
- private boolean onLongPressBackRecents(View v) {
+ private boolean onLongPressNavigationButtons(View v, @IdRes int btnId1, @IdRes int btnId2) {
try {
boolean sendBackLongPress = false;
IActivityManager activityManager = ActivityManagerNative.getDefault();
@@ -670,6 +714,7 @@
boolean inLockTaskMode = activityManager.isInLockTaskMode();
if (inLockTaskMode && !touchExplorationEnabled) {
long time = System.currentTimeMillis();
+
// If we recently long-pressed the other button then they were
// long-pressed 'together'
if ((time - mLastLockToAppLongPress) < LOCK_TO_APP_GESTURE_TOLERENCE) {
@@ -677,26 +722,32 @@
// When exiting refresh disabled flags.
mNavigationBarView.setDisabledFlags(mDisabledFlags1, true);
return true;
- } else if ((v.getId() == R.id.back)
- && !mNavigationBarView.getRecentsButton().getCurrentView().isPressed()) {
- // If we aren't pressing recents right now then they presses
- // won't be together, so send the standard long-press action.
- sendBackLongPress = true;
+ } else if (v.getId() == btnId1) {
+ ButtonDispatcher button = btnId2 == R.id.recent_apps
+ ? mNavigationBarView.getRecentsButton()
+ : mNavigationBarView.getHomeButton();
+ if (!button.getCurrentView().isPressed()) {
+ // If we aren't pressing recents/home right now then they presses
+ // won't be together, so send the standard long-press action.
+ sendBackLongPress = true;
+ }
}
mLastLockToAppLongPress = time;
} else {
// If this is back still need to handle sending the long-press event.
- if (v.getId() == R.id.back) {
+ if (v.getId() == btnId1) {
sendBackLongPress = true;
} else if (touchExplorationEnabled && inLockTaskMode) {
- // When in accessibility mode a long press that is recents (not back)
+ // When in accessibility mode a long press that is recents/home (not back)
// should stop lock task.
activityManager.stopSystemLockTaskMode();
// When exiting refresh disabled flags.
mNavigationBarView.setDisabledFlags(mDisabledFlags1, true);
return true;
- } else if (v.getId() == R.id.recent_apps) {
- return onLongPressRecents();
+ } else if (v.getId() == btnId2) {
+ return btnId2 == R.id.recent_apps
+ ? onLongPressRecents()
+ : onHomeLongClick(mNavigationBarView.getHomeButton().getCurrentView());
}
}
if (sendBackLongPress) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index e04ba83..c37dd55 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -207,23 +207,6 @@
}
}
- private final OverviewProxyListener mOverviewProxyListener = new OverviewProxyListener() {
- @Override
- public void onConnectionChanged(boolean isConnected) {
- updateSlippery();
- setDisabledFlags(mDisabledFlags, true);
- setUpSwipeUpOnboarding(isConnected);
- }
-
- @Override
- public void onRecentsAnimationStarted() {
- mRecentsAnimationStarted = true;
- if (mSwipeUpOnboarding != null) {
- mSwipeUpOnboarding.onRecentsAnimationStarted();
- }
- }
- };
-
public NavigationBarView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -280,6 +263,19 @@
notifyVerticalChangedListener(mVertical);
}
+ public void setRecentsAnimationStarted(boolean started) {
+ mRecentsAnimationStarted = started;
+ if (mSwipeUpOnboarding != null) {
+ mSwipeUpOnboarding.onRecentsAnimationStarted();
+ }
+ }
+
+ public void onConnectionChanged(boolean isConnected) {
+ updateSlippery();
+ setDisabledFlags(mDisabledFlags, true);
+ setUpSwipeUpOnboarding(isConnected);
+ }
+
@Override
public boolean onTouchEvent(MotionEvent event) {
if (mGestureHelper.onTouchEvent(event)) {
@@ -353,6 +349,10 @@
return mButtonDispatchers;
}
+ public boolean isRecentsButtonVisible() {
+ return getRecentsButton().getVisibility() == View.VISIBLE;
+ }
+
private void updateCarModeIcons(Context ctx) {
mBackCarModeIcon = getDrawable(ctx,
R.drawable.ic_sysbar_back_carmode, R.drawable.ic_sysbar_back_carmode);
@@ -613,6 +613,9 @@
final ViewGroup navbarView = ((ViewGroup) getParent());
final WindowManager.LayoutParams lp = (WindowManager.LayoutParams) navbarView
.getLayoutParams();
+ if (lp == null) {
+ return;
+ }
if (slippery && (lp.flags & WindowManager.LayoutParams.FLAG_SLIPPERY) == 0) {
lp.flags |= WindowManager.LayoutParams.FLAG_SLIPPERY;
changed = true;
@@ -676,6 +679,12 @@
}
}
+ public void onOverviewProxyConnectionChanged(boolean isConnected) {
+ setSlippery(!isConnected);
+ setDisabledFlags(mDisabledFlags, true);
+ setUpSwipeUpOnboarding(isConnected);
+ }
+
@Override
protected void onDraw(Canvas canvas) {
mGestureHelper.onDraw(canvas);
@@ -873,7 +882,6 @@
onPluginDisconnected(null); // Create default gesture helper
Dependency.get(PluginManager.class).addPluginListener(this,
NavGesture.class, false /* Only one */);
- mOverviewProxyService.addCallback(mOverviewProxyListener);
setUpSwipeUpOnboarding(mOverviewProxyService.getProxy() != null);
}
@@ -884,7 +892,6 @@
if (mGestureHelper != null) {
mGestureHelper.destroy();
}
- mOverviewProxyService.removeCallback(mOverviewProxyListener);
setUpSwipeUpOnboarding(false);
}
diff --git a/services/core/java/com/android/server/am/LockTaskNotify.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScreenPinningNotify.java
similarity index 70%
rename from services/core/java/com/android/server/am/LockTaskNotify.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/phone/ScreenPinningNotify.java
index 1dcb0ad..0d07ad9 100644
--- a/services/core/java/com/android/server/am/LockTaskNotify.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScreenPinningNotify.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.am;
+package com.android.systemui.statusbar.phone;
import android.content.Context;
import android.os.SystemClock;
@@ -22,36 +22,37 @@
import android.view.WindowManager;
import android.widget.Toast;
-import com.android.internal.R;
+import com.android.systemui.R;
+import com.android.systemui.SysUIToast;
/**
* Helper to manage showing/hiding a image to notify them that they are entering or exiting screen
* pinning mode. All exposed methods should be called from a handler thread.
*/
-public class LockTaskNotify {
- private static final String TAG = "LockTaskNotify";
+public class ScreenPinningNotify {
+ private static final String TAG = "ScreenPinningNotify";
private static final long SHOW_TOAST_MINIMUM_INTERVAL = 1000;
private final Context mContext;
private Toast mLastToast;
private long mLastShowToastTime;
- public LockTaskNotify(Context context) {
+ public ScreenPinningNotify(Context context) {
mContext = context;
}
/** Show "Screen pinned" toast. */
void showPinningStartToast() {
- makeAllUserToastAndShow(R.string.lock_to_app_start);
+ makeAllUserToastAndShow(R.string.screen_pinning_start);
}
/** Show "Screen unpinned" toast. */
void showPinningExitToast() {
- makeAllUserToastAndShow(R.string.lock_to_app_exit);
+ makeAllUserToastAndShow(R.string.screen_pinning_exit);
}
/** Show a toast that describes the gesture the user should use to escape pinned mode. */
- void showEscapeToast() {
+ void showEscapeToast(boolean isRecentsButtonVisible) {
long showToastTime = SystemClock.elapsedRealtime();
if ((showToastTime - mLastShowToastTime) < SHOW_TOAST_MINIMUM_INTERVAL) {
Slog.i(TAG, "Ignore toast since it is requested in very short interval.");
@@ -60,14 +61,14 @@
if (mLastToast != null) {
mLastToast.cancel();
}
- mLastToast = makeAllUserToastAndShow(R.string.lock_to_app_toast);
+ mLastToast = makeAllUserToastAndShow(isRecentsButtonVisible
+ ? R.string.screen_pinning_toast
+ : R.string.screen_pinning_toast_recents_invisible);
mLastShowToastTime = showToastTime;
}
private Toast makeAllUserToastAndShow(int resId) {
- Toast toast = Toast.makeText(mContext, resId, Toast.LENGTH_LONG);
- toast.getWindowParams().privateFlags |=
- WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+ Toast toast = SysUIToast.makeText(mContext, resId, Toast.LENGTH_LONG);
toast.show();
return toast;
}
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 426268b..1bf719a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -404,6 +404,13 @@
protected NotificationEntryManager mEntryManager;
protected NotificationViewHierarchyManager mViewHierarchyManager;
+ /**
+ * Helper that is responsible for showing the right toast when a disallowed activity operation
+ * occurred. In pinned mode, we show instructions on how to break out of this mode, whilst in
+ * fully locked mode we only show that unlocking is blocked.
+ */
+ private ScreenPinningNotify mScreenPinningNotify;
+
// for disabling the status bar
private int mDisabled1 = 0;
private int mDisabled2 = 0;
@@ -830,7 +837,7 @@
} catch (RemoteException ex) {
// no window manager? good luck with that
}
-
+ mScreenPinningNotify = new ScreenPinningNotify(mContext);
mStackScroller.setLongPressListener(mEntryManager.getNotificationLongClicker());
mStackScroller.setStatusBar(this);
mStackScroller.setGroupManager(mGroupManager);
@@ -2141,6 +2148,21 @@
}
+ @Override
+ public void showPinningEnterExitToast(boolean entering) {
+ if (entering) {
+ mScreenPinningNotify.showPinningStartToast();
+ } else {
+ mScreenPinningNotify.showPinningExitToast();
+ }
+ }
+
+ @Override
+ public void showPinningEscapeToast() {
+ mScreenPinningNotify.showEscapeToast(getNavigationBarView() == null
+ || getNavigationBarView().isRecentsButtonVisible());
+ }
+
boolean panelsEnabled() {
return (mDisabled1 & StatusBarManager.DISABLE_EXPAND) == 0
&& (mDisabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) == 0
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 0c6e0f6..a131a61 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -18,6 +18,7 @@
import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK;
import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_GENERIC;
+import static android.media.AudioManager.STREAM_ACCESSIBILITY;
import static com.android.systemui.volume.Events.DISMISS_REASON_OUTPUT_CHOOSER;
import static com.android.systemui.volume.Events.DISMISS_REASON_SETTINGS_CLICKED;
@@ -47,6 +48,7 @@
import android.provider.Settings;
import android.provider.Settings.Global;
import android.support.v7.media.MediaRouter;
+import android.text.InputFilter;
import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;
@@ -219,7 +221,7 @@
R.drawable.ic_volume_bt_sco, R.drawable.ic_volume_bt_sco, false, false);
addRow(AudioManager.STREAM_SYSTEM, R.drawable.ic_volume_system,
R.drawable.ic_volume_system_mute, false, false);
- addRow(AudioManager.STREAM_ACCESSIBILITY, R.drawable.ic_volume_accessibility,
+ addRow(STREAM_ACCESSIBILITY, R.drawable.ic_volume_accessibility,
R.drawable.ic_volume_accessibility, true, false);
}
} else {
@@ -334,6 +336,9 @@
row.view.setTag(row);
row.header = row.view.findViewById(R.id.volume_row_header);
row.header.setId(20 * row.stream);
+ if (stream == STREAM_ACCESSIBILITY) {
+ row.header.setFilters(new InputFilter[] {new InputFilter.LengthFilter(13)});
+ }
row.slider = row.view.findViewById(R.id.volume_row_slider);
row.slider.setOnSeekBarChangeListener(new VolumeSeekBarChangeListener(row));
row.anim = null;
@@ -643,7 +648,7 @@
if (ss.level == row.requestedLevel) {
row.requestedLevel = -1;
}
- final boolean isA11yStream = row.stream == AudioManager.STREAM_ACCESSIBILITY;
+ final boolean isA11yStream = row.stream == STREAM_ACCESSIBILITY;
final boolean isRingStream = row.stream == AudioManager.STREAM_RING;
final boolean isSystemStream = row.stream == AudioManager.STREAM_SYSTEM;
final boolean isAlarmStream = row.stream == AudioManager.STREAM_ALARM;
@@ -949,7 +954,7 @@
public void onAccessibilityModeChanged(Boolean showA11yStream) {
mShowA11yStream = showA11yStream == null ? false : showA11yStream;
VolumeRow activeRow = getActiveRow();
- if (!mShowA11yStream && AudioManager.STREAM_ACCESSIBILITY == activeRow.stream) {
+ if (!mShowA11yStream && STREAM_ACCESSIBILITY == activeRow.stream) {
dismissH(Events.DISMISS_STREAM_GONE);
} else {
updateRowsH(activeRow);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUiLayout.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUiLayout.java
index f50a287..3d44381 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUiLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUiLayout.java
@@ -14,26 +14,22 @@
package com.android.systemui.volume;
-import static com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE;
import static com.android.systemui.util.leak.RotationUtils.ROTATION_NONE;
-import static com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Configuration;
+import android.graphics.Rect;
import android.util.AttributeSet;
-import android.util.Slog;
-import android.view.Gravity;
+import android.view.DisplayCutout;
import android.view.View;
-import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
-import android.widget.LinearLayout;
-import android.widget.SeekBar;
import com.android.systemui.R;
import com.android.systemui.util.leak.RotationUtils;
@@ -46,6 +42,9 @@
private AnimatorSet mAnimation;
private boolean mHasOutsideTouch;
private int mRotation = ROTATION_NONE;
+ @Nullable
+ private DisplayCutout mDisplayCutout;
+
public VolumeUiLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@@ -60,6 +59,7 @@
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
getViewTreeObserver().removeOnComputeInternalInsetsListener(mInsetsListener);
+ mDisplayCutout = null;
}
@Override
@@ -86,200 +86,64 @@
updateRotation();
}
+ private void setDisplayCutout() {
+ if (mDisplayCutout == null && getRootWindowInsets() != null) {
+ DisplayCutout cutout = getRootWindowInsets().getDisplayCutout();
+ if (cutout != null) {
+ mDisplayCutout = cutout;
+ }
+ }
+ }
+
private void updateRotation() {
+ setDisplayCutout();
int rotation = RotationUtils.getRotation(getContext());
if (rotation != mRotation) {
- rotate(mRotation, rotation);
+ updateSafeInsets(rotation);
mRotation = rotation;
}
}
- private void rotate(View view, int from, int to, boolean swapDimens) {
- if (from != ROTATION_NONE && to != ROTATION_NONE) {
- // Rather than handling this confusing case, just do 2 rotations.
- rotate(view, from, ROTATION_NONE, swapDimens);
- rotate(view, ROTATION_NONE, to, swapDimens);
- return;
- }
- if (from == ROTATION_LANDSCAPE || to == ROTATION_SEASCAPE) {
- rotateRight(view);
- } else {
- rotateLeft(view);
- }
- if (to != ROTATION_NONE) {
- if (swapDimens && view instanceof LinearLayout) {
- LinearLayout linearLayout = (LinearLayout) view;
- linearLayout.setOrientation(LinearLayout.HORIZONTAL);
- swapDimens(view);
- }
- } else {
- if (swapDimens && view instanceof LinearLayout) {
- LinearLayout linearLayout = (LinearLayout) view;
- linearLayout.setOrientation(LinearLayout.VERTICAL);
- swapDimens(view);
- }
- }
- }
+ private void updateSafeInsets(int rotation) {
+ // Depending on our rotation, we may have to work around letterboxing from the right
+ // side from the navigation bar or a cutout.
- private void rotate(int from, int to) {
- View footer = mChild.findViewById(R.id.footer);
- rotate(footer, from, to, false);
- rotate(this, from, to, true);
- rotate(mChild, from, to, true);
- ViewGroup rows = mChild.findViewById(R.id.volume_dialog_rows);
- rotate(rows, from, to, true);
- swapOrientation((LinearLayout) rows);
- int rowCount = rows.getChildCount();
- for (int i = 0; i < rowCount; i++) {
- View row = rows.getChildAt(i);
- if (to == ROTATION_SEASCAPE) {
- rotateSeekBars(row, to, 180);
- } else if (to == ROTATION_LANDSCAPE) {
- rotateSeekBars(row, to, 0);
- } else {
- rotateSeekBars(row, to, 270);
- }
- rotate(row, from, to, true);
- }
- }
+ MarginLayoutParams lp = (MarginLayoutParams) mChild.getLayoutParams();
- private void swapOrientation(LinearLayout layout) {
- if(layout.getOrientation() == LinearLayout.HORIZONTAL) {
- layout.setOrientation(LinearLayout.VERTICAL);
- } else {
- layout.setOrientation(LinearLayout.HORIZONTAL);
- }
- }
-
- private void swapDimens(View v) {
- if (v == null) {
- return;
- }
- ViewGroup.LayoutParams params = v.getLayoutParams();
- int h = params.width;
- params.width = params.height;
- params.height = h;
- v.setLayoutParams(params);
- }
-
- private void rotateSeekBars(View row, int to, int rotation) {
- SeekBar seekbar = row.findViewById(R.id.volume_row_slider);
- if (seekbar != null) {
- seekbar.setRotation((float) rotation);
- }
-
- View parent = row.findViewById(R.id.volume_row_slider_frame);
- swapDimens(parent);
- ViewGroup.LayoutParams params = seekbar.getLayoutParams();
- ViewGroup.LayoutParams parentParams = parent.getLayoutParams();
- if (to != ROTATION_NONE) {
- params.height = parentParams.height;
- params.width = parentParams.width;
- } else {
- params.height = parentParams.width;
- params.width = parentParams.height;
- }
- seekbar.setLayoutParams(params);
- }
-
- private int rotateGravityRight(int gravity) {
- int retGravity = 0;
- int layoutDirection = getLayoutDirection();
- final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
- final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
-
- switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
- case Gravity.CENTER_HORIZONTAL:
- retGravity |= Gravity.CENTER_VERTICAL;
+ int margin = (int) getResources().getDimension(R.dimen.volume_dialog_base_margin);
+ switch (rotation) {
+ /*
+ * Landscape: <-|. Have to deal with the nav bar
+ * Seascape: |->. Have to deal with the cutout
+ */
+ case RotationUtils.ROTATION_LANDSCAPE:
+ margin += getNavBarHeight();
break;
- case Gravity.RIGHT:
- retGravity |= Gravity.BOTTOM;
+ case RotationUtils.ROTATION_SEASCAPE:
+ margin += getDisplayCutoutHeight();
break;
- case Gravity.LEFT:
default:
- retGravity |= Gravity.TOP;
break;
}
- switch (verticalGravity) {
- case Gravity.CENTER_VERTICAL:
- retGravity |= Gravity.CENTER_HORIZONTAL;
- break;
- case Gravity.BOTTOM:
- retGravity |= Gravity.LEFT;
- break;
- case Gravity.TOP:
- default:
- retGravity |= Gravity.RIGHT;
- break;
- }
- return retGravity;
+ lp.rightMargin = margin;
+ mChild.setLayoutParams(lp);
}
- private int rotateGravityLeft(int gravity) {
- if (gravity == -1) {
- gravity = Gravity.TOP | Gravity.START;
- }
- int retGravity = 0;
- int layoutDirection = getLayoutDirection();
- final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
- final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
-
- switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
- case Gravity.CENTER_HORIZONTAL:
- retGravity |= Gravity.CENTER_VERTICAL;
- break;
- case Gravity.RIGHT:
- retGravity |= Gravity.TOP;
- break;
- case Gravity.LEFT:
- default:
- retGravity |= Gravity.BOTTOM;
- break;
- }
-
- switch (verticalGravity) {
- case Gravity.CENTER_VERTICAL:
- retGravity |= Gravity.CENTER_HORIZONTAL;
- break;
- case Gravity.BOTTOM:
- retGravity |= Gravity.RIGHT;
- break;
- case Gravity.TOP:
- default:
- retGravity |= Gravity.LEFT;
- break;
- }
- return retGravity;
+ private int getNavBarHeight() {
+ return (int) getResources().getDimension(R.dimen.navigation_bar_size);
}
- private void rotateLeft(View v) {
- if (v.getParent() instanceof FrameLayout) {
- LayoutParams p = (LayoutParams) v.getLayoutParams();
- p.gravity = rotateGravityLeft(p.gravity);
+ //TODO: Find a better way
+ private int getDisplayCutoutHeight() {
+ if (mDisplayCutout == null || mDisplayCutout.isEmpty()) {
+ return 0;
}
- v.setPadding(v.getPaddingTop(), v.getPaddingRight(), v.getPaddingBottom(),
- v.getPaddingLeft());
- MarginLayoutParams params = (MarginLayoutParams) v.getLayoutParams();
- params.setMargins(params.topMargin, params.rightMargin, params.bottomMargin,
- params.leftMargin);
- v.setLayoutParams(params);
+ Rect r = mDisplayCutout.getBoundingRect();
+ return r.bottom - r.top;
}
- private void rotateRight(View v) {
- if (v.getParent() instanceof FrameLayout) {
- LayoutParams p = (LayoutParams) v.getLayoutParams();
- p.gravity = rotateGravityRight(p.gravity);
- }
-
- v.setPadding(v.getPaddingBottom(), v.getPaddingLeft(), v.getPaddingTop(),
- v.getPaddingRight());
- MarginLayoutParams params = (MarginLayoutParams) v.getLayoutParams();
- params.setMargins(params.bottomMargin, params.leftMargin, params.topMargin,
- params.rightMargin);
- v.setLayoutParams(params);
- }
private void animateChild(int oldHeight, int newHeight) {
if (true) return;
@@ -309,12 +173,6 @@
return super.getOutlineProvider();
}
- @Override
- public void setPressed(boolean pressed)
- {
- // Ignore presses because it activates the seekbar thumb unnecessarily.
- }
-
public void setOutsideTouchListener(OnClickListener onClickListener) {
mHasOutsideTouch = true;
requestLayout();
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index f6a54af..c77dcc0 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -63,7 +63,7 @@
// Number scans that returned at least one result.
optional int32 num_non_empty_scan_results = 13;
- // Number of scans that were one time.
+ // Number of single scans requests.
optional int32 num_oneshot_scans = 14;
// Number of repeated background scans that were scheduled to the chip.
@@ -376,6 +376,9 @@
// Wifi power statistics
optional WifiPowerStats wifi_power_stats = 92;
+
+ // Number of connectivity single scan requests.
+ optional int32 num_connectivity_oneshot_scans = 93;
}
// Information that gets logged for every WiFi connection.
@@ -1155,4 +1158,4 @@
// Amount of time wifi is in tx (ms)
optional int64 tx_time_ms = 5;
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 30dfee8..f49cd67 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -1840,14 +1840,6 @@
if (!blocked) {
pw.println(" none");
}
- pw.print(" mUseAllowWhileIdleShortTime: [");
- for (int i = 0; i < mUseAllowWhileIdleShortTime.size(); i++) {
- if (mUseAllowWhileIdleShortTime.valueAt(i)) {
- UserHandle.formatUid(pw, mUseAllowWhileIdleShortTime.keyAt(i));
- pw.print(" ");
- }
- }
- pw.println("]");
pw.println(" mLastAlarmDeliveredForPackage:");
for (int i = 0; i < mLastAlarmDeliveredForPackage.size(); i++) {
@@ -1913,14 +1905,32 @@
if (mLastAllowWhileIdleDispatch.size() > 0) {
pw.println(" Last allow while idle dispatch times:");
for (int i=0; i<mLastAllowWhileIdleDispatch.size(); i++) {
- pw.print(" UID ");
- UserHandle.formatUid(pw, mLastAllowWhileIdleDispatch.keyAt(i));
+ pw.print(" UID ");
+ final int uid = mLastAllowWhileIdleDispatch.keyAt(i);
+ UserHandle.formatUid(pw, uid);
pw.print(": ");
- TimeUtils.formatDuration(mLastAllowWhileIdleDispatch.valueAt(i),
- nowELAPSED, pw);
+ final long lastTime = mLastAllowWhileIdleDispatch.valueAt(i);
+ TimeUtils.formatDuration(lastTime, nowELAPSED, pw);
+
+ final long minInterval = getWhileIdleMinIntervalLocked(uid);
+ pw.print(" Next allowed:");
+ TimeUtils.formatDuration(lastTime + minInterval, nowELAPSED, pw);
+ pw.print(" (");
+ TimeUtils.formatDuration(minInterval, 0, pw);
+ pw.print(")");
+
pw.println();
}
}
+
+ pw.print(" mUseAllowWhileIdleShortTime: [");
+ for (int i = 0; i < mUseAllowWhileIdleShortTime.size(); i++) {
+ if (mUseAllowWhileIdleShortTime.valueAt(i)) {
+ UserHandle.formatUid(pw, mUseAllowWhileIdleShortTime.keyAt(i));
+ pw.print(" ");
+ }
+ }
+ pw.println("]");
pw.println();
if (mLog.dump(pw, " Recent problems", " ")) {
@@ -2181,13 +2191,23 @@
for (int i = 0; i < mLastAllowWhileIdleDispatch.size(); ++i) {
final long token = proto.start(
AlarmManagerServiceProto.LAST_ALLOW_WHILE_IDLE_DISPATCH_TIMES);
- proto.write(AlarmManagerServiceProto.LastAllowWhileIdleDispatch.UID,
- mLastAllowWhileIdleDispatch.keyAt(i));
- proto.write(AlarmManagerServiceProto.LastAllowWhileIdleDispatch.TIME_MS,
- mLastAllowWhileIdleDispatch.valueAt(i));
+ final int uid = mLastAllowWhileIdleDispatch.keyAt(i);
+ final long lastTime = mLastAllowWhileIdleDispatch.valueAt(i);
+
+ proto.write(AlarmManagerServiceProto.LastAllowWhileIdleDispatch.UID, uid);
+ proto.write(AlarmManagerServiceProto.LastAllowWhileIdleDispatch.TIME_MS, lastTime);
+ proto.write(AlarmManagerServiceProto.LastAllowWhileIdleDispatch.NEXT_ALLOWED_MS,
+ lastTime + getWhileIdleMinIntervalLocked(uid));
proto.end(token);
}
+ for (int i = 0; i < mUseAllowWhileIdleShortTime.size(); i++) {
+ if (mUseAllowWhileIdleShortTime.valueAt(i)) {
+ proto.write(AlarmManagerServiceProto.USE_ALLOW_WHILE_IDLE_SHORT_TIME,
+ mUseAllowWhileIdleShortTime.keyAt(i));
+ }
+ }
+
mLog.writeToProto(proto, AlarmManagerServiceProto.RECENT_PROBLEMS);
final FilterStats[] topFilters = new FilterStats[10];
@@ -2866,6 +2886,23 @@
private native int setKernelTime(long nativeData, long millis);
private native int setKernelTimezone(long nativeData, int minuteswest);
+ private long getWhileIdleMinIntervalLocked(int uid) {
+ final boolean dozing = mPendingIdleUntil != null;
+ final boolean ebs = mForceAppStandbyTracker.isForceAllAppsStandbyEnabled();
+ if (!dozing && !ebs) {
+ return mConstants.ALLOW_WHILE_IDLE_SHORT_TIME;
+ }
+ if (dozing) {
+ return mConstants.ALLOW_WHILE_IDLE_LONG_TIME;
+ }
+ if (mUseAllowWhileIdleShortTime.get(uid)) {
+ // if the last allow-while-idle went off while uid was fg, or the uid
+ // recently came into fg, don't block the alarm for long.
+ return mConstants.ALLOW_WHILE_IDLE_SHORT_TIME;
+ }
+ return mConstants.ALLOW_WHILE_IDLE_LONG_TIME;
+ }
+
boolean triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED,
final long nowRTC) {
boolean hasWakeup = false;
@@ -2891,20 +2928,7 @@
// If this is an ALLOW_WHILE_IDLE alarm, we constrain how frequently the app can
// schedule such alarms.
final long lastTime = mLastAllowWhileIdleDispatch.get(alarm.creatorUid, 0);
- final boolean dozing = mPendingIdleUntil != null;
- final boolean ebs = mForceAppStandbyTracker.isForceAllAppsStandbyEnabled();
- final long minTime;
- if (!dozing && !ebs) {
- minTime = lastTime + mConstants.ALLOW_WHILE_IDLE_SHORT_TIME;
- } else if (dozing) {
- minTime = lastTime + mConstants.ALLOW_WHILE_IDLE_LONG_TIME;
- } else if (mUseAllowWhileIdleShortTime.get(alarm.creatorUid)) {
- // if the last allow-while-idle went off while uid was fg, or the uid
- // recently came into fg, don't block the alarm for long.
- minTime = lastTime + mConstants.ALLOW_WHILE_IDLE_SHORT_TIME;
- } else {
- minTime = lastTime + mConstants.ALLOW_WHILE_IDLE_LONG_TIME;
- }
+ final long minTime = lastTime + getWhileIdleMinIntervalLocked(alarm.creatorUid);
if (nowELAPSED < minTime) {
// Whoops, it hasn't been long enough since the last ALLOW_WHILE_IDLE
// alarm went off for this app. Reschedule the alarm to be in the
@@ -3641,6 +3665,7 @@
} else if (Intent.ACTION_UID_REMOVED.equals(action)) {
if (uid >= 0) {
mLastAllowWhileIdleDispatch.delete(uid);
+ mUseAllowWhileIdleShortTime.delete(uid);
}
} else {
if (Intent.ACTION_PACKAGE_REMOVED.equals(action)
@@ -3693,7 +3718,6 @@
@Override public void onUidGone(int uid, boolean disabled) {
synchronized (mLock) {
- mUseAllowWhileIdleShortTime.delete(uid);
if (disabled) {
removeForStoppedLocked(uid);
}
@@ -3701,9 +3725,6 @@
}
@Override public void onUidActive(int uid) {
- synchronized (mLock) {
- mUseAllowWhileIdleShortTime.put(uid, true);
- }
}
@Override public void onUidIdle(int uid, boolean disabled) {
@@ -3766,6 +3787,18 @@
sendPendingBackgroundAlarmsLocked(uid, packageName);
}
}
+
+ @Override
+ public void onUidForeground(int uid, boolean foreground) {
+ synchronized (mLock) {
+ if (foreground) {
+ mUseAllowWhileIdleShortTime.put(uid, true);
+
+ // Note we don't have to drain the pending while-idle alarms here, because
+ // this event should coincide with unblockAlarmsForUid().
+ }
+ }
+ }
};
private final BroadcastStats getStatsLocked(PendingIntent pi) {
@@ -4026,7 +4059,7 @@
if (allowWhileIdle) {
// Record the last time this uid handled an ALLOW_WHILE_IDLE alarm.
mLastAllowWhileIdleDispatch.put(alarm.creatorUid, nowELAPSED);
- if (mForceAppStandbyTracker.isInForeground(alarm.creatorUid)) {
+ if (mForceAppStandbyTracker.isUidInForeground(alarm.creatorUid)) {
mUseAllowWhileIdleShortTime.put(alarm.creatorUid, true);
} else {
mUseAllowWhileIdleShortTime.put(alarm.creatorUid, false);
diff --git a/services/core/java/com/android/server/ForceAppStandbyTracker.java b/services/core/java/com/android/server/ForceAppStandbyTracker.java
index 7604044..339101f 100644
--- a/services/core/java/com/android/server/ForceAppStandbyTracker.java
+++ b/services/core/java/com/android/server/ForceAppStandbyTracker.java
@@ -54,6 +54,7 @@
import com.android.internal.app.IAppOpsService;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
+import com.android.server.DeviceIdleController.LocalService;
import com.android.server.ForceAppStandbyTrackerProto.ExemptedPackage;
import com.android.server.ForceAppStandbyTrackerProto.RunAnyInBackgroundRestrictedPackages;
@@ -64,18 +65,15 @@
/**
* Class to keep track of the information related to "force app standby", which includes:
* - OP_RUN_ANY_IN_BACKGROUND for each package
- * - UID foreground state
+ * - UID foreground/active state
* - User+system power save whitelist
* - Temporary power save whitelist
* - Global "force all apps standby" mode enforced by battery saver.
*
- * TODO: In general, we can reduce the number of callbacks by checking all signals before sending
- * each callback. For example, even when an UID comes into the foreground, if it wasn't
- * originally restricted, then there's no need to send an event.
- * Doing this would be error-prone, so we punt it for now, but we should revisit it later.
+ * TODO: Make it a LocalService.
*
* Test:
- * atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
+ atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
*/
public class ForceAppStandbyTracker {
private static final String TAG = "ForceAppStandbyTracker";
@@ -108,6 +106,11 @@
@GuardedBy("mLock")
final ArraySet<Pair<Integer, String>> mRunAnyRestrictedPackages = new ArraySet<>();
+ /** UIDs that are active. */
+ @GuardedBy("mLock")
+ final SparseBooleanArray mActiveUids = new SparseBooleanArray();
+
+ /** UIDs that are in the foreground. */
@GuardedBy("mLock")
final SparseBooleanArray mForegroundUids = new SparseBooleanArray();
@@ -160,18 +163,20 @@
boolean mForcedAppStandbyEnabled;
interface Stats {
- int UID_STATE_CHANGED = 0;
- int RUN_ANY_CHANGED = 1;
- int ALL_UNWHITELISTED = 2;
- int ALL_WHITELIST_CHANGED = 3;
- int TEMP_WHITELIST_CHANGED = 4;
- int EXEMPT_CHANGED = 5;
- int FORCE_ALL_CHANGED = 6;
- int FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED = 7;
+ int UID_FG_STATE_CHANGED = 0;
+ int UID_ACTIVE_STATE_CHANGED = 1;
+ int RUN_ANY_CHANGED = 2;
+ int ALL_UNWHITELISTED = 3;
+ int ALL_WHITELIST_CHANGED = 4;
+ int TEMP_WHITELIST_CHANGED = 5;
+ int EXEMPT_CHANGED = 6;
+ int FORCE_ALL_CHANGED = 7;
+ int FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED = 8;
}
private final StatLogger mStatLogger = new StatLogger(new String[] {
- "UID_STATE_CHANGED",
+ "UID_FG_STATE_CHANGED",
+ "UID_ACTIVE_STATE_CHANGED",
"RUN_ANY_CHANGED",
"ALL_UNWHITELISTED",
"ALL_WHITELIST_CHANGED",
@@ -260,9 +265,16 @@
* This is called when the foreground state changed for a UID.
*/
private void onUidForegroundStateChanged(ForceAppStandbyTracker sender, int uid) {
+ onUidForeground(uid, sender.isUidInForeground(uid));
+ }
+
+ /**
+ * This is called when the active/idle state changed for a UID.
+ */
+ private void onUidActiveStateChanged(ForceAppStandbyTracker sender, int uid) {
updateJobsForUid(uid);
- if (sender.isInForeground(uid)) {
+ if (sender.isUidActive(uid)) {
unblockAlarmsForUid(uid);
}
}
@@ -355,6 +367,14 @@
*/
public void unblockAlarmsForUidPackage(int uid, String packageName) {
}
+
+ /**
+ * Called when a UID comes into the foreground or the background.
+ *
+ * @see #isUidInForeground(int)
+ */
+ public void onUidForeground(int uid, boolean foreground) {
+ }
}
@VisibleForTesting
@@ -404,8 +424,10 @@
try {
mIActivityManager.registerUidObserver(new UidObserver(),
- ActivityManager.UID_OBSERVER_GONE | ActivityManager.UID_OBSERVER_IDLE
- | ActivityManager.UID_OBSERVER_ACTIVE,
+ ActivityManager.UID_OBSERVER_GONE
+ | ActivityManager.UID_OBSERVER_IDLE
+ | ActivityManager.UID_OBSERVER_ACTIVE
+ | ActivityManager.UID_OBSERVER_PROCSTATE,
ActivityManager.PROCESS_STATE_UNKNOWN, null);
mAppOpsService.startWatchingMode(TARGET_OP, null,
new AppOpsWatcher());
@@ -563,65 +585,77 @@
return true;
}
- /**
- * Puts a UID to {@link #mForegroundUids}.
- */
- void uidToForeground(int uid) {
- synchronized (mLock) {
- if (UserHandle.isCore(uid)) {
- return;
- }
- // TODO This can be optimized by calling indexOfKey and sharing the index for get and
- // put.
- if (mForegroundUids.get(uid)) {
- return;
- }
- mForegroundUids.put(uid, true);
- mHandler.notifyUidForegroundStateChanged(uid);
+ private static boolean addUidToArray(SparseBooleanArray array, int uid) {
+ if (UserHandle.isCore(uid)) {
+ return false;
}
+ if (array.get(uid)) {
+ return false;
+ }
+ array.put(uid, true);
+ return true;
}
- /**
- * Sets false for a UID {@link #mForegroundUids}, or remove it when {@code remove} is true.
- */
- void uidToBackground(int uid, boolean remove) {
- synchronized (mLock) {
- if (UserHandle.isCore(uid)) {
- return;
- }
- // TODO This can be optimized by calling indexOfKey and sharing the index for get and
- // put.
- if (!mForegroundUids.get(uid)) {
- return;
- }
- if (remove) {
- mForegroundUids.delete(uid);
- } else {
- mForegroundUids.put(uid, false);
- }
- mHandler.notifyUidForegroundStateChanged(uid);
+ private static boolean removeUidFromArray(SparseBooleanArray array, int uid, boolean remove) {
+ if (UserHandle.isCore(uid)) {
+ return false;
}
+ if (!array.get(uid)) {
+ return false;
+ }
+ if (remove) {
+ array.delete(uid);
+ } else {
+ array.put(uid, false);
+ }
+ return true;
}
private final class UidObserver extends IUidObserver.Stub {
@Override
public void onUidStateChanged(int uid, int procState, long procStateSeq) {
+ synchronized (mLock) {
+ if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
+ if (removeUidFromArray(mForegroundUids, uid, false)) {
+ mHandler.notifyUidForegroundStateChanged(uid);
+ }
+ } else {
+ if (addUidToArray(mForegroundUids, uid)) {
+ mHandler.notifyUidForegroundStateChanged(uid);
+ }
+ }
+ }
}
@Override
public void onUidGone(int uid, boolean disabled) {
- uidToBackground(uid, /*remove=*/ true);
+ removeUid(uid, true);
}
@Override
public void onUidActive(int uid) {
- uidToForeground(uid);
+ synchronized (mLock) {
+ if (addUidToArray(mActiveUids, uid)) {
+ mHandler.notifyUidActiveStateChanged(uid);
+ }
+ }
}
@Override
public void onUidIdle(int uid, boolean disabled) {
// Just to avoid excessive memcpy, don't remove from the array in this case.
- uidToBackground(uid, /*remove=*/ false);
+ removeUid(uid, false);
+ }
+
+ private void removeUid(int uid, boolean remove) {
+ synchronized (mLock) {
+ if (removeUidFromArray(mActiveUids, uid, remove)) {
+ mHandler.notifyUidActiveStateChanged(uid);
+ }
+ if (removeUidFromArray(mForegroundUids, uid, remove)) {
+ mHandler.notifyUidForegroundStateChanged(uid);
+ }
+ }
}
@Override
@@ -695,22 +729,27 @@
}
private class MyHandler extends Handler {
- private static final int MSG_UID_STATE_CHANGED = 1;
- private static final int MSG_RUN_ANY_CHANGED = 2;
- private static final int MSG_ALL_UNWHITELISTED = 3;
- private static final int MSG_ALL_WHITELIST_CHANGED = 4;
- private static final int MSG_TEMP_WHITELIST_CHANGED = 5;
- private static final int MSG_FORCE_ALL_CHANGED = 6;
- private static final int MSG_USER_REMOVED = 7;
- private static final int MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED = 8;
- private static final int MSG_EXEMPT_CHANGED = 9;
+ private static final int MSG_UID_ACTIVE_STATE_CHANGED = 0;
+ private static final int MSG_UID_FG_STATE_CHANGED = 1;
+ private static final int MSG_RUN_ANY_CHANGED = 3;
+ private static final int MSG_ALL_UNWHITELISTED = 4;
+ private static final int MSG_ALL_WHITELIST_CHANGED = 5;
+ private static final int MSG_TEMP_WHITELIST_CHANGED = 6;
+ private static final int MSG_FORCE_ALL_CHANGED = 7;
+ private static final int MSG_USER_REMOVED = 8;
+ private static final int MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED = 9;
+ private static final int MSG_EXEMPT_CHANGED = 10;
public MyHandler(Looper looper) {
super(looper);
}
+ public void notifyUidActiveStateChanged(int uid) {
+ obtainMessage(MSG_UID_ACTIVE_STATE_CHANGED, uid, 0).sendToTarget();
+ }
+
public void notifyUidForegroundStateChanged(int uid) {
- obtainMessage(MSG_UID_STATE_CHANGED, uid, 0).sendToTarget();
+ obtainMessage(MSG_UID_FG_STATE_CHANGED, uid, 0).sendToTarget();
}
public void notifyRunAnyAppOpsChanged(int uid, @NonNull String packageName) {
@@ -718,26 +757,32 @@
}
public void notifyAllUnwhitelisted() {
+ removeMessages(MSG_ALL_UNWHITELISTED);
obtainMessage(MSG_ALL_UNWHITELISTED).sendToTarget();
}
public void notifyAllWhitelistChanged() {
+ removeMessages(MSG_ALL_WHITELIST_CHANGED);
obtainMessage(MSG_ALL_WHITELIST_CHANGED).sendToTarget();
}
public void notifyTempWhitelistChanged() {
+ removeMessages(MSG_TEMP_WHITELIST_CHANGED);
obtainMessage(MSG_TEMP_WHITELIST_CHANGED).sendToTarget();
}
public void notifyForceAllAppsStandbyChanged() {
+ removeMessages(MSG_FORCE_ALL_CHANGED);
obtainMessage(MSG_FORCE_ALL_CHANGED).sendToTarget();
}
public void notifyForcedAppStandbyFeatureFlagChanged() {
+ removeMessages(MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED);
obtainMessage(MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED).sendToTarget();
}
public void notifyExemptChanged() {
+ removeMessages(MSG_EXEMPT_CHANGED);
obtainMessage(MSG_EXEMPT_CHANGED).sendToTarget();
}
@@ -763,11 +808,18 @@
long start = mStatLogger.getTime();
switch (msg.what) {
- case MSG_UID_STATE_CHANGED:
+ case MSG_UID_ACTIVE_STATE_CHANGED:
+ for (Listener l : cloneListeners()) {
+ l.onUidActiveStateChanged(sender, msg.arg1);
+ }
+ mStatLogger.logDurationStat(Stats.UID_ACTIVE_STATE_CHANGED, start);
+ return;
+
+ case MSG_UID_FG_STATE_CHANGED:
for (Listener l : cloneListeners()) {
l.onUidForegroundStateChanged(sender, msg.arg1);
}
- mStatLogger.logDurationStat(Stats.UID_STATE_CHANGED, start);
+ mStatLogger.logDurationStat(Stats.UID_FG_STATE_CHANGED, start);
return;
case MSG_RUN_ANY_CHANGED:
@@ -846,18 +898,23 @@
mRunAnyRestrictedPackages.removeAt(i);
}
}
- for (int i = mForegroundUids.size() - 1; i >= 0; i--) {
- final int uid = mForegroundUids.keyAt(i);
- final int userId = UserHandle.getUserId(uid);
-
- if (userId == removedUserId) {
- mForegroundUids.removeAt(i);
- }
- }
+ cleanUpArrayForUser(mActiveUids, removedUserId);
+ cleanUpArrayForUser(mForegroundUids, removedUserId);
mExemptedPackages.remove(removedUserId);
}
}
+ private void cleanUpArrayForUser(SparseBooleanArray array, int removedUserId) {
+ for (int i = array.size() - 1; i >= 0; i--) {
+ final int uid = array.keyAt(i);
+ final int userId = UserHandle.getUserId(uid);
+
+ if (userId == removedUserId) {
+ array.removeAt(i);
+ }
+ }
+ }
+
/**
* Called by device idle controller to update the power save whitelists.
*/
@@ -954,7 +1011,7 @@
*/
private boolean isRestricted(int uid, @NonNull String packageName,
boolean useTempWhitelistToo, boolean exemptOnBatterySaver) {
- if (isInForeground(uid)) {
+ if (isUidActive(uid)) {
return false;
}
synchronized (mLock) {
@@ -982,13 +1039,29 @@
}
/**
+ * @return whether a UID is in active or not.
+ *
+ * Note this information is based on the UID proc state callback, meaning it's updated
+ * asynchronously and may subtly be stale. If the fresh data is needed, use
+ * {@link ActivityManagerInternal#getUidProcessState} instead.
+ */
+ public boolean isUidActive(int uid) {
+ if (UserHandle.isCore(uid)) {
+ return true;
+ }
+ synchronized (mLock) {
+ return mActiveUids.get(uid);
+ }
+ }
+
+ /**
* @return whether a UID is in the foreground or not.
*
* Note this information is based on the UID proc state callback, meaning it's updated
* asynchronously and may subtly be stale. If the fresh data is needed, use
* {@link ActivityManagerInternal#getUidProcessState} instead.
*/
- public boolean isInForeground(int uid) {
+ public boolean isUidInForeground(int uid) {
if (UserHandle.isCore(uid)) {
return true;
}
@@ -1062,17 +1135,12 @@
pw.println(mIsPluggedIn);
pw.print(indent);
- pw.print("Foreground uids: [");
+ pw.print("Active uids: ");
+ dumpUids(pw, mActiveUids);
- String sep = "";
- for (int i = 0; i < mForegroundUids.size(); i++) {
- if (mForegroundUids.valueAt(i)) {
- pw.print(sep);
- pw.print(UserHandle.formatUid(mForegroundUids.keyAt(i)));
- sep = " ";
- }
- }
- pw.println("]");
+ pw.print(indent);
+ pw.print("Foreground uids: ");
+ dumpUids(pw, mForegroundUids);
pw.print(indent);
pw.print("Whitelist appids: ");
@@ -1114,6 +1182,20 @@
}
}
+ private void dumpUids(PrintWriter pw, SparseBooleanArray array) {
+ pw.print("[");
+
+ String sep = "";
+ for (int i = 0; i < array.size(); i++) {
+ if (array.valueAt(i)) {
+ pw.print(sep);
+ pw.print(UserHandle.formatUid(array.keyAt(i)));
+ sep = " ";
+ }
+ }
+ pw.println("]");
+ }
+
public void dumpProto(ProtoOutputStream proto, long fieldId) {
synchronized (mLock) {
final long token = proto.start(fieldId);
@@ -1125,6 +1207,13 @@
mForceAllAppStandbyForSmallBattery);
proto.write(ForceAppStandbyTrackerProto.IS_PLUGGED_IN, mIsPluggedIn);
+ for (int i = 0; i < mActiveUids.size(); i++) {
+ if (mActiveUids.valueAt(i)) {
+ proto.write(ForceAppStandbyTrackerProto.ACTIVE_UIDS,
+ mActiveUids.keyAt(i));
+ }
+ }
+
for (int i = 0; i < mForegroundUids.size(); i++) {
if (mForegroundUids.valueAt(i)) {
proto.write(ForceAppStandbyTrackerProto.FOREGROUND_UIDS,
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index fc91d0d..2f42585 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -59,6 +59,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.TestApi;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
@@ -468,7 +469,7 @@
int mCurFocusedWindowSoftInputMode;
/**
- * The client by which {@link #mCurFocusedWindow} was reported. Used only for debugging.
+ * The client by which {@link #mCurFocusedWindow} was reported.
*/
ClientState mCurFocusedWindowClient;
@@ -2989,8 +2990,8 @@
final int uid = Binder.getCallingUid();
if (UserHandle.getAppId(uid) == Process.SYSTEM_UID) {
return true;
- } else if (mCurClient != null && client != null
- && mCurClient.client.asBinder() == client.asBinder()) {
+ } else if (mCurFocusedWindowClient != null && client != null
+ && mCurFocusedWindowClient.client.asBinder() == client.asBinder()) {
return true;
} else if (mCurIntent != null && InputMethodUtils.checkIfPackageBelongsToUid(
mAppOpsManager,
@@ -3026,6 +3027,15 @@
}
}
+ public boolean isInputMethodPickerShownForTest() {
+ synchronized(mMethodMap) {
+ if (mSwitchingDialog == null) {
+ return false;
+ }
+ return mSwitchingDialog.isShowing();
+ }
+ }
+
@Override
public void setInputMethod(IBinder token, String id) {
if (!calledFromValidUser()) {
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 6747be3..6743484 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -35,6 +35,7 @@
import android.telephony.CellInfo;
import android.telephony.CellLocation;
import android.telephony.DisconnectCause;
+import android.telephony.LocationAccessPolicy;
import android.telephony.PhoneStateListener;
import android.telephony.PreciseCallState;
import android.telephony.PreciseDataConnectionState;
@@ -93,7 +94,8 @@
IPhoneStateListener callback;
IOnSubscriptionsChangedListener onSubscriptionsChangedListenerCallback;
- int callerUserId;
+ int callerUid;
+ int callerPid;
int events;
@@ -117,7 +119,7 @@
+ " callback=" + callback
+ " onSubscriptionsChangedListenererCallback="
+ onSubscriptionsChangedListenerCallback
- + " callerUserId=" + callerUserId + " subId=" + subId + " phoneId=" + phoneId
+ + " callerUid=" + callerUid + " subId=" + subId + " phoneId=" + phoneId
+ " events=" + Integer.toHexString(events)
+ " canReadPhoneState=" + canReadPhoneState + "}";
}
@@ -356,6 +358,8 @@
public void addOnSubscriptionsChangedListener(String callingPackage,
IOnSubscriptionsChangedListener callback) {
int callerUserId = UserHandle.getCallingUserId();
+ mContext.getSystemService(AppOpsManager.class)
+ .checkPackage(Binder.getCallingUid(), callingPackage);
if (VDBG) {
log("listen oscl: E pkg=" + callingPackage + " myUserId=" + UserHandle.myUserId()
+ " callerUserId=" + callerUserId + " callback=" + callback
@@ -399,7 +403,8 @@
r.onSubscriptionsChangedListenerCallback = callback;
r.callingPackage = callingPackage;
- r.callerUserId = callerUserId;
+ r.callerUid = Binder.getCallingUid();
+ r.callerPid = Binder.getCallingPid();
r.events = 0;
r.canReadPhoneState = true; // permission has been enforced above
if (DBG) {
@@ -470,6 +475,8 @@
private void listen(String callingPackage, IPhoneStateListener callback, int events,
boolean notifyNow, int subId) {
int callerUserId = UserHandle.getCallingUserId();
+ mContext.getSystemService(AppOpsManager.class)
+ .checkPackage(Binder.getCallingUid(), callingPackage);
if (VDBG) {
log("listen: E pkg=" + callingPackage + " events=0x" + Integer.toHexString(events)
+ " notifyNow=" + notifyNow + " subId=" + subId + " myUserId="
@@ -514,7 +521,8 @@
r.callback = callback;
r.callingPackage = callingPackage;
- r.callerUserId = callerUserId;
+ r.callerUid = Binder.getCallingUid();
+ r.callerPid = Binder.getCallingPid();
boolean isPhoneStateEvent = (events & (CHECK_PHONE_STATE_PERMISSION_MASK
| ENFORCE_PHONE_STATE_PERMISSION_MASK)) != 0;
r.canReadPhoneState = isPhoneStateEvent && canReadPhoneState(callingPackage);
@@ -572,8 +580,10 @@
try {
if (DBG_LOC) log("listen: mCellLocation = "
+ mCellLocation[phoneId]);
- r.callback.onCellLocationChanged(
- new Bundle(mCellLocation[phoneId]));
+ if (checkLocationAccess(r)) {
+ r.callback.onCellLocationChanged(
+ new Bundle(mCellLocation[phoneId]));
+ }
} catch (RemoteException ex) {
remove(r.binder);
}
@@ -619,7 +629,9 @@
try {
if (DBG_LOC) log("listen: mCellInfo[" + phoneId + "] = "
+ mCellInfo.get(phoneId));
- r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
+ if (checkLocationAccess(r)) {
+ r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
+ }
} catch (RemoteException ex) {
remove(r.binder);
}
@@ -979,7 +991,8 @@
mCellInfo.set(phoneId, cellInfo);
for (Record r : mRecords) {
if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO) &&
- idMatch(r.subId, subId, phoneId)) {
+ idMatch(r.subId, subId, phoneId) &&
+ checkLocationAccess(r)) {
try {
if (DBG_LOC) {
log("notifyCellInfo: mCellInfo=" + cellInfo + " r=" + r);
@@ -1262,7 +1275,8 @@
mCellLocation[phoneId] = cellLocation;
for (Record r : mRecords) {
if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION) &&
- idMatch(r.subId, subId, phoneId)) {
+ idMatch(r.subId, subId, phoneId) &&
+ checkLocationAccess(r)) {
try {
if (DBG_LOC) {
log("notifyCellLocation: cellLocation=" + cellLocation
@@ -1706,10 +1720,11 @@
boolean valid = false;
try {
foregroundUser = ActivityManager.getCurrentUser();
- valid = r.callerUserId == foregroundUser && r.matchPhoneStateListenerEvent(events);
+ valid = UserHandle.getUserId(r.callerUid) == foregroundUser
+ && r.matchPhoneStateListenerEvent(events);
if (DBG | DBG_LOC) {
log("validateEventsAndUserLocked: valid=" + valid
- + " r.callerUserId=" + r.callerUserId + " foregroundUser=" + foregroundUser
+ + " r.callerUid=" + r.callerUid + " foregroundUser=" + foregroundUser
+ " r.events=" + r.events + " events=" + events);
}
} finally {
@@ -1741,6 +1756,16 @@
}
}
+ private boolean checkLocationAccess(Record r) {
+ long token = Binder.clearCallingIdentity();
+ try {
+ return LocationAccessPolicy.canAccessCellLocation(mContext,
+ r.callingPackage, r.callerUid, r.callerPid);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
private void checkPossibleMissNotify(Record r, int phoneId) {
int events = r.events;
@@ -1788,7 +1813,9 @@
log("checkPossibleMissNotify: onCellInfoChanged[" + phoneId + "] = "
+ mCellInfo.get(phoneId));
}
- r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
+ if (checkLocationAccess(r)) {
+ r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
+ }
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
}
@@ -1836,7 +1863,9 @@
try {
if (DBG_LOC) log("checkPossibleMissNotify: onCellLocationChanged mCellLocation = "
+ mCellLocation[phoneId]);
- r.callback.onCellLocationChanged(new Bundle(mCellLocation[phoneId]));
+ if (checkLocationAccess(r)) {
+ r.callback.onCellLocationChanged(new Bundle(mCellLocation[phoneId]));
+ }
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index f370393..8d1632a 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -802,6 +802,7 @@
doDump(fd, pw, new String[]{"recents"}, asProto);
doDump(fd, pw, new String[]{"lastanr"}, asProto);
doDump(fd, pw, new String[]{"starter"}, asProto);
+ doDump(fd, pw, new String[]{"containers"}, asProto);
if (mAssociations.size() > 0) {
doDump(fd, pw, new String[]{"associations"}, asProto);
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index f0c90e0..24a77c7 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -115,6 +115,7 @@
private int mActivityType;
private int mTaskId;
private boolean mIsTaskOverlay;
+ private boolean mIsLockTask;
final boolean mDumping;
@@ -278,6 +279,7 @@
mActivityType = ACTIVITY_TYPE_UNDEFINED;
mTaskId = INVALID_TASK_ID;
mIsTaskOverlay = false;
+ mIsLockTask = false;
return Intent.parseCommandArgs(this, new Intent.CommandOptionHandler() {
@Override
@@ -334,6 +336,8 @@
mTaskId = Integer.parseInt(getNextArgRequired());
} else if (opt.equals("--task-overlay")) {
mIsTaskOverlay = true;
+ } else if (opt.equals("--lock-task")) {
+ mIsLockTask = true;
} else {
return false;
}
@@ -429,13 +433,22 @@
options.setLaunchActivityType(mActivityType);
}
if (mTaskId != INVALID_TASK_ID) {
- options = ActivityOptions.makeBasic();
+ if (options == null) {
+ options = ActivityOptions.makeBasic();
+ }
options.setLaunchTaskId(mTaskId);
if (mIsTaskOverlay) {
options.setTaskOverlay(true, true /* canResume */);
}
}
+ android.util.Log.d("bfranz", "I was here: " + mIsLockTask);
+ if (mIsLockTask) {
+ if (options == null) {
+ options = ActivityOptions.makeBasic();
+ }
+ options.setLockTaskMode(true);
+ }
if (mWaitOption) {
result = mInterface.startActivityAndWait(null, null, intent, mimeType,
null, null, 0, mStartFlags, profilerInfo,
diff --git a/services/core/java/com/android/server/am/LockTaskController.java b/services/core/java/com/android/server/am/LockTaskController.java
index 21f9135..e5762d2 100644
--- a/services/core/java/com/android/server/am/LockTaskController.java
+++ b/services/core/java/com/android/server/am/LockTaskController.java
@@ -38,6 +38,7 @@
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE;
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_WHITELISTED;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Activity;
@@ -142,14 +143,6 @@
TelecomManager mTelecomManager;
/**
- * Helper that is responsible for showing the right toast when a disallowed activity operation
- * occurred. In pinned mode, we show instructions on how to break out of this mode, whilst in
- * fully locked mode we only show that unlocking is blocked.
- */
- @VisibleForTesting
- LockTaskNotify mLockTaskNotify;
-
- /**
* The chain of tasks in LockTask mode, in the order of when they first entered LockTask mode.
*
* The first task in the list, which started the current LockTask session, is called the root
@@ -475,7 +468,7 @@
getDevicePolicyManager().notifyLockTaskModeChanged(false, null, userId);
}
if (mLockTaskModeState == LOCK_TASK_MODE_PINNED) {
- getLockTaskNotify().showPinningExitToast();
+ getStatusBarService().showPinningEnterExitToast(false /* entering */);
}
} catch (RemoteException ex) {
throw new RuntimeException(ex);
@@ -490,7 +483,11 @@
*/
void showLockTaskToast() {
if (mLockTaskModeState == LOCK_TASK_MODE_PINNED) {
- mHandler.post(() -> getLockTaskNotify().showEscapeToast());
+ try {
+ getStatusBarService().showPinningEscapeToast();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to send pinning escape toast", e);
+ }
}
}
@@ -582,7 +579,7 @@
// When lock task starts, we disable the status bars.
try {
if (lockTaskModeState == LOCK_TASK_MODE_PINNED) {
- getLockTaskNotify().showPinningStartToast();
+ getStatusBarService().showPinningEnterExitToast(true /* entering */);
}
mLockTaskModeState = lockTaskModeState;
setStatusBarState(lockTaskModeState, userId);
@@ -835,15 +832,6 @@
return mTelecomManager;
}
- // Should only be called on the handler thread
- @NonNull
- private LockTaskNotify getLockTaskNotify() {
- if (mLockTaskNotify == null) {
- mLockTaskNotify = new LockTaskNotify(mContext);
- }
- return mLockTaskNotify;
- }
-
public void dump(PrintWriter pw, String prefix) {
pw.println(prefix + "LockTaskController");
prefix = prefix + " ";
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/Convert.java b/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
index 3bb3d1f..5af19ec 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
@@ -21,6 +21,7 @@
import android.hardware.broadcastradio.V2_0.AmFmBandRange;
import android.hardware.broadcastradio.V2_0.AmFmRegionConfig;
import android.hardware.broadcastradio.V2_0.Announcement;
+import android.hardware.broadcastradio.V2_0.DabTableEntry;
import android.hardware.broadcastradio.V2_0.IdentifierType;
import android.hardware.broadcastradio.V2_0.ProgramFilter;
import android.hardware.broadcastradio.V2_0.ProgramIdentifier;
@@ -196,9 +197,15 @@
return bands.toArray(new RadioManager.BandDescriptor[bands.size()]);
}
+ private static @Nullable Map<String, Integer> dabConfigFromHal(
+ @Nullable List<DabTableEntry> config) {
+ if (config == null) return null;
+ return config.stream().collect(Collectors.toMap(e -> e.label, e -> e.frequency));
+ }
+
static @NonNull RadioManager.ModuleProperties
propertiesFromHal(int id, @NonNull String serviceName, @NonNull Properties prop,
- @Nullable AmFmRegionConfig amfmConfig) {
+ @Nullable AmFmRegionConfig amfmConfig, @Nullable List<DabTableEntry> dabConfig) {
Objects.requireNonNull(serviceName);
Objects.requireNonNull(prop);
@@ -228,6 +235,7 @@
true, // isBgScanSupported is deprecated
supportedProgramTypes,
supportedIdentifierTypes,
+ dabConfigFromHal(dabConfig),
vendorInfoFromHal(prop.vendorInfo)
);
}
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
index 50f032d..daec97a 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
@@ -24,6 +24,7 @@
import android.hardware.radio.RadioManager;
import android.hardware.broadcastradio.V2_0.AmFmRegionConfig;
import android.hardware.broadcastradio.V2_0.Announcement;
+import android.hardware.broadcastradio.V2_0.DabTableEntry;
import android.hardware.broadcastradio.V2_0.IAnnouncementListener;
import android.hardware.broadcastradio.V2_0.IBroadcastRadio;
import android.hardware.broadcastradio.V2_0.ICloseHandle;
@@ -58,12 +59,17 @@
if (service == null) return null;
Mutable<AmFmRegionConfig> amfmConfig = new Mutable<>();
- service.getAmFmRegionConfig(false, (int result, AmFmRegionConfig config) -> {
+ service.getAmFmRegionConfig(false, (result, config) -> {
if (result == Result.OK) amfmConfig.value = config;
});
- RadioManager.ModuleProperties prop =
- Convert.propertiesFromHal(idx, fqName, service.getProperties(), amfmConfig.value);
+ Mutable<List<DabTableEntry>> dabConfig = new Mutable<>();
+ service.getDabRegionConfig((result, config) -> {
+ if (result == Result.OK) dabConfig.value = config;
+ });
+
+ RadioManager.ModuleProperties prop = Convert.propertiesFromHal(idx, fqName,
+ service.getProperties(), amfmConfig.value, dabConfig.value);
return new RadioModule(service, prop);
} catch (RemoteException ex) {
diff --git a/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java b/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
index 2e4567a..5eb7700 100644
--- a/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
+++ b/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
@@ -92,7 +92,7 @@
jobStatus.printUniqueId(pw);
pw.print(" from ");
UserHandle.formatUid(pw, uid);
- pw.print(mForceAppStandbyTracker.isInForeground(uid) ? " foreground" : " background");
+ pw.print(mForceAppStandbyTracker.isUidActive(uid) ? " active" : " idle");
if (mForceAppStandbyTracker.isUidPowerSaveWhitelisted(uid) ||
mForceAppStandbyTracker.isUidTempPowerSaveWhitelisted(uid)) {
pw.print(", whitelisted");
@@ -136,7 +136,7 @@
proto.write(TrackedJob.SOURCE_PACKAGE_NAME, sourcePkg);
proto.write(TrackedJob.IS_IN_FOREGROUND,
- mForceAppStandbyTracker.isInForeground(sourceUid));
+ mForceAppStandbyTracker.isUidActive(sourceUid));
proto.write(TrackedJob.IS_WHITELISTED,
mForceAppStandbyTracker.isUidPowerSaveWhitelisted(sourceUid) ||
mForceAppStandbyTracker.isUidTempPowerSaveWhitelisted(sourceUid));
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 28fa86b..e715724 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -383,8 +383,8 @@
return KeyStore.getInstance();
}
- public RecoverableKeyStoreManager getRecoverableKeyStoreManager() {
- return RecoverableKeyStoreManager.getInstance(mContext);
+ public RecoverableKeyStoreManager getRecoverableKeyStoreManager(KeyStore keyStore) {
+ return RecoverableKeyStoreManager.getInstance(mContext, keyStore);
}
public IStorageManager getStorageManager() {
@@ -413,7 +413,7 @@
mInjector = injector;
mContext = injector.getContext();
mKeyStore = injector.getKeyStore();
- mRecoverableKeyStoreManager = injector.getRecoverableKeyStoreManager();
+ mRecoverableKeyStoreManager = injector.getRecoverableKeyStoreManager(mKeyStore);
mHandler = injector.getHandler();
mStrongAuth = injector.getStrongAuth();
mActivityManager = injector.getActivityManager();
@@ -1887,7 +1887,7 @@
mSpManager.removeUser(userId);
mStorage.removeUser(userId);
mStrongAuth.removeUser(userId);
- cleanSpCache();
+ tryRemoveUserFromSpCacheLater(userId);
final KeyStore ks = KeyStore.getInstance();
ks.onUserRemoved(userId);
@@ -2064,6 +2064,16 @@
return mRecoverableKeyStoreManager.generateAndStoreKey(alias);
}
+ @Override
+ public String generateKey(@NonNull String alias, byte[] account) throws RemoteException {
+ return mRecoverableKeyStoreManager.generateKey(alias, account);
+ }
+
+ @Override
+ public String getKey(@NonNull String alias) throws RemoteException {
+ return mRecoverableKeyStoreManager.getKey(alias);
+ }
+
private static final String[] VALID_SETTINGS = new String[] {
LockPatternUtils.LOCKOUT_PERMANENT_KEY,
LockPatternUtils.LOCKOUT_ATTEMPT_DEADLINE,
@@ -2141,6 +2151,13 @@
private SparseArray<AuthenticationToken> mSpCache = new SparseArray();
private void onAuthTokenKnownForUser(@UserIdInt int userId, AuthenticationToken auth) {
+ // Preemptively cache the SP and then try to remove it in a handler.
+ Slog.i(TAG, "Caching SP for user " + userId);
+ synchronized (mSpManager) {
+ mSpCache.put(userId, auth);
+ }
+ tryRemoveUserFromSpCacheLater(userId);
+
// Pass the primary user's auth secret to the HAL
if (mAuthSecretService != null && mUserManager.getUserInfo(userId).isPrimary()) {
try {
@@ -2154,33 +2171,25 @@
Slog.w(TAG, "Failed to pass primary user secret to AuthSecret HAL", e);
}
}
-
- // Update the SP cache, removing the entry when allowed
- synchronized (mSpManager) {
- if (shouldCacheSpForUser(userId)) {
- Slog.i(TAG, "Caching SP for user " + userId);
- mSpCache.put(userId, auth);
- } else {
- Slog.i(TAG, "Not caching SP for user " + userId);
- mSpCache.delete(userId);
- }
- }
}
- /** Clean up the SP cache by removing unneeded entries. */
- private void cleanSpCache() {
- synchronized (mSpManager) {
- // Preserve indicies after removal by iterating backwards
- for (int i = mSpCache.size() - 1; i >= 0; --i) {
- final int userId = mSpCache.keyAt(i);
- if (!shouldCacheSpForUser(userId)) {
- Slog.i(TAG, "Uncaching SP for user " + userId);
- mSpCache.removeAt(i);
+ private void tryRemoveUserFromSpCacheLater(@UserIdInt int userId) {
+ mHandler.post(() -> {
+ if (!shouldCacheSpForUser(userId)) {
+ // The transition from 'should not cache' to 'should cache' can only happen if
+ // certain admin apps are installed after provisioning e.g. via adb. This is not
+ // a common case and we do not seamlessly support; it may result in the SP not
+ // being cached when it is needed. The cache can be re-populated by verifying
+ // the credential again.
+ Slog.i(TAG, "Removing SP from cache for user " + userId);
+ synchronized (mSpManager) {
+ mSpCache.remove(userId);
}
}
- }
+ });
}
+ /** Do not hold any of the locks from this service when calling. */
private boolean shouldCacheSpForUser(@UserIdInt int userId) {
// Before the user setup has completed, an admin could be installed that requires the SP to
// be cached (see below).
@@ -2731,7 +2740,7 @@
}
@Override
- public void onChange(boolean selfChange, Uri uri) {
+ public void onChange(boolean selfChange, Uri uri, @UserIdInt int userId) {
if (mDeviceProvisionedUri.equals(uri)) {
updateRegistration();
@@ -2741,7 +2750,7 @@
clearFrpCredentialIfOwnerNotSecure();
}
} else if (mUserSetupCompleteUri.equals(uri)) {
- cleanSpCache();
+ tryRemoveUserFromSpCacheLater(userId);
}
}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeyStoreProxyImpl.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeyStoreProxyImpl.java
index 59132da..285e722 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeyStoreProxyImpl.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeyStoreProxyImpl.java
@@ -16,10 +16,13 @@
package com.android.server.locksettings.recoverablekeystore;
+import java.io.IOException;
+import java.security.cert.CertificateException;
import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
/**
@@ -27,6 +30,7 @@
*/
public class KeyStoreProxyImpl implements KeyStoreProxy {
+ private static final String ANDROID_KEY_STORE_PROVIDER = "AndroidKeyStore";
private final KeyStore mKeyStore;
/**
@@ -57,4 +61,21 @@
public void deleteEntry(String alias) throws KeyStoreException {
mKeyStore.deleteEntry(alias);
}
+
+ /**
+ * Returns AndroidKeyStore-provided {@link KeyStore}, having already invoked
+ * {@link KeyStore#load(KeyStore.LoadStoreParameter)}.
+ *
+ * @throws KeyStoreException if there was a problem getting or initializing the key store.
+ */
+ public static KeyStore getAndLoadAndroidKeyStore() throws KeyStoreException {
+ KeyStore keyStore = KeyStore.getInstance(ANDROID_KEY_STORE_PROVIDER);
+ try {
+ keyStore.load(/*param=*/ null);
+ } catch (CertificateException | IOException | NoSuchAlgorithmException e) {
+ // Should never happen.
+ throw new KeyStoreException("Unable to load keystore.", e);
+ }
+ return keyStore;
+ }
}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
index ec72b22..fda6cdf 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
@@ -37,21 +37,23 @@
import android.security.keystore.recovery.KeyChainSnapshot;
import android.security.keystore.recovery.RecoveryController;
import android.security.keystore.recovery.WrappedApplicationKey;
+import android.security.KeyStore;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.HexDump;
+import com.android.server.locksettings.recoverablekeystore.storage.ApplicationKeyStorage;
import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDb;
import com.android.server.locksettings.recoverablekeystore.storage.RecoverySessionStorage;
import com.android.server.locksettings.recoverablekeystore.storage.RecoverySnapshotStorage;
import java.security.InvalidKeyException;
-import java.security.KeyStoreException;
import java.security.KeyFactory;
+import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
-import java.security.UnrecoverableKeyException;
import java.security.spec.InvalidKeySpecException;
+import java.security.UnrecoverableKeyException;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.HashMap;
@@ -82,18 +84,23 @@
private final RecoverableKeyGenerator mRecoverableKeyGenerator;
private final RecoverySnapshotStorage mSnapshotStorage;
private final PlatformKeyManager mPlatformKeyManager;
+ private final KeyStore mKeyStore;
+ private final ApplicationKeyStorage mApplicationKeyStorage;
/**
* Returns a new or existing instance.
*
* @hide
*/
- public static synchronized RecoverableKeyStoreManager getInstance(Context context) {
+ public static synchronized RecoverableKeyStoreManager
+ getInstance(Context context, KeyStore keystore) {
if (mInstance == null) {
RecoverableKeyStoreDb db = RecoverableKeyStoreDb.newInstance(context);
PlatformKeyManager platformKeyManager;
+ ApplicationKeyStorage applicationKeyStorage;
try {
platformKeyManager = PlatformKeyManager.getInstance(context, db);
+ applicationKeyStorage = ApplicationKeyStorage.getInstance(keystore);
} catch (NoSuchAlgorithmException e) {
// Impossible: all algorithms must be supported by AOSP
throw new RuntimeException(e);
@@ -103,12 +110,14 @@
mInstance = new RecoverableKeyStoreManager(
context.getApplicationContext(),
+ keystore,
db,
new RecoverySessionStorage(),
Executors.newSingleThreadExecutor(),
new RecoverySnapshotStorage(),
new RecoverySnapshotListenersStorage(),
- platformKeyManager);
+ platformKeyManager,
+ applicationKeyStorage);
}
return mInstance;
}
@@ -116,19 +125,23 @@
@VisibleForTesting
RecoverableKeyStoreManager(
Context context,
+ KeyStore keystore,
RecoverableKeyStoreDb recoverableKeyStoreDb,
RecoverySessionStorage recoverySessionStorage,
ExecutorService executorService,
RecoverySnapshotStorage snapshotStorage,
RecoverySnapshotListenersStorage listenersStorage,
- PlatformKeyManager platformKeyManager) {
+ PlatformKeyManager platformKeyManager,
+ ApplicationKeyStorage applicationKeyStorage) {
mContext = context;
+ mKeyStore = keystore;
mDatabase = recoverableKeyStoreDb;
mRecoverySessionStorage = recoverySessionStorage;
mExecutorService = executorService;
mListenersStorage = listenersStorage;
mSnapshotStorage = snapshotStorage;
mPlatformKeyManager = platformKeyManager;
+ mApplicationKeyStorage = applicationKeyStorage;
try {
mRecoverableKeyGenerator = RecoverableKeyGenerator.newInstance(mDatabase);
@@ -406,6 +419,7 @@
}
/**
+ * Deprecated
* Generates a key named {@code alias} in the recoverable store for the calling uid. Then
* returns the raw key material.
*
@@ -450,9 +464,55 @@
boolean wasRemoved = mDatabase.removeKey(uid, alias);
if (wasRemoved) {
mDatabase.setShouldCreateSnapshot(userId, uid, true);
+ mApplicationKeyStorage.deleteEntry(userId, uid, alias);
}
}
+ /**
+ * Generates a key named {@code alias} in caller's namespace.
+ * The key is stored in system service keystore namespace.
+ *
+ * @return grant alias, which caller can use to access the key.
+ */
+ public String generateKey(@NonNull String alias, byte[] account) throws RemoteException {
+ int uid = Binder.getCallingUid();
+ int userId = UserHandle.getCallingUserId();
+
+ PlatformEncryptionKey encryptionKey;
+ try {
+ encryptionKey = mPlatformKeyManager.getEncryptKey(userId);
+ } catch (NoSuchAlgorithmException e) {
+ // Impossible: all algorithms must be supported by AOSP
+ throw new RuntimeException(e);
+ } catch (KeyStoreException | UnrecoverableKeyException e) {
+ throw new ServiceSpecificException(ERROR_SERVICE_INTERNAL_ERROR, e.getMessage());
+ } catch (InsecureUserException e) {
+ throw new ServiceSpecificException(ERROR_INSECURE_USER, e.getMessage());
+ }
+
+ try {
+ byte[] secretKey =
+ mRecoverableKeyGenerator.generateAndStoreKey(encryptionKey, userId, uid, alias);
+ mApplicationKeyStorage.setSymmetricKeyEntry(userId, uid, alias, secretKey);
+ String grantAlias = mApplicationKeyStorage.getGrantAlias(userId, uid, alias);
+ return grantAlias;
+ } catch (KeyStoreException | InvalidKeyException | RecoverableKeyStorageException e) {
+ throw new ServiceSpecificException(ERROR_SERVICE_INTERNAL_ERROR, e.getMessage());
+ }
+ }
+
+ /**
+ * Gets a key named {@code alias} in caller's namespace.
+ *
+ * @return grant alias, which caller can use to access the key.
+ */
+ public String getKey(@NonNull String alias) throws RemoteException {
+ int uid = Binder.getCallingUid();
+ int userId = UserHandle.getCallingUserId();
+ String grantAlias = mApplicationKeyStorage.getGrantAlias(userId, uid, alias);
+ return grantAlias;
+ }
+
private byte[] decryptRecoveryKey(
RecoverySessionStorage.Entry sessionEntry, byte[] encryptedClaimResponse)
throws RemoteException, ServiceSpecificException {
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java
new file mode 100644
index 0000000..600a534
--- /dev/null
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java
@@ -0,0 +1,113 @@
+/*
+ * 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 com.android.server.locksettings.recoverablekeystore.storage;
+
+import static android.security.keystore.RecoveryController.ERROR_SERVICE_INTERNAL_ERROR;
+
+import android.annotation.Nullable;
+import android.os.ServiceSpecificException;
+import android.security.Credentials;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyProperties;
+import android.security.keystore.KeyProtection;
+import android.security.keystore.recovery.KeyChainSnapshot;
+import android.security.KeyStore;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.locksettings.recoverablekeystore.KeyStoreProxy;
+import com.android.server.locksettings.recoverablekeystore.KeyStoreProxyImpl;
+
+import java.security.KeyStore.SecretKeyEntry;
+import java.security.KeyStoreException;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * Storage for Application keys in LockSettings service KeyStore namespace.
+ *
+ * <p> Uses KeyStore's grant mechanism to make keys usable by application process without
+ * revealing key material
+ */
+public class ApplicationKeyStorage {
+ private static final String APPLICATION_KEY_ALIAS_PREFIX =
+ "com.android.server.locksettings.recoverablekeystore/application/";
+
+ KeyStoreProxy mKeyStore;
+ KeyStore mKeystoreService;
+
+ public static ApplicationKeyStorage getInstance(KeyStore keystoreService)
+ throws KeyStoreException {
+ return new ApplicationKeyStorage(
+ new KeyStoreProxyImpl(KeyStoreProxyImpl.getAndLoadAndroidKeyStore()),
+ keystoreService);
+ }
+
+ @VisibleForTesting
+ ApplicationKeyStorage(KeyStoreProxy keyStore, KeyStore keystoreService) {
+ mKeyStore = keyStore;
+ mKeystoreService = keystoreService;
+ }
+
+ /**
+ * Returns grant alias, valid in Applications namespace.
+ */
+ public @Nullable String getGrantAlias(int userId, int uid, String alias) {
+ // Aliases used by {@link KeyStore} are different than used by public API.
+ // {@code USER_PRIVATE_KEY} prefix is used secret keys.
+ String keystoreAlias = Credentials.USER_PRIVATE_KEY + getInternalAlias(userId, uid, alias);
+ return mKeystoreService.grant(keystoreAlias, uid);
+ }
+
+ public void setSymmetricKeyEntry(int userId, int uid, String alias, byte[] secretKey)
+ throws KeyStoreException {
+ try {
+ mKeyStore.setEntry(
+ getInternalAlias(userId, uid, alias),
+ new SecretKeyEntry(
+ new SecretKeySpec(secretKey, KeyProperties.KEY_ALGORITHM_AES)),
+ new KeyProtection.Builder(
+ KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
+ .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
+ .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+ .build());
+ } catch (KeyStoreException e) {
+ throw new ServiceSpecificException(ERROR_SERVICE_INTERNAL_ERROR, e.getMessage());
+ }
+ }
+
+ public void deleteEntry(int userId, int uid, String alias) {
+ try {
+ mKeyStore.deleteEntry(getInternalAlias(userId, uid, alias));
+ } catch (KeyStoreException e) {
+ throw new ServiceSpecificException(ERROR_SERVICE_INTERNAL_ERROR, e.getMessage());
+ }
+ }
+
+ /**
+ * Returns the alias in locksettins service's KeyStore namespace used for given application key.
+ *
+ * <p>These IDs look as follows:
+ * {@code com.security.recoverablekeystore/application/<userId>/<uid>/<alias>}
+ *
+ * @param userId The ID of the user
+ * @param uid The uid
+ * @param alias - alias in application's namespace
+ * @return The alias.
+ */
+ private String getInternalAlias(int userId, int uid, String alias) {
+ return APPLICATION_KEY_ALIAS_PREFIX + userId + "/" + uid + "/" + alias;
+ }
+}
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 502760a..fd435f9 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -771,7 +771,7 @@
* Called whenever packages change, the user switches, or the secure setting
* is altered. (For example in response to USER_SWITCHED in our broadcast receiver)
*/
- private void rebindServices(boolean forceRebind) {
+ protected void rebindServices(boolean forceRebind) {
if (DEBUG) Slog.d(TAG, "rebindServices");
final int[] userIds = mUserProfiles.getCurrentProfileIds();
final int nUserIds = userIds.length;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 727e7ee..b25124a 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2891,6 +2891,7 @@
// Backup/restore interface
@Override
public byte[] getBackupPayload(int user) {
+ checkCallerIsSystem();
if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
//TODO: http://b/22388012
if (user != UserHandle.USER_SYSTEM) {
@@ -2911,6 +2912,7 @@
@Override
public void applyRestore(byte[] payload, int user) {
+ checkCallerIsSystem();
if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
+ (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
if (payload == null) {
@@ -5687,6 +5689,12 @@
mListeners.unregisterService(removed.service, removed.userid);
}
+ @Override
+ public void onUserUnlocked(int user) {
+ if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user);
+ rebindServices(true);
+ }
+
public void onNotificationEnqueued(final NotificationRecord r) {
final StatusBarNotification sbn = r.sbn;
TrimCache trimCache = new TrimCache(sbn);
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index c3f20af..b79caca 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -290,13 +290,14 @@
int dexoptNeeded, @Nullable String outputPath, int dexFlags,
String compilerFilter, @Nullable String volumeUuid, @Nullable String sharedLibraries,
@Nullable String seInfo, boolean downgrade, int targetSdkVersion,
- @Nullable String profileName) throws InstallerException {
+ @Nullable String profileName, @Nullable String dexMetadataPath)
+ throws InstallerException {
assertValidInstructionSet(instructionSet);
if (!checkBeforeRemote()) return;
try {
mInstalld.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded, outputPath,
dexFlags, compilerFilter, volumeUuid, sharedLibraries, seInfo, downgrade,
- targetSdkVersion, profileName);
+ targetSdkVersion, profileName, dexMetadataPath);
} catch (Exception e) {
throw InstallerException.from(e);
}
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index 10e05cf..fc73142 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -261,12 +261,12 @@
String instructionSet, int dexoptNeeded, @Nullable String outputPath,
int dexFlags, String compilerFilter, @Nullable String volumeUuid,
@Nullable String sharedLibraries, @Nullable String seInfo, boolean downgrade,
- int targetSdkVersion, @Nullable String profileName)
- throws InstallerException {
+ int targetSdkVersion, @Nullable String profileName,
+ @Nullable String dexMetadataPath) throws InstallerException {
final StringBuilder builder = new StringBuilder();
- // The version. Right now it's 5.
- builder.append("5 ");
+ // The version. Right now it's 6.
+ builder.append("6 ");
builder.append("dexopt");
@@ -284,6 +284,7 @@
encodeParameter(builder, downgrade);
encodeParameter(builder, targetSdkVersion);
encodeParameter(builder, profileName);
+ encodeParameter(builder, dexMetadataPath);
commands.add(builder.toString());
}
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index cde8cb7..2c68e67 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -21,6 +21,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageParser;
import android.content.pm.dex.ArtManager;
+import android.content.pm.dex.DexMetadataHelper;
import android.os.FileUtils;
import android.os.PowerManager;
import android.os.SystemClock;
@@ -209,6 +210,13 @@
String profileName = ArtManager.getProfileName(i == 0 ? null : pkg.splitNames[i - 1]);
+ String dexMetadataPath = null;
+ if (options.isDexoptInstallWithDexMetadata()) {
+ File dexMetadataFile = DexMetadataHelper.findDexMetadataForFile(new File(path));
+ dexMetadataPath = dexMetadataFile == null
+ ? null : dexMetadataFile.getAbsolutePath();
+ }
+
final boolean isUsedByOtherApps = options.isDexoptAsSharedLibrary()
|| packageUseInfo.isUsedByOtherApps(path);
final String compilerFilter = getRealCompilerFilter(pkg.applicationInfo,
@@ -223,7 +231,7 @@
for (String dexCodeIsa : dexCodeInstructionSets) {
int newResult = dexOptPath(pkg, path, dexCodeIsa, compilerFilter,
profileUpdated, classLoaderContexts[i], dexoptFlags, sharedGid,
- packageStats, options.isDowngrade(), profileName);
+ packageStats, options.isDowngrade(), profileName, dexMetadataPath);
// The end result is:
// - FAILED if any path failed,
// - PERFORMED if at least one path needed compilation,
@@ -248,7 +256,7 @@
private int dexOptPath(PackageParser.Package pkg, String path, String isa,
String compilerFilter, boolean profileUpdated, String classLoaderContext,
int dexoptFlags, int uid, CompilerStats.PackageStats packageStats, boolean downgrade,
- String profileName) {
+ String profileName, String dexMetadataPath) {
int dexoptNeeded = getDexoptNeeded(path, isa, compilerFilter, classLoaderContext,
profileUpdated, downgrade);
if (Math.abs(dexoptNeeded) == DexFile.NO_DEXOPT_NEEDED) {
@@ -275,7 +283,7 @@
mInstaller.dexopt(path, uid, pkg.packageName, isa, dexoptNeeded, oatDir, dexoptFlags,
compilerFilter, pkg.volumeUuid, classLoaderContext, pkg.applicationInfo.seInfo,
false /* downgrade*/, pkg.applicationInfo.targetSdkVersion,
- profileName);
+ profileName, dexMetadataPath);
if (packageStats != null) {
long endTime = System.currentTimeMillis();
@@ -396,7 +404,8 @@
mInstaller.dexopt(path, info.uid, info.packageName, isa, /*dexoptNeeded*/ 0,
/*oatDir*/ null, dexoptFlags,
compilerFilter, info.volumeUuid, classLoaderContext, info.seInfoUser,
- options.isDowngrade(), info.targetSdkVersion, /*profileName*/ null);
+ options.isDowngrade(), info.targetSdkVersion, /*profileName*/ null,
+ /*dexMetadataPath*/ null);
}
return DEX_OPT_PERFORMED;
@@ -511,9 +520,13 @@
private int getDexFlags(ApplicationInfo info, String compilerFilter, DexoptOptions options) {
int flags = info.flags;
boolean debuggable = (flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
- // Profile guide compiled oat files should not be public.
+ // Profile guide compiled oat files should not be public unles they are based
+ // on profiles from dex metadata archives.
+ // The flag isDexoptInstallWithDexMetadata applies only on installs when we know that
+ // the user does not have an existing profile.
boolean isProfileGuidedFilter = isProfileGuidedCompilerFilter(compilerFilter);
- boolean isPublic = !info.isForwardLocked() && !isProfileGuidedFilter;
+ boolean isPublic = !info.isForwardLocked() &&
+ (!isProfileGuidedFilter || options.isDexoptInstallWithDexMetadata());
int profileFlag = isProfileGuidedFilter ? DEXOPT_PROFILE_GUIDED : 0;
// System apps are invoked with a runtime flag which exempts them from
// restrictions on hidden API usage. We dexopt with the same runtime flag
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index a6ff4f7..3dd5a34 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -77,6 +77,7 @@
import android.os.UserHandle;
import android.os.storage.StorageManager;
import android.system.ErrnoException;
+import android.system.Int64Ref;
import android.system.Os;
import android.system.OsConstants;
import android.system.StructStat;
@@ -575,14 +576,24 @@
@Override
public ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes) {
try {
- return openWriteInternal(name, offsetBytes, lengthBytes);
+ return doWriteInternal(name, offsetBytes, lengthBytes, null);
} catch (IOException e) {
throw ExceptionUtils.wrap(e);
}
}
- private ParcelFileDescriptor openWriteInternal(String name, long offsetBytes, long lengthBytes)
- throws IOException {
+ @Override
+ public void write(String name, long offsetBytes, long lengthBytes,
+ ParcelFileDescriptor fd) {
+ try {
+ doWriteInternal(name, offsetBytes, lengthBytes, fd);
+ } catch (IOException e) {
+ throw ExceptionUtils.wrap(e);
+ }
+ }
+
+ private ParcelFileDescriptor doWriteInternal(String name, long offsetBytes, long lengthBytes,
+ ParcelFileDescriptor incomingFd) throws IOException {
// Quick sanity check of state, and allocate a pipe for ourselves. We
// then do heavy disk allocation outside the lock, but this open pipe
// will block any attempted install transitions.
@@ -636,7 +647,44 @@
Os.lseek(targetFd, offsetBytes, OsConstants.SEEK_SET);
}
- if (PackageInstaller.ENABLE_REVOCABLE_FD) {
+ if (incomingFd != null) {
+ switch (Binder.getCallingUid()) {
+ case android.os.Process.SHELL_UID:
+ case android.os.Process.ROOT_UID:
+ break;
+ default:
+ throw new SecurityException("Reverse mode only supported from shell");
+ }
+
+ // In "reverse" mode, we're streaming data ourselves from the
+ // incoming FD, which means we never have to hand out our
+ // sensitive internal FD. We still rely on a "bridge" being
+ // inserted above to hold the session active.
+ try {
+ final Int64Ref last = new Int64Ref(0);
+ FileUtils.copy(incomingFd.getFileDescriptor(), targetFd, (long progress) -> {
+ if (params.sizeBytes > 0) {
+ final long delta = progress - last.value;
+ last.value = progress;
+ addClientProgress((float) delta / (float) params.sizeBytes);
+ }
+ }, null, lengthBytes);
+ } finally {
+ IoUtils.closeQuietly(targetFd);
+ IoUtils.closeQuietly(incomingFd);
+
+ // We're done here, so remove the "bridge" that was holding
+ // the session active.
+ synchronized (mLock) {
+ if (PackageInstaller.ENABLE_REVOCABLE_FD) {
+ mFds.remove(fd);
+ } else {
+ mBridges.remove(bridge);
+ }
+ }
+ }
+ return null;
+ } else if (PackageInstaller.ENABLE_REVOCABLE_FD) {
fd.init(mContext, targetFd);
return fd.getRevocableFileDescriptor();
} else {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 89fbd17..a0cb722 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -3840,10 +3840,6 @@
if (ps == null) {
return null;
}
- PackageParser.Package p = ps.pkg;
- if (p == null) {
- return null;
- }
final int callingUid = Binder.getCallingUid();
// Filter out ephemeral app metadata:
// * The system/shell/root can see metadata for any app
@@ -3855,32 +3851,58 @@
return null;
}
- final PermissionsState permissionsState = ps.getPermissionsState();
-
- // Compute GIDs only if requested
- final int[] gids = (flags & PackageManager.GET_GIDS) == 0
- ? EMPTY_INT_ARRAY : permissionsState.computeGids(userId);
- // Compute granted permissions only if package has requested permissions
- final Set<String> permissions = ArrayUtils.isEmpty(p.requestedPermissions)
- ? Collections.<String>emptySet() : permissionsState.getPermissions(userId);
- final PackageUserState state = ps.readUserState(userId);
-
if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0
&& ps.isSystem()) {
flags |= MATCH_ANY_USER;
}
- PackageInfo packageInfo = PackageParser.generatePackageInfo(p, gids, flags,
- ps.firstInstallTime, ps.lastUpdateTime, permissions, state, userId);
+ final PackageUserState state = ps.readUserState(userId);
+ PackageParser.Package p = ps.pkg;
+ if (p != null) {
+ final PermissionsState permissionsState = ps.getPermissionsState();
- if (packageInfo == null) {
+ // Compute GIDs only if requested
+ final int[] gids = (flags & PackageManager.GET_GIDS) == 0
+ ? EMPTY_INT_ARRAY : permissionsState.computeGids(userId);
+ // Compute granted permissions only if package has requested permissions
+ final Set<String> permissions = ArrayUtils.isEmpty(p.requestedPermissions)
+ ? Collections.<String>emptySet() : permissionsState.getPermissions(userId);
+
+ PackageInfo packageInfo = PackageParser.generatePackageInfo(p, gids, flags,
+ ps.firstInstallTime, ps.lastUpdateTime, permissions, state, userId);
+
+ if (packageInfo == null) {
+ return null;
+ }
+
+ packageInfo.packageName = packageInfo.applicationInfo.packageName =
+ resolveExternalPackageNameLPr(p);
+
+ return packageInfo;
+ } else if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0 && state.isAvailable(flags)) {
+ PackageInfo pi = new PackageInfo();
+ pi.packageName = ps.name;
+ pi.setLongVersionCode(ps.versionCode);
+ pi.sharedUserId = (ps.sharedUser != null) ? ps.sharedUser.name : null;
+ pi.firstInstallTime = ps.firstInstallTime;
+ pi.lastUpdateTime = ps.lastUpdateTime;
+
+ ApplicationInfo ai = new ApplicationInfo();
+ ai.packageName = ps.name;
+ ai.uid = UserHandle.getUid(userId, ps.appId);
+ ai.primaryCpuAbi = ps.primaryCpuAbiString;
+ ai.secondaryCpuAbi = ps.secondaryCpuAbiString;
+ ai.versionCode = ps.versionCode;
+ ai.flags = ps.pkgFlags;
+ ai.privateFlags = ps.pkgPrivateFlags;
+ pi.applicationInfo = PackageParser.generateApplicationInfo(ai, flags, state, userId);
+
+ if (DEBUG_PACKAGE_INFO) Log.v(TAG, "ps.pkg is n/a for ["
+ + ps.name + "]. Provides a minimum info.");
+ return pi;
+ } else {
return null;
}
-
- packageInfo.packageName = packageInfo.applicationInfo.packageName =
- resolveExternalPackageNameLPr(p);
-
- return packageInfo;
}
@Override
@@ -17309,7 +17331,8 @@
// Also, don't fail application installs if the dexopt step fails.
DexoptOptions dexoptOptions = new DexoptOptions(pkg.packageName,
REASON_INSTALL,
- DexoptOptions.DEXOPT_BOOT_COMPLETE);
+ DexoptOptions.DEXOPT_BOOT_COMPLETE |
+ DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE);
mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles,
null /* instructionSets */,
getOrCreateCompilerPackageStats(pkg),
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 686c4a5..758c9d5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -16,6 +16,12 @@
package com.android.server.pm;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
+
import android.accounts.IAccountManager;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
@@ -32,8 +38,10 @@
import android.content.pm.InstrumentationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
+import android.content.pm.PackageInstaller.SessionParams;
import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageParser;
import android.content.pm.PackageParser.ApkLite;
import android.content.pm.PackageParser.PackageLite;
@@ -41,9 +49,6 @@
import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
-import android.content.pm.PackageInstaller.SessionInfo;
-import android.content.pm.PackageInstaller.SessionParams;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.content.pm.VersionedPackage;
@@ -73,7 +78,6 @@
import com.android.internal.content.PackageHelper;
import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.SizedInputStream;
import com.android.server.LocalServices;
import com.android.server.SystemConfig;
@@ -81,9 +85,8 @@
import libcore.io.IoUtils;
+import java.io.FileDescriptor;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.URISyntaxException;
import java.util.ArrayList;
@@ -95,12 +98,6 @@
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
-import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
-import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK;
-import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
-import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
-import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
-
class PackageManagerShellCommand extends ShellCommand {
/** Path for streaming APK content */
private static final String STDIN_PATH = "-";
@@ -2213,7 +2210,7 @@
final PrintWriter pw = getOutPrintWriter();
final ParcelFileDescriptor fd;
if (STDIN_PATH.equals(inPath)) {
- fd = null;
+ fd = new ParcelFileDescriptor(getInFileDescriptor());
} else if (inPath != null) {
fd = openFileForSystem(inPath, "r");
if (fd == null) {
@@ -2225,53 +2222,27 @@
return -1;
}
} else {
- fd = null;
+ fd = new ParcelFileDescriptor(getInFileDescriptor());
}
if (sizeBytes <= 0) {
getErrPrintWriter().println("Error: must specify a APK size");
return 1;
}
- final SessionInfo info = mInterface.getPackageInstaller().getSessionInfo(sessionId);
-
PackageInstaller.Session session = null;
- InputStream in = null;
- OutputStream out = null;
try {
session = new PackageInstaller.Session(
mInterface.getPackageInstaller().openSession(sessionId));
-
- if (fd != null) {
- in = new ParcelFileDescriptor.AutoCloseInputStream(fd);
- } else {
- in = new SizedInputStream(getRawInputStream(), sizeBytes);
- }
- out = session.openWrite(splitName, 0, sizeBytes);
-
- int total = 0;
- byte[] buffer = new byte[1024 * 1024];
- int c;
- while ((c = in.read(buffer)) != -1) {
- total += c;
- out.write(buffer, 0, c);
-
- if (info.sizeBytes > 0) {
- final float fraction = ((float) c / (float) info.sizeBytes);
- session.addProgress(fraction);
- }
- }
- session.fsync(out);
+ session.write(splitName, 0, sizeBytes, fd);
if (logSuccess) {
- pw.println("Success: streamed " + total + " bytes");
+ pw.println("Success: streamed " + sizeBytes + " bytes");
}
return 0;
} catch (IOException e) {
getErrPrintWriter().println("Error: failed to write; " + e.getMessage());
return 1;
} finally {
- IoUtils.closeQuietly(out);
- IoUtils.closeQuietly(in);
IoUtils.closeQuietly(session);
}
}
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index ebf6672..e4c74ed 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -703,7 +703,7 @@
*/
public boolean rescanPackageIfNeeded(boolean isNewApp, boolean forceRescan) {
final ShortcutService s = mShortcutUser.mService;
- final long start = s.injectElapsedRealtime();
+ final long start = s.getStatStartTime();
final PackageInfo pi;
try {
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index d2bc6d2..a85d6d8 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -99,6 +99,7 @@
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.Preconditions;
import com.android.server.LocalServices;
+import com.android.server.StatLogger;
import com.android.server.SystemService;
import com.android.server.pm.ShortcutUser.PackageWithUser;
@@ -367,7 +368,7 @@
int COUNT = GET_DEFAULT_LAUNCHER + 1;
}
- private static final String[] STAT_LABELS = {
+ private final StatLogger mStatLogger = new StatLogger(new String[] {
"getHomeActivities()",
"Launcher permission check",
"getPackageInfo()",
@@ -385,15 +386,7 @@
"packageUpdateCheck",
"asyncPreloadUserDelay",
"getDefaultLauncher()"
- };
-
- final Object mStatLock = new Object();
-
- @GuardedBy("mStatLock")
- private final int[] mCountStats = new int[Stats.COUNT];
-
- @GuardedBy("mStatLock")
- private final long[] mDurationStats = new long[Stats.COUNT];
+ });
private static final int PROCESS_STATE_FOREGROUND_THRESHOLD =
ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
@@ -480,11 +473,12 @@
| ActivityManager.UID_OBSERVER_GONE);
}
+ long getStatStartTime() {
+ return mStatLogger.getTime();
+ }
+
void logDurationStat(int statId, long start) {
- synchronized (mStatLock) {
- mCountStats[statId]++;
- mDurationStats[statId] += (injectElapsedRealtime() - start);
- }
+ mStatLogger.logDurationStat(statId, start);
}
public String injectGetLocaleTagsForUser(@UserIdInt int userId) {
@@ -621,7 +615,7 @@
// late since the launcher would already have started.
// So we just create a new thread. This code runs rarely, so we don't use a thread pool
// or anything.
- final long start = injectElapsedRealtime();
+ final long start = getStatStartTime();
injectRunOnNewThread(() -> {
synchronized (mLock) {
logDurationStat(Stats.ASYNC_PRELOAD_USER_DELAY, start);
@@ -1289,7 +1283,7 @@
if (DEBUG) {
Slog.d(TAG, "cleanupDanglingBitmaps: userId=" + userId);
}
- final long start = injectElapsedRealtime();
+ final long start = getStatStartTime();
final ShortcutUser user = getUserShortcutsLocked(userId);
@@ -1485,7 +1479,7 @@
final Resources publisherRes = injectGetResourcesForApplicationAsUser(
si.getPackage(), si.getUserId());
if (publisherRes != null) {
- final long start = injectElapsedRealtime();
+ final long start = getStatStartTime();
try {
si.lookupAndFillInResourceNames(publisherRes);
} finally {
@@ -2264,7 +2258,7 @@
if (canSeeAnyPinnedShortcut(callingPackage, userId, callingPid, callingUid)) {
return true;
}
- final long start = injectElapsedRealtime();
+ final long start = getStatStartTime();
try {
return hasShortcutHostPermissionInner(callingPackage, userId);
} finally {
@@ -2327,7 +2321,7 @@
@Nullable
ComponentName getDefaultLauncher(@UserIdInt int userId) {
- final long start = injectElapsedRealtime();
+ final long start = getStatStartTime();
final long token = injectClearCallingIdentity();
try {
synchronized (mLock) {
@@ -2338,7 +2332,7 @@
final List<ResolveInfo> allHomeCandidates = new ArrayList<>();
// Default launcher from package manager.
- final long startGetHomeActivitiesAsUser = injectElapsedRealtime();
+ final long startGetHomeActivitiesAsUser = getStatStartTime();
final ComponentName defaultLauncher = mPackageManagerInternal
.getHomeActivitiesAsUser(allHomeCandidates, userId);
logDurationStat(Stats.GET_DEFAULT_HOME, startGetHomeActivitiesAsUser);
@@ -2910,7 +2904,7 @@
return;
}
- final long start = injectElapsedRealtime();
+ final long start = getStatStartTime();
try {
final ArrayList<PackageWithUser> gonePackages = new ArrayList<>();
@@ -3087,7 +3081,7 @@
@VisibleForTesting
PackageInfo injectPackageInfoWithUninstalled(String packageName, @UserIdInt int userId,
boolean getSignatures) {
- final long start = injectElapsedRealtime();
+ final long start = getStatStartTime();
final long token = injectClearCallingIdentity();
try {
return mIPackageManager.getPackageInfo(
@@ -3122,7 +3116,7 @@
@VisibleForTesting
ApplicationInfo injectApplicationInfoWithUninstalled(
String packageName, @UserIdInt int userId) {
- final long start = injectElapsedRealtime();
+ final long start = getStatStartTime();
final long token = injectClearCallingIdentity();
try {
return mIPackageManager.getApplicationInfo(packageName, PACKAGE_MATCH_FLAGS, userId);
@@ -3153,7 +3147,7 @@
@VisibleForTesting
ActivityInfo injectGetActivityInfoWithMetadataWithUninstalled(
ComponentName activity, @UserIdInt int userId) {
- final long start = injectElapsedRealtime();
+ final long start = getStatStartTime();
final long token = injectClearCallingIdentity();
try {
return mIPackageManager.getActivityInfo(activity,
@@ -3175,7 +3169,7 @@
@NonNull
@VisibleForTesting
final List<PackageInfo> getInstalledPackages(@UserIdInt int userId) {
- final long start = injectElapsedRealtime();
+ final long start = getStatStartTime();
final long token = injectClearCallingIdentity();
try {
final List<PackageInfo> all = injectGetPackagesWithUninstalled(userId);
@@ -3280,7 +3274,7 @@
@Nullable
Resources injectGetResourcesForApplicationAsUser(String packageName, int userId) {
- final long start = injectElapsedRealtime();
+ final long start = getStatStartTime();
final long token = injectClearCallingIdentity();
try {
return mContext.getPackageManager().getResourcesForApplicationAsUser(
@@ -3348,7 +3342,7 @@
*/
@Nullable
ComponentName injectGetDefaultMainActivity(@NonNull String packageName, int userId) {
- final long start = injectElapsedRealtime();
+ final long start = getStatStartTime();
try {
final List<ResolveInfo> resolved =
queryActivities(getMainActivityIntent(), packageName, null, userId);
@@ -3362,7 +3356,7 @@
* Return whether an activity is enabled, exported and main.
*/
boolean injectIsMainActivity(@NonNull ComponentName activity, int userId) {
- final long start = injectElapsedRealtime();
+ final long start = getStatStartTime();
try {
if (activity == null) {
wtf("null activity detected");
@@ -3397,7 +3391,7 @@
*/
@NonNull
List<ResolveInfo> injectGetMainActivities(@NonNull String packageName, int userId) {
- final long start = injectElapsedRealtime();
+ final long start = getStatStartTime();
try {
return queryActivities(getMainActivityIntent(), packageName, null, userId);
} finally {
@@ -3411,7 +3405,7 @@
@VisibleForTesting
boolean injectIsActivityEnabledAndExported(
@NonNull ComponentName activity, @UserIdInt int userId) {
- final long start = injectElapsedRealtime();
+ final long start = getStatStartTime();
try {
return queryActivities(new Intent(), activity.getPackageName(), activity, userId)
.size() > 0;
@@ -3831,12 +3825,7 @@
pw.println(mMaxShortcuts);
pw.println();
- pw.println(" Stats:");
- synchronized (mStatLock) {
- for (int i = 0; i < Stats.COUNT; i++) {
- dumpStatLS(pw, " ", i);
- }
- }
+ mStatLogger.dump(pw, " ");
pw.println();
pw.print(" #Failures: ");
@@ -3902,15 +3891,6 @@
pw.print(formatTime(injectCurrentTimeMillis()));
}
- private void dumpStatLS(PrintWriter pw, String prefix, int statId) {
- pw.print(prefix);
- final int count = mCountStats[statId];
- final long dur = mDurationStats[statId];
- pw.println(String.format("%s: count=%d, total=%dms, avg=%.1fms",
- STAT_LABELS[statId], count, dur,
- (count == 0 ? 0 : ((double) dur) / count)));
- }
-
/**
* Dumpsys for checkin.
*
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 92fd904..b53d83b 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -88,6 +88,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IAppOpsService;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.os.BackgroundThread;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.Preconditions;
@@ -387,7 +388,9 @@
}
final IntentSender target = intent.getParcelableExtra(Intent.EXTRA_INTENT);
final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_ID, UserHandle.USER_NULL);
- setQuietModeEnabled(userHandle, false, target);
+ // Call setQuietModeEnabled on bg thread to avoid ANR
+ BackgroundThread.getHandler()
+ .post(() -> setQuietModeEnabled(userHandle, false, target));
}
};
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index a42fcbd..842f8d0 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -117,7 +117,7 @@
UserManager.DISALLOW_AUTOFILL,
UserManager.DISALLOW_USER_SWITCH,
UserManager.DISALLOW_UNIFIED_PASSWORD,
- UserManager.DISALLOW_CONFIG_LOCATION_MODE,
+ UserManager.DISALLOW_CONFIG_LOCATION,
UserManager.DISALLOW_AIRPLANE_MODE,
UserManager.DISALLOW_CONFIG_BRIGHTNESS,
UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE,
diff --git a/services/core/java/com/android/server/pm/dex/DexoptOptions.java b/services/core/java/com/android/server/pm/dex/DexoptOptions.java
index 0966770..d4f95cb 100644
--- a/services/core/java/com/android/server/pm/dex/DexoptOptions.java
+++ b/services/core/java/com/android/server/pm/dex/DexoptOptions.java
@@ -59,6 +59,10 @@
// When set, indicates that dexopt is invoked from the background service.
public static final int DEXOPT_IDLE_BACKGROUND_JOB = 1 << 9;
+ // When set, indicates that dexopt is invoked from the install time flow and
+ // should get the dex metdata file if present.
+ public static final int DEXOPT_INSTALL_WITH_DEX_METADATA_FILE = 1 << 10;
+
// The name of package to optimize.
private final String mPackageName;
@@ -90,7 +94,8 @@
DEXOPT_ONLY_SHARED_DEX |
DEXOPT_DOWNGRADE |
DEXOPT_AS_SHARED_LIBRARY |
- DEXOPT_IDLE_BACKGROUND_JOB;
+ DEXOPT_IDLE_BACKGROUND_JOB |
+ DEXOPT_INSTALL_WITH_DEX_METADATA_FILE;
if ((flags & (~validityMask)) != 0) {
throw new IllegalArgumentException("Invalid flags : " + Integer.toHexString(flags));
}
@@ -141,6 +146,10 @@
return (mFlags & DEXOPT_IDLE_BACKGROUND_JOB) != 0;
}
+ public boolean isDexoptInstallWithDexMetadata() {
+ return (mFlags & DEXOPT_INSTALL_WITH_DEX_METADATA_FILE) != 0;
+ }
+
public String getSplitName() {
return mSplitName;
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 0502848..177d6af 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -5603,9 +5603,7 @@
final int fl = PolicyControl.getWindowFlags(null,
mTopFullscreenOpaqueWindowState.getAttrs());
if (localLOGV) {
- Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw()
- + " shown position: "
- + mTopFullscreenOpaqueWindowState.getShownPositionLw());
+ Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw());
Slog.d(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs()
+ " lp.flags=0x" + Integer.toHexString(fl));
}
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index e9c4c5c..3af3fcb 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -232,14 +232,6 @@
public Rect getFrameLw();
/**
- * Retrieve the current position of the window that is actually shown.
- * Must be called with the window manager lock held.
- *
- * @return Point The point holding the shown window position.
- */
- public Point getShownPositionLw();
-
- /**
* Retrieve the frame of the display that this window was last
* laid out in. Must be called with the
* window manager lock held.
diff --git a/services/core/java/com/android/server/slice/SliceFullAccessList.java b/services/core/java/com/android/server/slice/SliceFullAccessList.java
index 5e0cd03..6f5afa2 100644
--- a/services/core/java/com/android/server/slice/SliceFullAccessList.java
+++ b/services/core/java/com/android/server/slice/SliceFullAccessList.java
@@ -16,9 +16,9 @@
import android.content.Context;
import android.content.pm.UserInfo;
+import android.os.UserHandle;
import android.os.UserManager;
import android.util.ArraySet;
-import android.util.Log;
import android.util.SparseArray;
import com.android.internal.util.XmlUtils;
@@ -72,7 +72,7 @@
pkgs.remove(pkg);
}
- public void writeXml(XmlSerializer out) throws IOException {
+ public void writeXml(XmlSerializer out, int user) throws IOException {
out.startTag(null, TAG_LIST);
out.attribute(null, ATT_VERSION, String.valueOf(DB_VERSION));
@@ -80,6 +80,9 @@
for (int i = 0 ; i < N; i++) {
final int userId = mFullAccessPkgs.keyAt(i);
final ArraySet<String> pkgs = mFullAccessPkgs.valueAt(i);
+ if (user != UserHandle.USER_ALL && user != userId) {
+ continue;
+ }
out.startTag(null, TAG_USER);
out.attribute(null, ATT_USER_ID, Integer.toString(userId));
if (pkgs != null) {
@@ -88,7 +91,6 @@
out.startTag(null, TAG_PKG);
out.text(pkgs.valueAt(j));
out.endTag(null, TAG_PKG);
-
}
}
out.endTag(null, TAG_USER);
diff --git a/services/core/java/com/android/server/slice/SliceManagerService.java b/services/core/java/com/android/server/slice/SliceManagerService.java
index c4871df..a1def44 100644
--- a/services/core/java/com/android/server/slice/SliceManagerService.java
+++ b/services/core/java/com/android/server/slice/SliceManagerService.java
@@ -21,6 +21,7 @@
import static android.content.ContentProvider.maybeAddUserId;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.os.Process.SYSTEM_UID;
import android.Manifest.permission;
import android.app.ActivityManager;
@@ -68,8 +69,9 @@
import org.xmlpull.v1.XmlPullParserFactory;
import org.xmlpull.v1.XmlSerializer;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
import java.io.File;
-import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -93,6 +95,7 @@
private final ArraySet<SliceGrant> mUserGrants = new ArraySet<>();
private final Handler mHandler;
private final ContentObserver mObserver;
+ @GuardedBy("mSliceAccessFile")
private final AtomicFile mSliceAccessFile;
@GuardedBy("mAccessList")
private final SliceFullAccessList mAccessList;
@@ -257,6 +260,63 @@
}
}
+ // Backup/restore interface
+ @Override
+ public byte[] getBackupPayload(int user) {
+ if (Binder.getCallingUid() != SYSTEM_UID) {
+ throw new SecurityException("Caller must be system");
+ }
+ //TODO: http://b/22388012
+ if (user != UserHandle.USER_SYSTEM) {
+ Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
+ return null;
+ }
+ synchronized(mSliceAccessFile) {
+ final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try {
+ XmlSerializer out = XmlPullParserFactory.newInstance().newSerializer();
+ out.setOutput(baos, Encoding.UTF_8.name());
+ synchronized (mAccessList) {
+ mAccessList.writeXml(out, user);
+ }
+ out.flush();
+ return baos.toByteArray();
+ } catch (IOException | XmlPullParserException e) {
+ Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public void applyRestore(byte[] payload, int user) {
+ if (Binder.getCallingUid() != SYSTEM_UID) {
+ throw new SecurityException("Caller must be system");
+ }
+ if (payload == null) {
+ Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
+ return;
+ }
+ //TODO: http://b/22388012
+ if (user != UserHandle.USER_SYSTEM) {
+ Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
+ return;
+ }
+ synchronized(mSliceAccessFile) {
+ final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
+ try {
+ XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
+ parser.setInput(bais, Encoding.UTF_8.name());
+ synchronized (mAccessList) {
+ mAccessList.readXml(parser);
+ }
+ mHandler.post(mSaveAccessList);
+ } catch (NumberFormatException | XmlPullParserException | IOException e) {
+ Slog.w(TAG, "applyRestore: error reading payload", e);
+ }
+ }
+ }
+
/// ----- internal code -----
private void removeFullAccess(String pkg, int userId) {
synchronized (mAccessList) {
@@ -492,7 +552,7 @@
XmlSerializer out = XmlPullParserFactory.newInstance().newSerializer();
out.setOutput(stream, Encoding.UTF_8.name());
synchronized (mAccessList) {
- mAccessList.writeXml(out);
+ mAccessList.writeXml(out, UserHandle.USER_ALL);
}
out.flush();
mSliceAccessFile.finishWrite(stream);
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index adb368b..7c170ae 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -56,7 +56,6 @@
import java.util.ArrayList;
import java.util.List;
-
/**
* A note on locking: We rely on the fact that calls onto mBar are oneway or
* if they are local, that they just enqueue messages to not deadlock.
@@ -525,6 +524,26 @@
}
@Override
+ public void showPinningEnterExitToast(boolean entering) throws RemoteException {
+ if (mBar != null) {
+ try {
+ mBar.showPinningEnterExitToast(entering);
+ } catch (RemoteException ex) {
+ }
+ }
+ }
+
+ @Override
+ public void showPinningEscapeToast() throws RemoteException {
+ if (mBar != null) {
+ try {
+ mBar.showPinningEscapeToast();
+ } catch (RemoteException ex) {
+ }
+ }
+ }
+
+ @Override
public void showFingerprintDialog(Bundle bundle, IFingerprintDialogReceiver receiver) {
if (mBar != null) {
try {
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index f09a294..2c3c5d2 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -55,6 +55,7 @@
import android.view.SurfaceSession;
import android.view.WindowManager;
+import com.android.internal.os.logging.MetricsLoggerWrapper;
import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethodClient;
import com.android.internal.view.IInputMethodManager;
@@ -508,8 +509,14 @@
// on-going notification for the user to control their visibility.
if (visible) {
changed = mAlertWindowSurfaces.add(surfaceController);
+ if (changed) {
+ MetricsLoggerWrapper.logAppOverlayEnter(mUid, mPackageName, true);
+ }
} else {
changed = mAlertWindowSurfaces.remove(surfaceController);
+ if (changed) {
+ MetricsLoggerWrapper.logAppOverlayExit(mUid, mPackageName, true);
+ }
}
if (changed) {
@@ -530,8 +537,14 @@
if (visible) {
changed = mAppOverlaySurfaces.add(surfaceController);
+ if (changed) {
+ MetricsLoggerWrapper.logAppOverlayEnter(mUid, mPackageName, false);
+ }
} else {
changed = mAppOverlaySurfaces.remove(surfaceController);
+ if (changed) {
+ MetricsLoggerWrapper.logAppOverlayExit(mUid, mPackageName, false);
+ }
}
if (changed) {
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 212a0d70..a7a2b53 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -27,6 +27,7 @@
import android.app.ActivityManager.TaskSnapshot;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
+import android.graphics.Color;
import android.graphics.GraphicBuffer;
import android.graphics.Rect;
import android.os.Environment;
@@ -40,6 +41,7 @@
import android.view.WindowManager.LayoutParams;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.graphics.ColorUtils;
import com.android.server.policy.WindowManagerPolicy.ScreenOffListener;
import com.android.server.policy.WindowManagerPolicy.StartingSurface;
import com.android.server.wm.TaskSnapshotSurface.SystemBarBackgroundPainter;
@@ -324,7 +326,8 @@
if (mainWindow == null) {
return null;
}
- final int color = task.getTaskDescription().getBackgroundColor();
+ final int color = ColorUtils.setAlphaComponent(
+ task.getTaskDescription().getBackgroundColor(), 255);
final int statusBarColor = task.getTaskDescription().getStatusBarColor();
final int navigationBarColor = task.getTaskDescription().getNavigationBarColor();
final LayoutParams attrs = mainWindow.getAttrs();
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index 259f8df..e4db3b0 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -47,6 +47,7 @@
import android.app.ActivityThread;
import android.content.Context;
import android.graphics.Canvas;
+import android.graphics.Color;
import android.graphics.GraphicBuffer;
import android.graphics.Paint;
import android.graphics.Rect;
@@ -516,7 +517,7 @@
@VisibleForTesting
void drawStatusBarBackground(Canvas c, @Nullable Rect alreadyDrawnFrame,
int statusBarHeight) {
- if (statusBarHeight > 0
+ if (statusBarHeight > 0 && Color.alpha(mStatusBarColor) != 0
&& (alreadyDrawnFrame == null || c.getWidth() > alreadyDrawnFrame.right)) {
final int rightInset = DecorView.getColorViewRightInset(mStableInsets.right,
mContentInsets.right);
@@ -531,7 +532,7 @@
getNavigationBarRect(c.getWidth(), c.getHeight(), mStableInsets, mContentInsets,
navigationBarRect);
final boolean visible = isNavigationBarColorViewVisible();
- if (visible && !navigationBarRect.isEmpty()) {
+ if (visible && Color.alpha(mNavigationBarColor) != 0 && !navigationBarRect.isEmpty()) {
c.drawRect(navigationBarRect, mNavigationBarPaint);
}
}
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index f2ad6fb..da3a035 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -272,6 +272,8 @@
}
boolean updateWallpaperOffset(WindowState wallpaperWin, int dw, int dh, boolean sync) {
+ int xOffset = 0;
+ int yOffset = 0;
boolean rawChanged = false;
// Set the default wallpaper x-offset to either edge of the screen (depending on RTL), to
// match the behavior of most Launchers
@@ -283,11 +285,8 @@
if (mLastWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
offset += mLastWallpaperDisplayOffsetX;
}
- boolean changed = wallpaperWin.mXOffset != offset;
- if (changed) {
- if (DEBUG_WALLPAPER) Slog.v(TAG, "Update wallpaper " + wallpaperWin + " x: " + offset);
- wallpaperWin.mXOffset = offset;
- }
+ xOffset = offset;
+
if (wallpaperWin.mWallpaperX != wpx || wallpaperWin.mWallpaperXStep != wpxs) {
wallpaperWin.mWallpaperX = wpx;
wallpaperWin.mWallpaperXStep = wpxs;
@@ -301,17 +300,16 @@
if (mLastWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
offset += mLastWallpaperDisplayOffsetY;
}
- if (wallpaperWin.mYOffset != offset) {
- if (DEBUG_WALLPAPER) Slog.v(TAG, "Update wallpaper " + wallpaperWin + " y: " + offset);
- changed = true;
- wallpaperWin.mYOffset = offset;
- }
+ yOffset = offset;
+
if (wallpaperWin.mWallpaperY != wpy || wallpaperWin.mWallpaperYStep != wpys) {
wallpaperWin.mWallpaperY = wpy;
wallpaperWin.mWallpaperYStep = wpys;
rawChanged = true;
}
+ boolean changed = wallpaperWin.mWinAnimator.setWallpaperOffset(xOffset, yOffset);
+
if (rawChanged && (wallpaperWin.mAttrs.privateFlags &
WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS) != 0) {
try {
diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
index 2ae5c7b..ddda027 100644
--- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java
+++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
@@ -74,10 +74,6 @@
for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
final WindowState wallpaper = mChildren.get(wallpaperNdx);
if (wallpaperController.updateWallpaperOffset(wallpaper, dw, dh, sync)) {
- final WindowStateAnimator winAnimator = wallpaper.mWinAnimator;
- winAnimator.computeShownFrameLocked();
- // No need to lay out the windows - we can just set the wallpaper position directly.
- winAnimator.setWallpaperOffset(wallpaper.mShownPosition);
// We only want to be synchronous with one wallpaper.
sync = false;
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index a9f2e03..3bee1e8 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -137,7 +137,6 @@
import static com.android.server.wm.proto.WindowStateProto.REMOVE_ON_EXIT;
import static com.android.server.wm.proto.WindowStateProto.REQUESTED_HEIGHT;
import static com.android.server.wm.proto.WindowStateProto.REQUESTED_WIDTH;
-import static com.android.server.wm.proto.WindowStateProto.SHOWN_POSITION;
import static com.android.server.wm.proto.WindowStateProto.STABLE_INSETS;
import static com.android.server.wm.proto.WindowStateProto.STACK_ID;
import static com.android.server.wm.proto.WindowStateProto.SURFACE_INSETS;
@@ -297,12 +296,6 @@
private final MergedConfiguration mLastReportedConfiguration = new MergedConfiguration();
/**
- * Actual position of the surface shown on-screen (may be modified by animation). These are
- * in the screen's coordinate space (WITH the compatibility scale applied).
- */
- final Point mShownPosition = new Point();
-
- /**
* Insets that determine the actually visible area. These are in the application's
* coordinate space (without compatibility scale applied).
*/
@@ -461,10 +454,6 @@
int mWallpaperDisplayOffsetX = Integer.MIN_VALUE;
int mWallpaperDisplayOffsetY = Integer.MIN_VALUE;
- // Wallpaper windows: pixels offset based on above variables.
- int mXOffset;
- int mYOffset;
-
/**
* This is set after IWindowSession.relayout() has been called at
* least once for the window. It allows us to detect the situation
@@ -745,8 +734,6 @@
mRequestedHeight = 0;
mLastRequestedWidth = 0;
mLastRequestedHeight = 0;
- mXOffset = 0;
- mYOffset = 0;
mLayer = 0;
mInputWindowHandle = new InputWindowHandle(
mAppToken != null ? mAppToken.mInputApplicationHandle : null, this, c,
@@ -1112,11 +1099,6 @@
}
@Override
- public Point getShownPositionLw() {
- return mShownPosition;
- }
-
- @Override
public Rect getDisplayFrameLw() {
return mDisplayFrame;
}
@@ -3134,7 +3116,6 @@
mContentInsets.writeToProto(proto, CONTENT_INSETS);
mAttrs.surfaceInsets.writeToProto(proto, SURFACE_INSETS);
mSurfacePosition.writeToProto(proto, SURFACE_POSITION);
- mShownPosition.writeToProto(proto, SHOWN_POSITION);
mWinAnimator.writeToProto(proto, ANIMATOR);
proto.write(ANIMATING_EXIT, mAnimatingExit);
for (int i = 0; i < mChildren.size(); i++) {
@@ -3250,10 +3231,6 @@
pw.print(prefix); pw.print("mRelayoutCalled="); pw.print(mRelayoutCalled);
pw.print(" mLayoutNeeded="); pw.println(mLayoutNeeded);
}
- if (mXOffset != 0 || mYOffset != 0) {
- pw.print(prefix); pw.print("Offsets x="); pw.print(mXOffset);
- pw.print(" y="); pw.println(mYOffset);
- }
if (dumpAll) {
pw.print(prefix); pw.print("mGivenContentInsets=");
mGivenContentInsets.printShortString(pw);
@@ -3272,7 +3249,6 @@
pw.println(getLastReportedConfiguration());
}
pw.print(prefix); pw.print("mHasSurface="); pw.print(mHasSurface);
- pw.print(" mShownPosition="); mShownPosition.printShortString(pw);
pw.print(" isReadyForDisplay()="); pw.print(isReadyForDisplay());
pw.print(" mWindowRemovalAllowed="); pw.println(mWindowRemovalAllowed);
if (dumpAll) {
@@ -4195,9 +4171,8 @@
final int width = mFrame.width();
final int height = mFrame.height();
- // Compute the offset of the window in relation to the decor rect.
- final int left = mXOffset + mFrame.left;
- final int top = mYOffset + mFrame.top;
+ final int left = mFrame.left;
+ final int top = mFrame.top;
// Initialize the decor rect to the entire frame.
if (isDockedResizing()) {
@@ -4392,8 +4367,8 @@
float9[Matrix.MSKEW_Y] = mWinAnimator.mDtDx;
float9[Matrix.MSKEW_X] = mWinAnimator.mDtDy;
float9[Matrix.MSCALE_Y] = mWinAnimator.mDsDy;
- int x = mSurfacePosition.x + mShownPosition.x;
- int y = mSurfacePosition.y + mShownPosition.y;
+ int x = mSurfacePosition.x;
+ int y = mSurfacePosition.y;
// If changed, also adjust transformFrameToSurfacePosition
final WindowContainer parent = getParent();
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 5c9cfbb..499322c 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -209,6 +209,12 @@
float mExtraHScale = (float) 1.0;
float mExtraVScale = (float) 1.0;
+ // An offset in pixel of the surface contents from the window position. Used for Wallpaper
+ // to provide the effect of scrolling within a large surface. We just use these values as
+ // a cache.
+ int mXOffset = 0;
+ int mYOffset = 0;
+
private final Rect mTmpSize = new Rect();
WindowStateAnimator(final WindowState win) {
@@ -436,7 +442,7 @@
flags |= SurfaceControl.SECURE;
}
- mTmpSize.set(w.mFrame.left + w.mXOffset, w.mFrame.top + w.mYOffset, 0, 0);
+ mTmpSize.set(0, 0, 0, 0);
calculateSurfaceBounds(w, attrs);
final int width = mTmpSize.width();
final int height = mTmpSize.height();
@@ -677,8 +683,8 @@
// WindowState.prepareSurfaces expands for surface insets (in order they don't get
// clipped by the WindowState surface), so we need to go into the other direction here.
- tmpMatrix.postTranslate(mWin.mXOffset + mWin.mAttrs.surfaceInsets.left,
- mWin.mYOffset + mWin.mAttrs.surfaceInsets.top);
+ tmpMatrix.postTranslate(mWin.mAttrs.surfaceInsets.left,
+ mWin.mAttrs.surfaceInsets.top);
// "convert" it into SurfaceFlinger's format
@@ -693,9 +699,6 @@
mDtDx = tmpFloats[Matrix.MSKEW_Y];
mDtDy = tmpFloats[Matrix.MSKEW_X];
mDsDy = tmpFloats[Matrix.MSCALE_Y];
- float x = tmpFloats[Matrix.MTRANS_X];
- float y = tmpFloats[Matrix.MTRANS_Y];
- mWin.mShownPosition.set(Math.round(x), Math.round(y));
// Now set the alpha... but because our current hardware
// can't do alpha transformation on a non-opaque surface,
@@ -705,8 +708,7 @@
mShownAlpha = mAlpha;
if (!mService.mLimitedAlphaCompositing
|| (!PixelFormat.formatHasAlpha(mWin.mAttrs.format)
- || (mWin.isIdentityMatrix(mDsDx, mDtDx, mDtDy, mDsDy)
- && x == frame.left && y == frame.top))) {
+ || (mWin.isIdentityMatrix(mDsDx, mDtDx, mDtDy, mDsDy)))) {
//Slog.i(TAG_WM, "Applying alpha transform");
if (screenAnimation) {
mShownAlpha *= screenRotationAnimation.getEnterTransformation().getAlpha();
@@ -736,10 +738,6 @@
TAG, "computeShownFrameLocked: " + this +
" not attached, mAlpha=" + mAlpha);
- // WindowState.prepareSurfaces expands for surface insets (in order they don't get
- // clipped by the WindowState surface), so we need to go into the other direction here.
- mWin.mShownPosition.set(mWin.mXOffset + mWin.mAttrs.surfaceInsets.left,
- mWin.mYOffset + mWin.mAttrs.surfaceInsets.top);
mShownAlpha = mAlpha;
mHaveMatrix = false;
mDsDx = mWin.mGlobalScale;
@@ -790,12 +788,6 @@
if (DEBUG_WINDOW_CROP) Slog.d(TAG, "win=" + w + " Initial clip rect: " + clipRect
+ " fullscreen=" + fullscreen);
- if (isFreeformResizing && !w.isChildWindow()) {
- // For freeform resizing non child windows, we are using the big surface positioned
- // at 0,0. Thus we must express the crop in that coordinate space.
- clipRect.offset(w.mShownPosition.x, w.mShownPosition.y);
- }
-
w.expandForSurfaceInsets(clipRect);
// The clip rect was generated assuming (0,0) as the window origin,
@@ -837,7 +829,7 @@
return;
}
- mTmpSize.set(w.mShownPosition.x, w.mShownPosition.y, 0, 0);
+ mTmpSize.set(0, 0, 0, 0);
calculateSurfaceBounds(w, attrs);
mExtraHScale = (float) 1.0;
@@ -971,11 +963,6 @@
// then take over the scaling until the new buffer arrives, and things
// will be seamless.
mForceScaleUntilResize = true;
- } else {
- if (!w.mSeamlesslyRotated) {
- mSurfaceController.setPositionInTransaction(mTmpSize.left, mTmpSize.top,
- recoveringMemory);
- }
}
// If we are ending the scaling mode. We switch to SCALING_MODE_FREEZE
@@ -1167,24 +1154,26 @@
mSurfaceController.setTransparentRegionHint(region);
}
- void setWallpaperOffset(Point shownPosition) {
- final LayoutParams attrs = mWin.getAttrs();
- final int left = shownPosition.x - attrs.surfaceInsets.left;
- final int top = shownPosition.y - attrs.surfaceInsets.top;
+ boolean setWallpaperOffset(int dx, int dy) {
+ if (mXOffset == dx && mYOffset == dy) {
+ return false;
+ }
+ mXOffset = dx;
+ mYOffset = dy;
try {
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setWallpaperOffset");
mService.openSurfaceTransaction();
- mSurfaceController.setPositionInTransaction(mWin.mFrame.left + left,
- mWin.mFrame.top + top, false);
+ mSurfaceController.setPositionInTransaction(dx, dy, false);
applyCrop(null, false);
} catch (RuntimeException e) {
Slog.w(TAG, "Error positioning surface of " + mWin
- + " pos=(" + left + "," + top + ")", e);
+ + " pos=(" + dx + "," + dy + ")", e);
} finally {
mService.closeSurfaceTransaction("setWallpaperOffset");
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
"<<< CLOSE TRANSACTION setWallpaperOffset");
+ return true;
}
}
diff --git a/services/core/jni/BroadcastRadio/convert.cpp b/services/core/jni/BroadcastRadio/convert.cpp
index 8c38e0a..847222a 100644
--- a/services/core/jni/BroadcastRadio/convert.cpp
+++ b/services/core/jni/BroadcastRadio/convert.cpp
@@ -395,7 +395,8 @@
gjni.ModuleProperties.cstor, moduleId, jServiceName.get(), prop10.classId,
jImplementor.get(), jProduct.get(), jVersion.get(), jSerial.get(), prop10.numTuners,
prop10.numAudioSources, prop10.supportsCapture, jBands.get(), isBgScanSupported,
- jSupportedProgramTypes.get(), jSupportedIdentifierTypes.get(), jVendorInfo.get()));
+ jSupportedProgramTypes.get(), jSupportedIdentifierTypes.get(), nullptr,
+ jVendorInfo.get()));
}
JavaRef<jobject> ModulePropertiesFromHal(JNIEnv *env, const V1_0::Properties &properties,
@@ -712,7 +713,7 @@
gjni.ModuleProperties.cstor = GetMethodIDOrDie(env, modulePropertiesClass, "<init>",
"(ILjava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;"
"Ljava/lang/String;IIZ[Landroid/hardware/radio/RadioManager$BandDescriptor;Z"
- "[I[ILjava/util/Map;)V");
+ "[I[ILjava/util/Map;Ljava/util/Map;)V");
auto programInfoClass = FindClassOrDie(env, "android/hardware/radio/RadioManager$ProgramInfo");
gjni.ProgramInfo.clazz = MakeGlobalRefOrDie(env, programInfoClass);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 210fd47..d5ed98e 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -723,21 +723,9 @@
MmsServiceBroker mmsService = null;
HardwarePropertiesManagerService hardwarePropertiesService = null;
- boolean disableSystemUI = SystemProperties.getBoolean("config.disable_systemui", false);
boolean disableRtt = SystemProperties.getBoolean("config.disable_rtt", false);
- boolean disableMediaProjection = SystemProperties.getBoolean("config.disable_mediaproj",
- false);
- boolean disableSerial = SystemProperties.getBoolean("config.disable_serial", false);
- boolean disableSearchManager = SystemProperties.getBoolean("config.disable_searchmanager",
- false);
- boolean disableTrustManager = SystemProperties.getBoolean("config.disable_trustmanager",
- false);
- boolean disableTextServices = SystemProperties.getBoolean("config.disable_textservices",
- false);
boolean disableSystemTextClassifier = SystemProperties.getBoolean(
"config.disable_systemtextclassifier", false);
- boolean disableConsumerIr = SystemProperties.getBoolean("config.disable_consumerir", false);
- boolean disableVrManager = SystemProperties.getBoolean("config.disable_vrmanager", false);
boolean disableCameraService = SystemProperties.getBoolean("config.disable_cameraservice",
false);
boolean disableSlices = SystemProperties.getBoolean("config.disable_slices", false);
@@ -745,6 +733,9 @@
boolean isEmulator = SystemProperties.get("ro.kernel.qemu").equals("1");
+ boolean isWatch = context.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_WATCH);
+
// For debugging RescueParty
if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean("debug.crash_system", false)) {
throw new RuntimeException();
@@ -819,7 +810,7 @@
ServiceManager.addService("vibrator", vibrator);
traceEnd();
- if (!disableConsumerIr) {
+ if (!isWatch) {
traceBeginAndSlog("StartConsumerIrService");
consumerIr = new ConsumerIrService(context);
ServiceManager.addService(Context.CONSUMER_IR_SERVICE, consumerIr);
@@ -862,7 +853,7 @@
traceLog.traceEnd();
}, START_HIDL_SERVICES);
- if (!disableVrManager) {
+ if (!isWatch) {
traceBeginAndSlog("StartVrManagerService");
mSystemServiceManager.startService(VrManagerService.class);
traceEnd();
@@ -1030,7 +1021,7 @@
mSystemServiceManager.startService(DevicePolicyManagerService.Lifecycle.class);
traceEnd();
- if (!disableSystemUI) {
+ if (!isWatch) {
traceBeginAndSlog("StartStatusBarManagerService");
try {
statusBar = new StatusBarManagerService(context, wm);
@@ -1063,11 +1054,9 @@
}
traceEnd();
- if (!disableTextServices) {
- traceBeginAndSlog("StartTextServicesManager");
- mSystemServiceManager.startService(TextServicesManagerService.Lifecycle.class);
- traceEnd();
- }
+ traceBeginAndSlog("StartTextServicesManager");
+ mSystemServiceManager.startService(TextServicesManagerService.Lifecycle.class);
+ traceEnd();
if (!disableSystemTextClassifier) {
traceBeginAndSlog("StartTextClassificationManagerService");
@@ -1229,7 +1218,7 @@
}
traceEnd();
- if (!disableSearchManager) {
+ if (!isWatch) {
traceBeginAndSlog("StartSearchManagerService");
try {
mSystemServiceManager.startService(SEARCH_MANAGER_SERVICE_CLASS);
@@ -1259,7 +1248,7 @@
mSystemServiceManager.startService(DockObserver.class);
traceEnd();
- if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+ if (isWatch) {
traceBeginAndSlog("StartThermalObserver");
mSystemServiceManager.startService(THERMAL_OBSERVER_CLASS);
traceEnd();
@@ -1291,7 +1280,7 @@
traceEnd();
}
- if (!disableSerial) {
+ if (!isWatch) {
traceBeginAndSlog("StartSerialService");
try {
// Serial port support
@@ -1331,11 +1320,9 @@
mSystemServiceManager.startService(SoundTriggerService.class);
traceEnd();
- if (!disableTrustManager) {
- traceBeginAndSlog("StartTrustManager");
- mSystemServiceManager.startService(TrustManagerService.class);
- traceEnd();
- }
+ traceBeginAndSlog("StartTrustManager");
+ mSystemServiceManager.startService(TrustManagerService.class);
+ traceEnd();
if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_BACKUP)) {
traceBeginAndSlog("StartBackupManager");
@@ -1392,14 +1379,16 @@
traceEnd();
}
- traceBeginAndSlog("StartNetworkTimeUpdateService");
- try {
- networkTimeUpdater = new NetworkTimeUpdateService(context);
- ServiceManager.addService("network_time_update_service", networkTimeUpdater);
- } catch (Throwable e) {
- reportWtf("starting NetworkTimeUpdate service", e);
+ if (!isWatch) {
+ traceBeginAndSlog("StartNetworkTimeUpdateService");
+ try {
+ networkTimeUpdater = new NetworkTimeUpdateService(context);
+ ServiceManager.addService("network_time_update_service", networkTimeUpdater);
+ } catch (Throwable e) {
+ reportWtf("starting NetworkTimeUpdate service", e);
+ }
+ traceEnd();
}
- traceEnd();
traceBeginAndSlog("StartCommonTimeManagementService");
try {
@@ -1535,13 +1524,13 @@
traceEnd();
}
- if (!disableMediaProjection) {
+ if (!isWatch) {
traceBeginAndSlog("StartMediaProjectionManager");
mSystemServiceManager.startService(MediaProjectionManagerService.class);
traceEnd();
}
- if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+ if (isWatch) {
traceBeginAndSlog("StartWearConnectivityService");
mSystemServiceManager.startService(WEAR_CONNECTIVITY_SERVICE_CLASS);
traceEnd();
diff --git a/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java b/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
index a16f118..2c50f22 100644
--- a/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
@@ -54,7 +54,6 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.provider.Settings;
import android.provider.Settings.Global;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -64,7 +63,6 @@
import com.android.internal.app.IAppOpsCallback;
import com.android.internal.app.IAppOpsService;
-import com.android.internal.util.test.FakeSettingsProvider;
import com.android.server.ForceAppStandbyTracker.Listener;
import org.junit.Before;
@@ -83,6 +81,12 @@
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
+/**
+ * Tests for {@link ForceAppStandbyTracker}
+ *
+ * Run with:
+ atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
+ */
@SmallTest
@RunWith(AndroidJUnit4.class)
public class ForceAppStandbyTrackerTest {
@@ -236,7 +240,8 @@
verify(mMockIActivityManager).registerUidObserver(
uidObserverArgumentCaptor.capture(),
eq(ActivityManager.UID_OBSERVER_GONE | ActivityManager.UID_OBSERVER_IDLE
- | ActivityManager.UID_OBSERVER_ACTIVE),
+ | ActivityManager.UID_OBSERVER_ACTIVE
+ | ActivityManager.UID_OBSERVER_PROCSTATE),
eq(ActivityManager.PROCESS_STATE_UNKNOWN),
isNull());
verify(mMockIAppOpsService).startWatchingMode(
@@ -333,23 +338,23 @@
mPowerSaveMode = true;
mPowerSaveObserver.accept(getPowerSaveState());
- assertFalse(instance.isInForeground(UID_1));
- assertFalse(instance.isInForeground(UID_2));
- assertTrue(instance.isInForeground(Process.SYSTEM_UID));
+ assertFalse(instance.isUidActive(UID_1));
+ assertFalse(instance.isUidActive(UID_2));
+ assertTrue(instance.isUidActive(Process.SYSTEM_UID));
mIUidObserver.onUidActive(UID_1);
areRestricted(instance, UID_1, PACKAGE_1, NONE);
areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS);
areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE);
- assertTrue(instance.isInForeground(UID_1));
- assertFalse(instance.isInForeground(UID_2));
+ assertTrue(instance.isUidActive(UID_1));
+ assertFalse(instance.isUidActive(UID_2));
mIUidObserver.onUidGone(UID_1, /*disable=*/ false);
areRestricted(instance, UID_1, PACKAGE_1, JOBS_AND_ALARMS);
areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS);
areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE);
- assertFalse(instance.isInForeground(UID_1));
- assertFalse(instance.isInForeground(UID_2));
+ assertFalse(instance.isUidActive(UID_1));
+ assertFalse(instance.isUidActive(UID_2));
mIUidObserver.onUidActive(UID_1);
areRestricted(instance, UID_1, PACKAGE_1, NONE);
@@ -360,8 +365,8 @@
areRestricted(instance, UID_1, PACKAGE_1, JOBS_AND_ALARMS);
areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS);
areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE);
- assertFalse(instance.isInForeground(UID_1));
- assertFalse(instance.isInForeground(UID_2));
+ assertFalse(instance.isUidActive(UID_1));
+ assertFalse(instance.isUidActive(UID_2));
// Toggle the app ops.
mPowerSaveMode = false;
@@ -456,6 +461,88 @@
}
@Test
+ public void testUidStateForeground() throws Exception {
+ final ForceAppStandbyTrackerTestable instance = newInstance();
+ callStart(instance);
+
+ mIUidObserver.onUidActive(UID_1);
+
+ assertTrue(instance.isUidActive(UID_1));
+ assertFalse(instance.isUidActive(UID_2));
+ assertTrue(instance.isUidActive(Process.SYSTEM_UID));
+
+ assertFalse(instance.isUidInForeground(UID_1));
+ assertFalse(instance.isUidInForeground(UID_2));
+ assertTrue(instance.isUidInForeground(Process.SYSTEM_UID));
+
+
+ mIUidObserver.onUidStateChanged(UID_2,
+ ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE, 0);
+
+ assertTrue(instance.isUidActive(UID_1));
+ assertFalse(instance.isUidActive(UID_2));
+ assertTrue(instance.isUidActive(Process.SYSTEM_UID));
+
+ assertFalse(instance.isUidInForeground(UID_1));
+ assertTrue(instance.isUidInForeground(UID_2));
+ assertTrue(instance.isUidInForeground(Process.SYSTEM_UID));
+
+
+ mIUidObserver.onUidStateChanged(UID_1,
+ ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0);
+
+ assertTrue(instance.isUidActive(UID_1));
+ assertFalse(instance.isUidActive(UID_2));
+ assertTrue(instance.isUidActive(Process.SYSTEM_UID));
+
+ assertTrue(instance.isUidInForeground(UID_1));
+ assertTrue(instance.isUidInForeground(UID_2));
+ assertTrue(instance.isUidInForeground(Process.SYSTEM_UID));
+
+ mIUidObserver.onUidGone(UID_1, true);
+
+ assertFalse(instance.isUidActive(UID_1));
+ assertFalse(instance.isUidActive(UID_2));
+ assertTrue(instance.isUidActive(Process.SYSTEM_UID));
+
+ assertFalse(instance.isUidInForeground(UID_1));
+ assertTrue(instance.isUidInForeground(UID_2));
+ assertTrue(instance.isUidInForeground(Process.SYSTEM_UID));
+
+ mIUidObserver.onUidIdle(UID_2, true);
+
+ assertFalse(instance.isUidActive(UID_1));
+ assertFalse(instance.isUidActive(UID_2));
+ assertTrue(instance.isUidActive(Process.SYSTEM_UID));
+
+ assertFalse(instance.isUidInForeground(UID_1));
+ assertFalse(instance.isUidInForeground(UID_2));
+ assertTrue(instance.isUidInForeground(Process.SYSTEM_UID));
+
+ mIUidObserver.onUidStateChanged(UID_1,
+ ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND, 0);
+
+ assertFalse(instance.isUidActive(UID_1));
+ assertFalse(instance.isUidActive(UID_2));
+ assertTrue(instance.isUidActive(Process.SYSTEM_UID));
+
+ assertTrue(instance.isUidInForeground(UID_1));
+ assertFalse(instance.isUidInForeground(UID_2));
+ assertTrue(instance.isUidInForeground(Process.SYSTEM_UID));
+
+ mIUidObserver.onUidStateChanged(UID_1,
+ ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND, 0);
+
+ assertFalse(instance.isUidActive(UID_1));
+ assertFalse(instance.isUidActive(UID_2));
+ assertTrue(instance.isUidActive(Process.SYSTEM_UID));
+
+ assertFalse(instance.isUidInForeground(UID_1));
+ assertFalse(instance.isUidInForeground(UID_2));
+ assertTrue(instance.isUidInForeground(Process.SYSTEM_UID));
+ }
+
+ @Test
public void testExempt() throws Exception {
final ForceAppStandbyTrackerTestable instance = newInstance();
callStart(instance);
@@ -953,8 +1040,8 @@
setAppOps(UID_2, PACKAGE_2, true);
setAppOps(UID_10_2, PACKAGE_2, true);
- assertTrue(instance.isInForeground(UID_1));
- assertTrue(instance.isInForeground(UID_10_1));
+ assertTrue(instance.isUidActive(UID_1));
+ assertTrue(instance.isUidActive(UID_10_1));
assertFalse(instance.isRunAnyInBackgroundAppOpsAllowed(UID_2, PACKAGE_2));
assertFalse(instance.isRunAnyInBackgroundAppOpsAllowed(UID_10_2, PACKAGE_2));
@@ -965,8 +1052,8 @@
waitUntilMainHandlerDrain();
- assertTrue(instance.isInForeground(UID_1));
- assertFalse(instance.isInForeground(UID_10_1));
+ assertTrue(instance.isUidActive(UID_1));
+ assertFalse(instance.isUidActive(UID_10_1));
assertFalse(instance.isRunAnyInBackgroundAppOpsAllowed(UID_2, PACKAGE_2));
assertTrue(instance.isRunAnyInBackgroundAppOpsAllowed(UID_10_2, PACKAGE_2));
diff --git a/services/tests/servicestests/src/com/android/server/am/LockTaskControllerTest.java b/services/tests/servicestests/src/com/android/server/am/LockTaskControllerTest.java
index d2ae22b..1cbb399 100644
--- a/services/tests/servicestests/src/com/android/server/am/LockTaskControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/LockTaskControllerTest.java
@@ -90,7 +90,6 @@
@Mock private IStatusBarService mStatusBarService;
@Mock private WindowManagerService mWindowManager;
@Mock private LockPatternUtils mLockPatternUtils;
- @Mock private LockTaskNotify mLockTaskNotify;
@Mock private StatusBarManagerInternal mStatusBarManagerInternal;
@Mock private TelecomManager mTelecomManager;
@Mock private RecentTasks mRecentTasks;
@@ -123,7 +122,6 @@
mLockTaskController.mDevicePolicyManager = mDevicePolicyManager;
mLockTaskController.mTelecomManager = mTelecomManager;
mLockTaskController.mLockPatternUtils = mLockPatternUtils;
- mLockTaskController.mLockTaskNotify = mLockTaskNotify;
LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
LocalServices.addService(StatusBarManagerInternal.class, mStatusBarManagerInternal);
@@ -208,7 +206,7 @@
// THEN lock task mode should be started
verifyLockTaskStarted(STATUS_BAR_MASK_PINNED, DISABLE2_NONE);
// THEN screen pinning toast should be shown
- verify(mLockTaskNotify).showPinningStartToast();
+ verify(mStatusBarService).showPinningEnterExitToast(true /* entering */);
}
@Test
@@ -377,7 +375,7 @@
// THEN the keyguard should be shown
verify(mLockPatternUtils).requireCredentialEntry(UserHandle.USER_ALL);
// THEN screen pinning toast should be shown
- verify(mLockTaskNotify).showPinningExitToast();
+ verify(mStatusBarService).showPinningEnterExitToast(false /* entering */);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
index c863aab..473a813 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
@@ -39,6 +39,7 @@
import android.os.Binder;
import android.os.ServiceSpecificException;
import android.os.UserHandle;
+import android.security.KeyStore;
import android.security.keystore.AndroidKeyStoreSecretKey;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
@@ -49,6 +50,7 @@
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
+import com.android.server.locksettings.recoverablekeystore.storage.ApplicationKeyStorage;
import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDb;
import com.android.server.locksettings.recoverablekeystore.storage.RecoverySessionStorage;
import com.android.server.locksettings.recoverablekeystore.storage.RecoverySnapshotStorage;
@@ -135,6 +137,8 @@
@Mock private RecoverySnapshotListenersStorage mMockListenersStorage;
@Mock private KeyguardManager mKeyguardManager;
@Mock private PlatformKeyManager mPlatformKeyManager;
+ @Mock private KeyStore mKeyStore;
+ @Mock private ApplicationKeyStorage mApplicationKeyStorage;
private RecoverableKeyStoreDb mRecoverableKeyStoreDb;
private File mDatabaseFile;
@@ -164,12 +168,14 @@
mRecoverableKeyStoreManager = new RecoverableKeyStoreManager(
mMockContext,
+ mKeyStore,
mRecoverableKeyStoreDb,
mRecoverySessionStorage,
Executors.newSingleThreadExecutor(),
mRecoverySnapshotStorage,
mMockListenersStorage,
- mPlatformKeyManager);
+ mPlatformKeyManager,
+ mApplicationKeyStorage);
}
@After
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index 56d4b7e..857925b 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -5149,7 +5149,8 @@
.forAllShortcuts(si -> {
switch (package1DisabledReason) {
case ShortcutInfo.DISABLED_REASON_VERSION_LOWER:
- assertEquals("This shortcut requires latest app",
+ assertEquals("App version downgraded, or isn’t compatible"
+ + " with this shortcut",
si.getDisabledMessage());
break;
case ShortcutInfo.DISABLED_REASON_SIGNATURE_MISMATCH:
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java
index c2072df..f559986a 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java
@@ -53,6 +53,7 @@
assertFalse(opt.isDowngrade());
assertFalse(opt.isForce());
assertFalse(opt.isDexoptIdleBackgroundJob());
+ assertFalse(opt.isDexoptInstallWithDexMetadata());
}
@Test
@@ -65,7 +66,8 @@
DexoptOptions.DEXOPT_ONLY_SHARED_DEX |
DexoptOptions.DEXOPT_DOWNGRADE |
DexoptOptions.DEXOPT_AS_SHARED_LIBRARY |
- DexoptOptions.DEXOPT_IDLE_BACKGROUND_JOB;
+ DexoptOptions.DEXOPT_IDLE_BACKGROUND_JOB |
+ DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE;
DexoptOptions opt = new DexoptOptions(mPackageName, mCompilerFilter, flags);
assertEquals(mPackageName, opt.getPackageName());
@@ -79,6 +81,7 @@
assertTrue(opt.isForce());
assertTrue(opt.isDexoptAsSharedLibrary());
assertTrue(opt.isDexoptIdleBackgroundJob());
+ assertTrue(opt.isDexoptInstallWithDexMetadata());
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java b/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java
index a628b7b..5de393c 100644
--- a/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java
+++ b/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java
@@ -79,11 +79,6 @@
}
@Override
- public Point getShownPositionLw() {
- return new Point(parentFrame.left, parentFrame.top);
- }
-
- @Override
public Rect getDisplayFrameLw() {
return displayFrame;
}
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index 40964c0..78b6077 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -24,6 +24,7 @@
import static android.app.usage.UsageStatsManager.REASON_TIMEOUT;
import static android.app.usage.UsageStatsManager.REASON_USAGE;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE;
+import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_EXEMPTED;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_NEVER;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
@@ -35,6 +36,7 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doReturn;
@@ -80,6 +82,8 @@
private static final String PACKAGE_1 = "com.example.foo";
private static final int UID_1 = 10000;
+ private static final String PACKAGE_EXEMPTED_1 = "com.android.exempted";
+ private static final int UID_EXEMPTED_1 = 10001;
private static final int USER_ID = 0;
private static final int USER_ID2 = 10;
@@ -116,7 +120,7 @@
List<String> mPowerSaveWhitelistExceptIdle = new ArrayList<>();
boolean mDisplayOn;
DisplayManager.DisplayListener mDisplayListener;
- String mBoundWidgetPackage;
+ String mBoundWidgetPackage = PACKAGE_EXEMPTED_1;
MyInjector(Context context, Looper looper) {
super(context, looper);
@@ -223,10 +227,21 @@
pi.packageName = PACKAGE_1;
packages.add(pi);
+ PackageInfo pie = new PackageInfo();
+ pie.applicationInfo = new ApplicationInfo();
+ pie.applicationInfo.uid = UID_EXEMPTED_1;
+ pie.packageName = PACKAGE_EXEMPTED_1;
+ packages.add(pie);
+
doReturn(packages).when(mockPm).getInstalledPackagesAsUser(anyInt(), anyInt());
try {
- doReturn(UID_1).when(mockPm).getPackageUidAsUser(anyString(), anyInt(), anyInt());
- doReturn(pi.applicationInfo).when(mockPm).getApplicationInfo(anyString(), anyInt());
+ doReturn(UID_1).when(mockPm).getPackageUidAsUser(eq(PACKAGE_1), anyInt(), anyInt());
+ doReturn(UID_EXEMPTED_1).when(mockPm).getPackageUidAsUser(eq(PACKAGE_EXEMPTED_1),
+ anyInt(), anyInt());
+ doReturn(pi.applicationInfo).when(mockPm).getApplicationInfo(eq(pi.packageName),
+ anyInt());
+ doReturn(pie.applicationInfo).when(mockPm).getApplicationInfo(eq(pie.packageName),
+ anyInt());
} catch (PackageManager.NameNotFoundException nnfe) {}
}
@@ -239,14 +254,21 @@
private AppStandbyController setupController() throws Exception {
mInjector.mElapsedRealtime = 0;
+ setupPm(mInjector.getContext().getPackageManager());
AppStandbyController controller = new AppStandbyController(mInjector);
+ controller.initializeDefaultsForSystemApps(USER_ID);
controller.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
controller.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
mInjector.setDisplayOn(false);
mInjector.setDisplayOn(true);
setChargingState(controller, false);
- setupPm(mInjector.getContext().getPackageManager());
controller.checkIdleStates(USER_ID);
+ assertEquals(STANDBY_BUCKET_EXEMPTED,
+ controller.getAppStandbyBucket(PACKAGE_EXEMPTED_1, USER_ID,
+ mInjector.mElapsedRealtime, false));
+ assertNotEquals(STANDBY_BUCKET_EXEMPTED,
+ controller.getAppStandbyBucket(PACKAGE_1, USER_ID,
+ mInjector.mElapsedRealtime, false));
return controller;
}
diff --git a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
index 99eb846..e36586e 100644
--- a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
+++ b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
@@ -210,6 +210,9 @@
runCommand(instrumentation, "cmd package set-home-activity --user "
+ instrumentation.getContext().getUserId() + " " + component,
result -> result.contains("Success"));
+ runCommand(instrumentation, "cmd shortcut clear-default-launcher --user "
+ + instrumentation.getContext().getUserId(),
+ result -> result.contains("Success"));
}
public static void setDefaultLauncher(Instrumentation instrumentation, Context packageContext) {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 9ae6f00..6b6df29 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -117,7 +117,7 @@
public class NotificationManagerServiceTest extends UiServiceTestCase {
private static final String TEST_CHANNEL_ID = "NotificationManagerServiceTestChannelId";
private final int mUid = Binder.getCallingUid();
- private NotificationManagerService mService;
+ private TestableNotificationManagerService mService;
private INotificationManager mBinderService;
private NotificationManagerInternal mInternalService;
@Mock
@@ -152,17 +152,21 @@
// Use a Testable subclass so we can simulate calls from the system without failing.
private static class TestableNotificationManagerService extends NotificationManagerService {
+ int countSystemChecks = 0;
+
public TestableNotificationManagerService(Context context) {
super(context);
}
@Override
protected boolean isCallingUidSystem() {
+ countSystemChecks++;
return true;
}
@Override
protected boolean isCallerSystemOrPhone() {
+ countSystemChecks++;
return true;
}
@@ -2429,4 +2433,18 @@
.setUid(user2.sbn.getUid())
.setLastNotified(user2.sbn.getPostTime())));
}
+
+ @Test
+ public void testRestore() throws Exception {
+ int systemChecks = mService.countSystemChecks;
+ mBinderService.applyRestore(null, UserHandle.USER_SYSTEM);
+ assertEquals(1, mService.countSystemChecks - systemChecks);
+ }
+
+ @Test
+ public void testBackup() throws Exception {
+ int systemChecks = mService.countSystemChecks;
+ mBinderService.getBackupPayload(1);
+ assertEquals(1, mService.countSystemChecks - systemChecks);
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/slice/SliceFullAccessListTest.java b/services/tests/uiservicestests/src/com/android/server/slice/SliceFullAccessListTest.java
index b784c60..bc28150 100644
--- a/services/tests/uiservicestests/src/com/android/server/slice/SliceFullAccessListTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/slice/SliceFullAccessListTest.java
@@ -18,6 +18,7 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import android.os.UserHandle;
import android.support.test.filters.SmallTest;
import android.util.Xml.Encoding;
@@ -85,7 +86,7 @@
ByteArrayOutputStream output = new ByteArrayOutputStream();
XmlSerializer out = XmlPullParserFactory.newInstance().newSerializer();
out.setOutput(output, Encoding.UTF_8.name());
- mAccessList.writeXml(out);
+ mAccessList.writeXml(out, UserHandle.USER_ALL);
out.flush();
assertEquals(TEST_XML, output.toString(Encoding.UTF_8.name()));
diff --git a/services/usage/java/com/android/server/usage/AppIdleHistory.java b/services/usage/java/com/android/server/usage/AppIdleHistory.java
index 2becdf2..b654a66 100644
--- a/services/usage/java/com/android/server/usage/AppIdleHistory.java
+++ b/services/usage/java/com/android/server/usage/AppIdleHistory.java
@@ -228,7 +228,9 @@
}
if (timeout > elapsedRealtime) {
// Convert to elapsed timebase
- appUsageHistory.bucketTimeoutTime = mElapsedDuration + (timeout - mElapsedSnapshot);
+ appUsageHistory.bucketTimeoutTime =
+ Math.max(appUsageHistory.bucketTimeoutTime,
+ mElapsedDuration + (timeout - mElapsedSnapshot));
}
}
appUsageHistory.bucketingReason = REASON_USAGE;
diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java
index 8cb2eec..cc21199 100644
--- a/services/usage/java/com/android/server/usage/AppStandbyController.java
+++ b/services/usage/java/com/android/server/usage/AppStandbyController.java
@@ -183,6 +183,8 @@
boolean mCharging;
private long mLastAppIdleParoledTime;
private boolean mSystemServicesReady = false;
+ // There was a system update, defaults need to be initialized after services are ready
+ private boolean mPendingInitializeDefaults;
private final DeviceStateReceiver mDeviceStateReceiver;
@@ -279,6 +281,7 @@
public void onBootPhase(int phase) {
mInjector.onBootPhase(phase);
if (phase == PHASE_SYSTEM_SERVICES_READY) {
+ Slog.d(TAG, "Setting app idle enabled state");
setAppIdleEnabled(mInjector.isAppIdleEnabled());
// Observe changes to the threshold
SettingsObserver settingsObserver = new SettingsObserver(mHandler);
@@ -293,11 +296,15 @@
mAppIdleHistory.updateDisplay(isDisplayOn(), mInjector.elapsedRealtime());
}
+ mSystemServicesReady = true;
+
+ if (mPendingInitializeDefaults) {
+ initializeDefaultsForSystemApps(UserHandle.USER_SYSTEM);
+ }
+
if (mPendingOneTimeCheckIdleStates) {
postOneTimeCheckIdleStates();
}
-
- mSystemServicesReady = true;
} else if (phase == PHASE_BOOT_COMPLETED) {
setChargingState(mInjector.isCharging());
}
@@ -451,7 +458,8 @@
UserHandle.getAppId(pi.applicationInfo.uid),
userId);
if (DEBUG) {
- Slog.d(TAG, " Checking idle state for " + packageName);
+ Slog.d(TAG, " Checking idle state for " + packageName + " special=" +
+ isSpecial);
}
if (isSpecial) {
synchronized (mAppIdleLock) {
@@ -523,6 +531,7 @@
elapsedRealtime, bucket)) {
StandbyUpdateRecord r = StandbyUpdateRecord.obtain(packageName, userId,
bucket, userStartedInteracting);
+ if (DEBUG) Slog.d(TAG, "Standby bucket for " + packageName + "=" + bucket);
mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS,
StandbyUpdateRecord.obtain(packageName, userId,
bucket, userStartedInteracting)));
@@ -1087,7 +1096,13 @@
}
void initializeDefaultsForSystemApps(int userId) {
- Slog.d(TAG, "Initializing defaults for system apps on user " + userId);
+ if (!mSystemServicesReady) {
+ // Do it later, since SettingsProvider wasn't queried yet for app_standby_enabled
+ mPendingInitializeDefaults = true;
+ return;
+ }
+ Slog.d(TAG, "Initializing defaults for system apps on user " + userId + ", "
+ + "appIdleEnabled=" + mAppIdleEnabled);
final long elapsedRealtime = mInjector.elapsedRealtime();
List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser(
PackageManager.MATCH_DISABLED_COMPONENTS,
@@ -1102,11 +1117,6 @@
// past usage pattern was.
mAppIdleHistory.reportUsage(packageName, userId, STANDBY_BUCKET_ACTIVE, 0,
elapsedRealtime + 4 * ONE_HOUR);
- if (isAppSpecial(packageName, UserHandle.getAppId(pi.applicationInfo.uid),
- userId)) {
- mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime,
- STANDBY_BUCKET_EXEMPTED, REASON_DEFAULT);
- }
}
}
}
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaDevice.java b/services/usb/java/com/android/server/usb/UsbAlsaDevice.java
new file mode 100644
index 0000000..74280ff
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/UsbAlsaDevice.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.usb;
+
+/**
+ * Represents the ALSA specification, and attributes of an ALSA device.
+ */
+public final class UsbAlsaDevice {
+ private static final String TAG = "UsbAlsaDevice";
+ protected static final boolean DEBUG = false;
+
+ private final int mCardNum;
+ private final int mDeviceNum;
+ private final boolean mHasPlayback;
+ private final boolean mHasCapture;
+
+ private final boolean mIsInputHeadset;
+ private final boolean mIsOutputHeadset;
+
+ private final String mDeviceAddress;
+
+ private String mDeviceName = "";
+ private String mDeviceDescription = "";
+
+ public UsbAlsaDevice(int card, int device, String deviceAddress,
+ boolean hasPlayback, boolean hasCapture,
+ boolean isInputHeadset, boolean isOutputHeadset) {
+ mCardNum = card;
+ mDeviceNum = device;
+ mDeviceAddress = deviceAddress;
+ mHasPlayback = hasPlayback;
+ mHasCapture = hasCapture;
+ mIsInputHeadset = isInputHeadset;
+ mIsOutputHeadset = isOutputHeadset;
+ }
+
+ /**
+ * @returns the ALSA card number associated with this peripheral.
+ */
+ public int getCardNum() {
+ return mCardNum;
+ }
+
+ /**
+ * @returns the ALSA device number associated with this peripheral.
+ */
+ public int getDeviceNum() {
+ return mDeviceNum;
+ }
+
+ /**
+ * @returns the USB device device address associated with this peripheral.
+ */
+ public String getDeviceAddress() {
+ return mDeviceAddress;
+ }
+
+ /**
+ * @returns true if the device supports playback.
+ */
+ public boolean hasPlayback() {
+ return mHasPlayback;
+ }
+
+ /**
+ * @returns true if the device supports capture (recording).
+ */
+ public boolean hasCapture() {
+ return mHasCapture;
+ }
+
+ /**
+ * @returns true if the device is a headset for purposes of capture.
+ */
+ public boolean isInputHeadset() {
+ return mIsInputHeadset;
+ }
+
+ /**
+ * @returns true if the device is a headset for purposes of playback.
+ */
+ public boolean isOutputHeadset() {
+ return mIsOutputHeadset;
+ }
+
+ /**
+ * @Override
+ * @returns a string representation of the object.
+ */
+ public String toString() {
+ return "UsbAlsaDevice: [card: " + mCardNum
+ + ", device: " + mDeviceNum
+ + ", name: " + mDeviceName
+ + ", hasPlayback: " + mHasPlayback
+ + ", hasCapture: " + mHasCapture + "]";
+ }
+
+ // called by logDevices
+ String toShortString() {
+ return "[card:" + mCardNum + " device:" + mDeviceNum + " " + mDeviceName + "]";
+ }
+
+ String getDeviceName() {
+ return mDeviceName;
+ }
+
+ void setDeviceNameAndDescription(String deviceName, String deviceDescription) {
+ mDeviceName = deviceName;
+ mDeviceDescription = deviceDescription;
+ }
+
+ /**
+ * @Override
+ * @returns true if the objects are equivalent.
+ */
+ public boolean equals(Object obj) {
+ if (!(obj instanceof UsbAlsaDevice)) {
+ return false;
+ }
+ UsbAlsaDevice other = (UsbAlsaDevice) obj;
+ return (mCardNum == other.mCardNum
+ && mDeviceNum == other.mDeviceNum
+ && mHasPlayback == other.mHasPlayback
+ && mHasCapture == other.mHasCapture
+ && mIsInputHeadset == other.mIsInputHeadset
+ && mIsOutputHeadset == other.mIsOutputHeadset);
+ }
+
+ /**
+ * @Override
+ * @returns a hash code generated from the object contents.
+ */
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + mCardNum;
+ result = prime * result + mDeviceNum;
+ result = prime * result + (mHasPlayback ? 0 : 1);
+ result = prime * result + (mHasCapture ? 0 : 1);
+ result = prime * result + (mIsInputHeadset ? 0 : 1);
+ result = prime * result + (mIsOutputHeadset ? 0 : 1);
+
+ return result;
+ }
+}
+
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index 7bea8a1..0a94828 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -10,7 +10,7 @@
* 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 an
+ * See the License for the specific language governing permissions and
* limitations under the License.
*/
@@ -19,28 +19,24 @@
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Resources;
-import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
-import android.hardware.usb.UsbInterface;
import android.media.AudioSystem;
import android.media.IAudioService;
import android.media.midi.MidiDeviceInfo;
import android.os.Bundle;
-import android.os.FileObserver;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.SystemClock;
import android.provider.Settings;
import android.util.Slog;
import com.android.internal.alsa.AlsaCardsParser;
-import com.android.internal.alsa.AlsaDevicesParser;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.audio.AudioService;
+import com.android.server.usb.descriptors.UsbDescriptorParser;
import libcore.io.IoUtils;
-import java.io.File;
+import java.util.ArrayList;
import java.util.HashMap;
/**
@@ -57,107 +53,36 @@
private final boolean mHasMidiFeature;
private final AlsaCardsParser mCardsParser = new AlsaCardsParser();
- private final AlsaDevicesParser mDevicesParser = new AlsaDevicesParser();
// this is needed to map USB devices to ALSA Audio Devices, especially to remove an
// ALSA device when we are notified that its associated USB device has been removed.
+ private final ArrayList<UsbAlsaDevice> mAlsaDevices = new ArrayList<UsbAlsaDevice>();
- private final HashMap<UsbDevice,UsbAudioDevice>
- mAudioDevices = new HashMap<UsbDevice,UsbAudioDevice>();
-
- private boolean mIsInputHeadset; // as reported by UsbDescriptorParser
- private boolean mIsOutputHeadset; // as reported by UsbDescriptorParser
-
- private final HashMap<UsbDevice,UsbMidiDevice>
- mMidiDevices = new HashMap<UsbDevice,UsbMidiDevice>();
-
- private final HashMap<String,AlsaDevice>
- mAlsaDevices = new HashMap<String,AlsaDevice>();
-
- private UsbAudioDevice mAccessoryAudioDevice = null;
+ /**
+ * List of connected MIDI devices
+ */
+ private final HashMap<String, UsbMidiDevice>
+ mMidiDevices = new HashMap<String, UsbMidiDevice>();
// UsbMidiDevice for USB peripheral mode (gadget) device
private UsbMidiDevice mPeripheralMidiDevice = null;
- private final class AlsaDevice {
- public static final int TYPE_UNKNOWN = 0;
- public static final int TYPE_PLAYBACK = 1;
- public static final int TYPE_CAPTURE = 2;
- public static final int TYPE_MIDI = 3;
-
- public int mCard;
- public int mDevice;
- public int mType;
-
- public AlsaDevice(int type, int card, int device) {
- mType = type;
- mCard = card;
- mDevice = device;
- }
-
- public boolean equals(Object obj) {
- if (! (obj instanceof AlsaDevice)) {
- return false;
- }
- AlsaDevice other = (AlsaDevice)obj;
- return (mType == other.mType && mCard == other.mCard && mDevice == other.mDevice);
- }
-
- public String toString() {
- StringBuilder sb = new StringBuilder();
- sb.append("AlsaDevice: [card: " + mCard);
- sb.append(", device: " + mDevice);
- sb.append(", type: " + mType);
- sb.append("]");
- return sb.toString();
- }
- }
-
- private final FileObserver mAlsaObserver = new FileObserver(ALSA_DIRECTORY,
- FileObserver.CREATE | FileObserver.DELETE) {
- public void onEvent(int event, String path) {
- switch (event) {
- case FileObserver.CREATE:
- alsaFileAdded(path);
- break;
- case FileObserver.DELETE:
- alsaFileRemoved(path);
- break;
- }
- }
- };
-
/* package */ UsbAlsaManager(Context context) {
mContext = context;
mHasMidiFeature = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_MIDI);
-
- // initial scan
- if (mCardsParser.scan() != AlsaCardsParser.SCANSTATUS_SUCCESS) {
- Slog.e(TAG, "Error scanning ASLA cards file.");
- }
}
public void systemReady() {
mAudioService = IAudioService.Stub.asInterface(
ServiceManager.getService(Context.AUDIO_SERVICE));
-
- mAlsaObserver.startWatching();
-
- // add existing alsa devices
- File[] files = new File(ALSA_DIRECTORY).listFiles();
- if (files != null) {
- for (int i = 0; i < files.length; i++) {
- alsaFileAdded(files[i].getName());
- }
- }
}
// Notifies AudioService when a device is added or removed
// audioDevice - the AudioDevice that was added or removed
// enabled - if true, we're connecting a device (it's arrived), else disconnecting
- private void notifyDeviceState(UsbAudioDevice audioDevice, boolean enabled) {
+ private void notifyDeviceState(UsbAlsaDevice alsaDevice, boolean enabled) {
if (DEBUG) {
- Slog.d(TAG, "notifyDeviceState " + enabled + " " + audioDevice);
+ Slog.d(TAG, "notifyDeviceState " + enabled + " " + alsaDevice);
}
if (mAudioService == null) {
@@ -177,276 +102,151 @@
}
int state = (enabled ? 1 : 0);
- int alsaCard = audioDevice.mCard;
- int alsaDevice = audioDevice.mDevice;
- if (alsaCard < 0 || alsaDevice < 0) {
- Slog.e(TAG, "Invalid alsa card or device alsaCard: " + alsaCard +
- " alsaDevice: " + alsaDevice);
+ int cardNum = alsaDevice.getCardNum();
+ int deviceNum = alsaDevice.getDeviceNum();
+ if (cardNum < 0 || deviceNum < 0) {
+ Slog.e(TAG, "Invalid alsa card or device alsaCard: " + cardNum
+ + " alsaDevice: " + deviceNum);
return;
}
- String address = AudioService.makeAlsaAddressString(alsaCard, alsaDevice);
+ String address = AudioService.makeAlsaAddressString(cardNum, deviceNum);
try {
// Playback Device
- if (audioDevice.mHasPlayback) {
- int device;
- if (mIsOutputHeadset) {
- device = AudioSystem.DEVICE_OUT_USB_HEADSET;
- } else {
- device = (audioDevice == mAccessoryAudioDevice
- ? AudioSystem.DEVICE_OUT_USB_ACCESSORY
- : AudioSystem.DEVICE_OUT_USB_DEVICE);
- }
+ if (alsaDevice.hasPlayback()) {
+ int device = alsaDevice.isOutputHeadset()
+ ? AudioSystem.DEVICE_OUT_USB_HEADSET
+ : AudioSystem.DEVICE_OUT_USB_DEVICE;
if (DEBUG) {
Slog.i(TAG, "pre-call device:0x" + Integer.toHexString(device) +
- " addr:" + address + " name:" + audioDevice.getDeviceName());
+ " addr:" + address + " name:" + alsaDevice.getDeviceName());
}
mAudioService.setWiredDeviceConnectionState(
- device, state, address, audioDevice.getDeviceName(), TAG);
+ device, state, address, alsaDevice.getDeviceName(), TAG);
}
// Capture Device
- if (audioDevice.mHasCapture) {
- int device;
- if (mIsInputHeadset) {
- device = AudioSystem.DEVICE_IN_USB_HEADSET;
- } else {
- device = (audioDevice == mAccessoryAudioDevice
- ? AudioSystem.DEVICE_IN_USB_ACCESSORY
- : AudioSystem.DEVICE_IN_USB_DEVICE);
- }
+ if (alsaDevice.hasCapture()) {
+ int device = alsaDevice.isInputHeadset()
+ ? AudioSystem.DEVICE_IN_USB_HEADSET
+ : AudioSystem.DEVICE_IN_USB_DEVICE;
mAudioService.setWiredDeviceConnectionState(
- device, state, address, audioDevice.getDeviceName(), TAG);
+ device, state, address, alsaDevice.getDeviceName(), TAG);
}
} catch (RemoteException e) {
Slog.e(TAG, "RemoteException in setWiredDeviceConnectionState");
}
}
- private AlsaDevice waitForAlsaDevice(int card, int device, int type) {
- if (DEBUG) {
- Slog.e(TAG, "waitForAlsaDevice(c:" + card + " d:" + device + ")");
+ private int getAlsaDeviceListIndexFor(String deviceAddress) {
+ for (int index = 0; index < mAlsaDevices.size(); index++) {
+ if (mAlsaDevices.get(index).getDeviceAddress().equals(deviceAddress)) {
+ return index;
+ }
}
-
- AlsaDevice testDevice = new AlsaDevice(type, card, device);
-
- // This value was empirically determined.
- final int kWaitTimeMs = 2500;
-
- synchronized(mAlsaDevices) {
- long timeoutMs = SystemClock.elapsedRealtime() + kWaitTimeMs;
- do {
- if (mAlsaDevices.values().contains(testDevice)) {
- return testDevice;
- }
- long waitTimeMs = timeoutMs - SystemClock.elapsedRealtime();
- if (waitTimeMs > 0) {
- try {
- mAlsaDevices.wait(waitTimeMs);
- } catch (InterruptedException e) {
- Slog.d(TAG, "usb: InterruptedException while waiting for ALSA file.");
- }
- }
- } while (timeoutMs > SystemClock.elapsedRealtime());
- }
-
- Slog.e(TAG, "waitForAlsaDevice failed for " + testDevice);
- return null;
+ return -1;
}
- private void alsaFileAdded(String name) {
- Slog.i(TAG, "alsaFileAdded(" + name + ")");
- int type = AlsaDevice.TYPE_UNKNOWN;
- int card = -1, device = -1;
-
- if (name.startsWith("pcmC")) {
- if (name.endsWith("p")) {
- type = AlsaDevice.TYPE_PLAYBACK;
- } else if (name.endsWith("c")) {
- type = AlsaDevice.TYPE_CAPTURE;
- }
- } else if (name.startsWith("midiC")) {
- type = AlsaDevice.TYPE_MIDI;
- }
-
- if (type != AlsaDevice.TYPE_UNKNOWN) {
- try {
- int c_index = name.indexOf('C');
- int d_index = name.indexOf('D');
- int end = name.length();
- if (type == AlsaDevice.TYPE_PLAYBACK || type == AlsaDevice.TYPE_CAPTURE) {
- // skip trailing 'p' or 'c'
- end--;
- }
- card = Integer.parseInt(name.substring(c_index + 1, d_index));
- device = Integer.parseInt(name.substring(d_index + 1, end));
- } catch (Exception e) {
- Slog.e(TAG, "Could not parse ALSA file name " + name, e);
- return;
- }
- synchronized(mAlsaDevices) {
- if (mAlsaDevices.get(name) == null) {
- AlsaDevice alsaDevice = new AlsaDevice(type, card, device);
- Slog.d(TAG, "Adding ALSA device " + alsaDevice);
- mAlsaDevices.put(name, alsaDevice);
- mAlsaDevices.notifyAll();
- }
- }
+ private UsbAlsaDevice removeAlsaDeviceFromList(String deviceAddress) {
+ int index = getAlsaDeviceListIndexFor(deviceAddress);
+ if (index > -1) {
+ return mAlsaDevices.remove(index);
+ } else {
+ return null;
}
}
- private void alsaFileRemoved(String path) {
- synchronized(mAlsaDevices) {
- AlsaDevice device = mAlsaDevices.remove(path);
- if (device != null) {
- Slog.d(TAG, "ALSA device removed: " + device);
- }
- }
- }
-
- /*
- * Select the default device of the specified card.
- */
- /* package */ UsbAudioDevice selectAudioCard(int card) {
- if (DEBUG) {
- Slog.d(TAG, "selectAudioCard() card:" + card
- + " isCardUsb(): " + mCardsParser.isCardUsb(card));
- }
- if (!mCardsParser.isCardUsb(card)) {
- // Don't. AudioPolicyManager has logic for falling back to internal devices.
- return null;
- }
-
- if (mDevicesParser.scan() != AlsaDevicesParser.SCANSTATUS_SUCCESS) {
- Slog.e(TAG, "Error parsing ALSA devices file.");
- return null;
- }
-
- int device = mDevicesParser.getDefaultDeviceNum(card);
-
- boolean hasPlayback = mDevicesParser.hasPlaybackDevices(card);
- boolean hasCapture = mDevicesParser.hasCaptureDevices(card);
- if (DEBUG) {
- Slog.d(TAG, "usb: hasPlayback:" + hasPlayback + " hasCapture:" + hasCapture);
- }
-
- int deviceClass =
- (mCardsParser.isCardUsb(card)
- ? UsbAudioDevice.kAudioDeviceClass_External
- : UsbAudioDevice.kAudioDeviceClass_Internal) |
- UsbAudioDevice.kAudioDeviceMeta_Alsa;
-
- // Playback device file needed/present?
- if (hasPlayback && (waitForAlsaDevice(card, device, AlsaDevice.TYPE_PLAYBACK) == null)) {
- return null;
- }
-
- // Capture device file needed/present?
- if (hasCapture && (waitForAlsaDevice(card, device, AlsaDevice.TYPE_CAPTURE) == null)) {
- return null;
- }
-
- UsbAudioDevice audioDevice =
- new UsbAudioDevice(card, device, hasPlayback, hasCapture, deviceClass);
- AlsaCardsParser.AlsaCardRecord cardRecord = mCardsParser.getCardRecordFor(card);
- audioDevice.setDeviceNameAndDescription(cardRecord.mCardName, cardRecord.mCardDescription);
-
- notifyDeviceState(audioDevice, true /*enabled*/);
-
- return audioDevice;
- }
-
- /* package */ UsbAudioDevice selectDefaultDevice() {
+ /* package */ UsbAlsaDevice selectDefaultDevice() {
if (DEBUG) {
Slog.d(TAG, "UsbAudioManager.selectDefaultDevice()");
}
- return selectAudioCard(mCardsParser.getDefaultCard());
+
+ if (mAlsaDevices.size() > 0) {
+ UsbAlsaDevice alsaDevice = mAlsaDevices.get(0);
+ if (DEBUG) {
+ Slog.d(TAG, " alsaDevice:" + alsaDevice);
+ }
+ if (alsaDevice != null) {
+ notifyDeviceState(alsaDevice, true /*enabled*/);
+ }
+ return alsaDevice;
+ } else {
+ return null;
+ }
}
- /* package */ void usbDeviceAdded(UsbDevice usbDevice,
- boolean isInputHeadset, boolean isOutputHeadset) {
+ /* package */ void usbDeviceAdded(String deviceAddress, UsbDevice usbDevice,
+ UsbDescriptorParser parser) {
if (DEBUG) {
- Slog.d(TAG, "deviceAdded(): " + usbDevice.getManufacturerName()
+ Slog.d(TAG, "usbDeviceAdded(): " + usbDevice.getManufacturerName()
+ " nm:" + usbDevice.getProductName());
}
- mIsInputHeadset = isInputHeadset;
- mIsOutputHeadset = isOutputHeadset;
+ // Scan the Alsa File Space
+ mCardsParser.scan();
- // Is there an audio interface in there?
- boolean isAudioDevice = false;
-
- // FIXME - handle multiple configurations?
- int interfaceCount = usbDevice.getInterfaceCount();
- for (int ntrfaceIndex = 0; !isAudioDevice && ntrfaceIndex < interfaceCount;
- ntrfaceIndex++) {
- UsbInterface ntrface = usbDevice.getInterface(ntrfaceIndex);
- if (ntrface.getInterfaceClass() == UsbConstants.USB_CLASS_AUDIO) {
- isAudioDevice = true;
- }
- }
-
- if (DEBUG) {
- Slog.d(TAG, " isAudioDevice: " + isAudioDevice);
- }
- if (!isAudioDevice) {
+ // Find the ALSA spec for this device address
+ AlsaCardsParser.AlsaCardRecord cardRec =
+ mCardsParser.findCardNumFor(deviceAddress);
+ if (cardRec == null) {
return;
}
- int addedCard = mCardsParser.getDefaultUsbCard();
-
- // If the default isn't a USB device, let the existing "select internal mechanism"
- // handle the selection.
+ // Add it to the devices list
+ boolean hasInput = parser.hasInput();
+ boolean hasOutput = parser.hasOutput();
if (DEBUG) {
- Slog.d(TAG, " mCardsParser.isCardUsb(" + addedCard + ") = "
- + mCardsParser.isCardUsb(addedCard));
+ Slog.d(TAG, "hasInput: " + hasInput + " hasOutput:" + hasOutput);
}
- if (mCardsParser.isCardUsb(addedCard)) {
- UsbAudioDevice audioDevice = selectAudioCard(addedCard);
- if (audioDevice != null) {
- mAudioDevices.put(usbDevice, audioDevice);
- Slog.i(TAG, "USB Audio Device Added: " + audioDevice);
+ if (hasInput || hasOutput) {
+ boolean isInputHeadset = parser.isInputHeadset();
+ boolean isOutputHeadset = parser.isOutputHeadset();
+ UsbAlsaDevice alsaDevice =
+ new UsbAlsaDevice(cardRec.getCardNum(), 0 /*device*/, deviceAddress,
+ hasOutput, hasInput, isInputHeadset, isOutputHeadset);
+ alsaDevice.setDeviceNameAndDescription(
+ cardRec.getCardName(), cardRec.getCardDescription());
+ mAlsaDevices.add(0, alsaDevice);
+
+ // Select it
+ if (alsaDevice != null) {
+ notifyDeviceState(alsaDevice, true /*enabled*/);
}
+ }
- // look for MIDI devices
+ // look for MIDI devices
+ boolean hasMidi = parser.hasMIDIInterface();
+ if (DEBUG) {
+ Slog.d(TAG, "hasMidi: " + hasMidi + " mHasMidiFeature:" + mHasMidiFeature);
+ }
+ if (hasMidi && mHasMidiFeature) {
+ int device = 0;
+ Bundle properties = new Bundle();
+ String manufacturer = usbDevice.getManufacturerName();
+ String product = usbDevice.getProductName();
+ String version = usbDevice.getVersion();
+ String name;
+ if (manufacturer == null || manufacturer.isEmpty()) {
+ name = product;
+ } else if (product == null || product.isEmpty()) {
+ name = manufacturer;
+ } else {
+ name = manufacturer + " " + product;
+ }
+ properties.putString(MidiDeviceInfo.PROPERTY_NAME, name);
+ properties.putString(MidiDeviceInfo.PROPERTY_MANUFACTURER, manufacturer);
+ properties.putString(MidiDeviceInfo.PROPERTY_PRODUCT, product);
+ properties.putString(MidiDeviceInfo.PROPERTY_VERSION, version);
+ properties.putString(MidiDeviceInfo.PROPERTY_SERIAL_NUMBER,
+ usbDevice.getSerialNumber());
+ properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_CARD, cardRec.getCardNum());
+ properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_DEVICE, 0 /*deviceNum*/);
+ properties.putParcelable(MidiDeviceInfo.PROPERTY_USB_DEVICE, usbDevice);
- // Don't need to call mDevicesParser.scan() because selectAudioCard() does this above.
- // Uncomment this next line if that behavior changes in the fugure.
- // mDevicesParser.scan()
-
- boolean hasMidi = mDevicesParser.hasMIDIDevices(addedCard);
- if (hasMidi && mHasMidiFeature) {
- int device = mDevicesParser.getDefaultDeviceNum(addedCard);
- AlsaDevice alsaDevice = waitForAlsaDevice(addedCard, device, AlsaDevice.TYPE_MIDI);
- if (alsaDevice != null) {
- Bundle properties = new Bundle();
- String manufacturer = usbDevice.getManufacturerName();
- String product = usbDevice.getProductName();
- String version = usbDevice.getVersion();
- String name;
- if (manufacturer == null || manufacturer.isEmpty()) {
- name = product;
- } else if (product == null || product.isEmpty()) {
- name = manufacturer;
- } else {
- name = manufacturer + " " + product;
- }
- properties.putString(MidiDeviceInfo.PROPERTY_NAME, name);
- properties.putString(MidiDeviceInfo.PROPERTY_MANUFACTURER, manufacturer);
- properties.putString(MidiDeviceInfo.PROPERTY_PRODUCT, product);
- properties.putString(MidiDeviceInfo.PROPERTY_VERSION, version);
- properties.putString(MidiDeviceInfo.PROPERTY_SERIAL_NUMBER,
- usbDevice.getSerialNumber());
- properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_CARD, alsaDevice.mCard);
- properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_DEVICE, alsaDevice.mDevice);
- properties.putParcelable(MidiDeviceInfo.PROPERTY_USB_DEVICE, usbDevice);
-
- UsbMidiDevice usbMidiDevice = UsbMidiDevice.create(mContext, properties,
- alsaDevice.mCard, alsaDevice.mDevice);
- if (usbMidiDevice != null) {
- mMidiDevices.put(usbDevice, usbMidiDevice);
- }
- }
+ UsbMidiDevice usbMidiDevice = UsbMidiDevice.create(mContext, properties,
+ cardRec.getCardNum(), 0 /*device*/);
+ if (usbMidiDevice != null) {
+ mMidiDevices.put(deviceAddress, usbMidiDevice);
}
}
@@ -455,39 +255,28 @@
}
}
- /* package */ void usbDeviceRemoved(UsbDevice usbDevice) {
+ /* package */ void usbDeviceRemoved(String deviceAddress/*UsbDevice usbDevice*/) {
if (DEBUG) {
- Slog.d(TAG, "deviceRemoved(): " + usbDevice.getManufacturerName() +
- " " + usbDevice.getProductName());
+ Slog.d(TAG, "deviceRemoved(" + deviceAddress + ")");
}
- UsbAudioDevice audioDevice = mAudioDevices.remove(usbDevice);
- Slog.i(TAG, "USB Audio Device Removed: " + audioDevice);
- if (audioDevice != null) {
- if (audioDevice.mHasPlayback || audioDevice.mHasCapture) {
- notifyDeviceState(audioDevice, false /*enabled*/);
+ // Audio
+ UsbAlsaDevice alsaDevice = removeAlsaDeviceFromList(deviceAddress);
+ Slog.i(TAG, "USB Audio Device Removed: " + alsaDevice);
+ if (alsaDevice != null) {
+ if (alsaDevice.hasPlayback() || alsaDevice.hasCapture()) {
+ notifyDeviceState(alsaDevice, false /*enabled*/);
// if there any external devices left, select one of them
selectDefaultDevice();
}
}
- UsbMidiDevice usbMidiDevice = mMidiDevices.remove(usbDevice);
- if (usbMidiDevice != null) {
- IoUtils.closeQuietly(usbMidiDevice);
- }
- }
- /* package */ void setAccessoryAudioState(boolean enabled, int card, int device) {
- if (DEBUG) {
- Slog.d(TAG, "setAccessoryAudioState " + enabled + " " + card + " " + device);
- }
- if (enabled) {
- mAccessoryAudioDevice = new UsbAudioDevice(card, device, true, false,
- UsbAudioDevice.kAudioDeviceClass_External);
- notifyDeviceState(mAccessoryAudioDevice, true /*enabled*/);
- } else if (mAccessoryAudioDevice != null) {
- notifyDeviceState(mAccessoryAudioDevice, false /*enabled*/);
- mAccessoryAudioDevice = null;
+ // MIDI
+ UsbMidiDevice usbMidiDevice = mMidiDevices.remove(deviceAddress);
+ if (usbMidiDevice != null) {
+ Slog.i(TAG, "USB MIDI Device Removed: " + usbMidiDevice);
+ IoUtils.closeQuietly(usbMidiDevice);
}
}
@@ -515,44 +304,31 @@
}
//
- // Devices List
- //
-/*
- //import java.util.ArrayList;
- public ArrayList<UsbAudioDevice> getConnectedDevices() {
- ArrayList<UsbAudioDevice> devices = new ArrayList<UsbAudioDevice>(mAudioDevices.size());
- for (HashMap.Entry<UsbDevice,UsbAudioDevice> entry : mAudioDevices.entrySet()) {
- devices.add(entry.getValue());
- }
- return devices;
- }
-*/
-
- //
// Logging
//
// called by UsbService.dump
public void dump(IndentingPrintWriter pw) {
pw.println("Parsers Scan Status:");
pw.println(" Cards Parser: " + mCardsParser.getScanStatus());
- pw.println(" Devices Parser: " + mDevicesParser.getScanStatus());
+// pw.println(" Devices Parser: " + mDevicesParser.getScanStatus());
pw.println("USB Audio Devices:");
- for (UsbDevice device : mAudioDevices.keySet()) {
- pw.println(" " + device.getDeviceName() + ": " + mAudioDevices.get(device));
+ for (UsbAlsaDevice usbAlsaDevice : mAlsaDevices) {
+ pw.println(" " + usbAlsaDevice.getDeviceAddress() + ": " + usbAlsaDevice);
}
pw.println("USB MIDI Devices:");
- for (UsbDevice device : mMidiDevices.keySet()) {
- pw.println(" " + device.getDeviceName() + ": " + mMidiDevices.get(device));
+ for (String deviceAddr : mMidiDevices.keySet()) {
+ UsbMidiDevice midiDevice = mMidiDevices.get(deviceAddr);
+ pw.println(" " + deviceAddr + ": " + midiDevice);
}
}
/*
public void logDevicesList(String title) {
if (DEBUG) {
- for (HashMap.Entry<UsbDevice,UsbAudioDevice> entry : mAudioDevices.entrySet()) {
+ for (HashMap.Entry<UsbDevice,UsbAlsaDevice> entry : mAudioDevices.entrySet()) {
Slog.i(TAG, "UsbDevice-------------------");
Slog.i(TAG, "" + (entry != null ? entry.getKey() : "[none]"));
- Slog.i(TAG, "UsbAudioDevice--------------");
+ Slog.i(TAG, "UsbAlsaDevice--------------");
Slog.i(TAG, "" + entry.getValue());
}
}
@@ -564,7 +340,7 @@
public void logDevices(String title) {
if (DEBUG) {
Slog.i(TAG, title);
- for (HashMap.Entry<UsbDevice,UsbAudioDevice> entry : mAudioDevices.entrySet()) {
+ for (HashMap.Entry<UsbDevice,UsbAlsaDevice> entry : mAudioDevices.entrySet()) {
Slog.i(TAG, entry.getValue().toShortString());
}
}
diff --git a/services/usb/java/com/android/server/usb/UsbAudioDevice.java b/services/usb/java/com/android/server/usb/UsbAudioDevice.java
deleted file mode 100644
index 4b17dfe..0000000
--- a/services/usb/java/com/android/server/usb/UsbAudioDevice.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions an
- * limitations under the License.
- */
-
-package com.android.server.usb;
-
-public final class UsbAudioDevice {
- private static final String TAG = "UsbAudioDevice";
- protected static final boolean DEBUG = false;
-
- public final int mCard;
- public final int mDevice;
- public final boolean mHasPlayback;
- public final boolean mHasCapture;
-
- // Device "class" flags
- public static final int kAudioDeviceClassMask = 0x00FFFFFF;
- public static final int kAudioDeviceClass_Undefined = 0x00000000;
- public static final int kAudioDeviceClass_Internal = 0x00000001;
- public static final int kAudioDeviceClass_External = 0x00000002;
- // Device meta-data flags
- public static final int kAudioDeviceMetaMask = 0xFF000000;
- public static final int kAudioDeviceMeta_Alsa = 0x80000000;
- // This member is a combination of the above bit-flags
- public final int mDeviceClass;
-
- private String mDeviceName = "";
- private String mDeviceDescription = "";
-
- public UsbAudioDevice(int card, int device,
- boolean hasPlayback, boolean hasCapture, int deviceClass) {
- mCard = card;
- mDevice = device;
- mHasPlayback = hasPlayback;
- mHasCapture = hasCapture;
- mDeviceClass = deviceClass;
- }
-
- public String toString() {
- StringBuilder sb = new StringBuilder();
- sb.append("UsbAudioDevice: [card: " + mCard);
- sb.append(", device: " + mDevice);
- sb.append(", name: " + mDeviceName);
- sb.append(", hasPlayback: " + mHasPlayback);
- sb.append(", hasCapture: " + mHasCapture);
- sb.append(", class: 0x" + Integer.toHexString(mDeviceClass) + "]");
- return sb.toString();
- }
-
- // called by logDevices
- String toShortString() {
- return "[card:" + mCard + " device:" + mDevice + " " + mDeviceName + "]";
- }
-
- String getDeviceName() {
- return mDeviceName;
- }
-
- void setDeviceNameAndDescription(String deviceName, String deviceDescription) {
- mDeviceName = deviceName;
- mDeviceDescription = deviceDescription;
- }
-
-}
-
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 55ffea6..a67e7f3 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -726,35 +726,9 @@
}
private void updateUsbFunctions() {
- updateAudioSourceFunction();
updateMidiFunction();
}
- private void updateAudioSourceFunction() {
- boolean enabled = (mCurrentFunctions & UsbManager.FUNCTION_AUDIO_SOURCE) != 0;
- if (enabled != mAudioSourceEnabled) {
- int card = -1;
- int device = -1;
-
- if (enabled) {
- Scanner scanner = null;
- try {
- scanner = new Scanner(new File(AUDIO_SOURCE_PCM_PATH));
- card = scanner.nextInt();
- device = scanner.nextInt();
- } catch (FileNotFoundException e) {
- Slog.e(TAG, "could not open audio source PCM file", e);
- } finally {
- if (scanner != null) {
- scanner.close();
- }
- }
- }
- mUsbAlsaManager.setAccessoryAudioState(enabled, card, device);
- mAudioSourceEnabled = enabled;
- }
- }
-
private void updateMidiFunction() {
boolean enabled = (mCurrentFunctions & UsbManager.FUNCTION_MIDI) != 0;
if (enabled != mMidiEnabled) {
diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
index 7a352a4..58f91477 100644
--- a/services/usb/java/com/android/server/usb/UsbHostManager.java
+++ b/services/usb/java/com/android/server/usb/UsbHostManager.java
@@ -44,7 +44,7 @@
*/
public class UsbHostManager {
private static final String TAG = UsbHostManager.class.getSimpleName();
- private static final boolean DEBUG = true;
+ private static final boolean DEBUG = false;
private final Context mContext;
@@ -230,6 +230,7 @@
}
private boolean isBlackListed(String deviceAddress) {
+ Slog.i(TAG, "isBlackListed(" + deviceAddress + ")");
int count = mHostBlacklist.length;
for (int i = 0; i < count; i++) {
if (deviceAddress.startsWith(mHostBlacklist[i])) {
@@ -241,6 +242,7 @@
/* returns true if the USB device should not be accessible by applications */
private boolean isBlackListed(int clazz, int subClass) {
+ Slog.i(TAG, "isBlackListed(" + clazz + ", " + subClass + ")");
// blacklist hubs
if (clazz == UsbConstants.USB_CLASS_HUB) return true;
@@ -312,13 +314,7 @@
usbDeviceConnectionHandler);
}
- // Headset?
- boolean isInputHeadset = parser.isInputHeadset();
- boolean isOutputHeadset = parser.isOutputHeadset();
- Slog.i(TAG, "---- isHeadset[in: " + isInputHeadset
- + " , out: " + isOutputHeadset + "]");
-
- mUsbAlsaManager.usbDeviceAdded(newDevice, isInputHeadset, isOutputHeadset);
+ mUsbAlsaManager.usbDeviceAdded(deviceAddress, newDevice, parser);
// Tracking
addConnectionRecord(deviceAddress, ConnectionRecord.CONNECT,
@@ -343,10 +339,13 @@
/* Called from JNI in monitorUsbHostBus to report USB device removal */
@SuppressWarnings("unused")
private void usbDeviceRemoved(String deviceAddress) {
+ if (DEBUG) {
+ Slog.d(TAG, "usbDeviceRemoved(" + deviceAddress + ") - start");
+ }
synchronized (mLock) {
UsbDevice device = mDevices.remove(deviceAddress);
if (device != null) {
- mUsbAlsaManager.usbDeviceRemoved(device);
+ mUsbAlsaManager.usbDeviceRemoved(deviceAddress/*device*/);
mSettingsManager.usbDeviceRemoved(device);
getCurrentUserSettings().usbDeviceRemoved(device);
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
index 7a1e9e2..297a6ea 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
@@ -26,7 +26,7 @@
*/
public final class UsbDescriptorParser {
private static final String TAG = "UsbDescriptorParser";
- private static final boolean DEBUG = true;
+ private static final boolean DEBUG = false;
private final String mDeviceAddr;
@@ -358,6 +358,139 @@
return list;
}
+ /*
+ * Attribute predicates
+ */
+ /**
+ * @hide
+ */
+ public boolean hasInput() {
+ if (DEBUG) {
+ Log.d(TAG, "---- hasInput()");
+ }
+ ArrayList<UsbDescriptor> acDescriptors =
+ getACInterfaceDescriptors(UsbACInterface.ACI_INPUT_TERMINAL,
+ UsbACInterface.AUDIO_AUDIOCONTROL);
+ boolean hasInput = false;
+ for (UsbDescriptor descriptor : acDescriptors) {
+ if (descriptor instanceof UsbACTerminal) {
+ UsbACTerminal inDescr = (UsbACTerminal) descriptor;
+ // Check for input and bi-directional terminal types
+ int type = inDescr.getTerminalType();
+ if (DEBUG) {
+ Log.d(TAG, " type:0x" + Integer.toHexString(type));
+ }
+ if ((type >= UsbTerminalTypes.TERMINAL_IN_UNDEFINED
+ && type <= UsbTerminalTypes.TERMINAL_IN_PROC_MIC_ARRAY)
+ || (type >= UsbTerminalTypes.TERMINAL_BIDIR_UNDEFINED
+ && type <= UsbTerminalTypes.TERMINAL_BIDIR_SKRPHONE_CANCEL)
+ || (type == UsbTerminalTypes.TERMINAL_USB_STREAMING)) {
+ hasInput = true;
+ break;
+ }
+ } else {
+ Log.w(TAG, "Undefined Audio Input terminal l: " + descriptor.getLength()
+ + " t:0x" + Integer.toHexString(descriptor.getType()));
+ }
+ }
+
+ if (DEBUG) {
+ Log.d(TAG, "hasInput() = " + hasInput);
+ }
+ return hasInput;
+ }
+
+ /**
+ * @hide
+ */
+ public boolean hasOutput() {
+ if (DEBUG) {
+ Log.d(TAG, "---- hasOutput()");
+ }
+ ArrayList<UsbDescriptor> acDescriptors =
+ getACInterfaceDescriptors(UsbACInterface.ACI_OUTPUT_TERMINAL,
+ UsbACInterface.AUDIO_AUDIOCONTROL);
+ boolean hasOutput = false;
+ for (UsbDescriptor descriptor : acDescriptors) {
+ if (descriptor instanceof UsbACTerminal) {
+ UsbACTerminal outDescr = (UsbACTerminal) descriptor;
+ // Check for output and bi-directional terminal types
+ int type = outDescr.getTerminalType();
+ if (DEBUG) {
+ Log.d(TAG, " type:0x" + Integer.toHexString(type));
+ }
+ if ((type >= UsbTerminalTypes.TERMINAL_OUT_UNDEFINED
+ && type <= UsbTerminalTypes.TERMINAL_OUT_LFSPEAKER)
+ || (type >= UsbTerminalTypes.TERMINAL_BIDIR_UNDEFINED
+ && type <= UsbTerminalTypes.TERMINAL_BIDIR_SKRPHONE_CANCEL)) {
+ hasOutput = true;
+ break;
+ }
+ } else {
+ Log.w(TAG, "Undefined Audio Input terminal l: " + descriptor.getLength()
+ + " t:0x" + Integer.toHexString(descriptor.getType()));
+ }
+ }
+ if (DEBUG) {
+ Log.d(TAG, "hasOutput() = " + hasOutput);
+ }
+ return hasOutput;
+ }
+
+ /**
+ * @hide
+ */
+ public boolean hasMic() {
+ boolean hasMic = false;
+
+ ArrayList<UsbDescriptor> acDescriptors =
+ getACInterfaceDescriptors(UsbACInterface.ACI_INPUT_TERMINAL,
+ UsbACInterface.AUDIO_AUDIOCONTROL);
+ for (UsbDescriptor descriptor : acDescriptors) {
+ if (descriptor instanceof UsbACTerminal) {
+ UsbACTerminal inDescr = (UsbACTerminal) descriptor;
+ if (inDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_IN_MIC
+ || inDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_BIDIR_HEADSET
+ || inDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_BIDIR_UNDEFINED
+ || inDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_EXTERN_LINE) {
+ hasMic = true;
+ break;
+ }
+ } else {
+ Log.w(TAG, "Undefined Audio Input terminal l: " + descriptor.getLength()
+ + " t:0x" + Integer.toHexString(descriptor.getType()));
+ }
+ }
+ return hasMic;
+ }
+
+ /**
+ * @hide
+ */
+ public boolean hasSpeaker() {
+ boolean hasSpeaker = false;
+
+ ArrayList<UsbDescriptor> acDescriptors =
+ getACInterfaceDescriptors(UsbACInterface.ACI_OUTPUT_TERMINAL,
+ UsbACInterface.AUDIO_AUDIOCONTROL);
+ for (UsbDescriptor descriptor : acDescriptors) {
+ if (descriptor instanceof UsbACTerminal) {
+ UsbACTerminal outDescr = (UsbACTerminal) descriptor;
+ if (outDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_OUT_SPEAKER
+ || outDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_OUT_HEADPHONES
+ || outDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_BIDIR_HEADSET) {
+ hasSpeaker = true;
+ break;
+ }
+ } else {
+ Log.w(TAG, "Undefined Audio Output terminal l: " + descriptor.getLength()
+ + " t:0x" + Integer.toHexString(descriptor.getType()));
+ }
+ }
+
+ return hasSpeaker;
+ }
+
/**
* @hide
*/
@@ -397,48 +530,12 @@
}
float probability = 0.0f;
- ArrayList<UsbDescriptor> acDescriptors;
// Look for a microphone
- boolean hasMic = false;
- acDescriptors = getACInterfaceDescriptors(UsbACInterface.ACI_INPUT_TERMINAL,
- UsbACInterface.AUDIO_AUDIOCONTROL);
- for (UsbDescriptor descriptor : acDescriptors) {
- if (descriptor instanceof UsbACTerminal) {
- UsbACTerminal inDescr = (UsbACTerminal) descriptor;
- if (inDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_IN_MIC
- || inDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_BIDIR_HEADSET
- || inDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_BIDIR_UNDEFINED
- || inDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_EXTERN_LINE) {
- hasMic = true;
- break;
- }
- } else {
- Log.w(TAG, "Undefined Audio Input terminal l: " + descriptor.getLength()
- + " t:0x" + Integer.toHexString(descriptor.getType()));
- }
- }
+ boolean hasMic = hasMic();
// Look for a "speaker"
- boolean hasSpeaker = false;
- acDescriptors =
- getACInterfaceDescriptors(UsbACInterface.ACI_OUTPUT_TERMINAL,
- UsbACInterface.AUDIO_AUDIOCONTROL);
- for (UsbDescriptor descriptor : acDescriptors) {
- if (descriptor instanceof UsbACTerminal) {
- UsbACTerminal outDescr = (UsbACTerminal) descriptor;
- if (outDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_OUT_SPEAKER
- || outDescr.getTerminalType()
- == UsbTerminalTypes.TERMINAL_OUT_HEADPHONES
- || outDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_BIDIR_HEADSET) {
- hasSpeaker = true;
- break;
- }
- } else {
- Log.w(TAG, "Undefined Audio Output terminal l: " + descriptor.getLength()
- + " t:0x" + Integer.toHexString(descriptor.getType()));
- }
- }
+ boolean hasSpeaker = hasSpeaker();
if (hasMic && hasSpeaker) {
probability += 0.75f;
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index fcfc593..95eb14a 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -134,6 +134,25 @@
"android.telecom.extra.LOG_SELF_MANAGED_CALLS";
/**
+ * Boolean {@link PhoneAccount} extras key (see {@link PhoneAccount#getExtras()}) which
+ * indicates whether calls for a {@link PhoneAccount} should generate a "call recording tone"
+ * when the user is recording audio on the device.
+ * <p>
+ * The call recording tone is played over the telephony audio stream so that the remote party
+ * has an audible indication that it is possible their call is being recorded using a call
+ * recording app on the device.
+ * <p>
+ * This extra only has an effect for calls placed via Telephony (e.g.
+ * {@link #CAPABILITY_SIM_SUBSCRIPTION}).
+ * <p>
+ * The call recording tone is a 1400 hz tone which repeats every 15 seconds while recording is
+ * in progress.
+ * @hide
+ */
+ public static final String EXTRA_PLAY_CALL_RECORDING_TONE =
+ "android.telecom.extra.PLAY_CALL_RECORDING_TONE";
+
+ /**
* Flag indicating that this {@code PhoneAccount} can act as a connection manager for
* other connections. The {@link ConnectionService} associated with this {@code PhoneAccount}
* will be allowed to manage phone calls including using its own proprietary phone-call
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index a34e9f9..63ab766 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -77,6 +77,14 @@
public static final String
KEY_CARRIER_VOLTE_PROVISIONED_BOOL = "carrier_volte_provisioned_bool";
+ /**
+ * Boolean indicating if the "Call barring" item is visible in the Call Settings menu.
+ * true means visible. false means gone.
+ * @hide
+ */
+ public static final String KEY_CALL_BARRING_VISIBILITY_BOOL =
+ "call_barring_visibility_bool";
+
/**
* Flag indicating whether the Phone app should ignore EVENT_SIM_NETWORK_LOCKED
* events from the Sim.
@@ -146,6 +154,15 @@
public static final String KEY_ALLOW_LOCAL_DTMF_TONES_BOOL = "allow_local_dtmf_tones_bool";
/**
+ * Determines if the carrier requires that a tone be played to the remote party when an app is
+ * recording audio during a call (e.g. using a call recording app).
+ * <p>
+ * Note: This requires the Telephony config_supports_telephony_audio_device overlay to be true
+ * in order to work.
+ * @hide
+ */
+ public static final String KEY_PLAY_CALL_RECORDING_TONE_BOOL = "play_call_recording_tone_bool";
+ /**
* Determines if the carrier requires converting the destination number before sending out an
* SMS. Certain networks and numbering plans require different formats.
*/
@@ -1381,6 +1398,14 @@
public static final String KEY_VIDEO_CALLS_CAN_BE_HD_AUDIO = "video_calls_can_be_hd_audio";
/**
+ * When true, indicates that the HD audio icon in the in-call screen should be shown for
+ * GSM/CDMA calls.
+ * @hide
+ */
+ public static final String KEY_GSM_CDMA_CALLS_CAN_BE_HD_AUDIO =
+ "gsm_cdma_calls_can_be_hd_audio";
+
+ /**
* Whether system apps are allowed to use fallback if carrier video call is not available.
* Defaults to {@code true}.
*
@@ -1793,6 +1818,7 @@
sDefaults.putBoolean(KEY_ADDITIONAL_CALL_SETTING_BOOL, true);
sDefaults.putBoolean(KEY_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG_BOOL, false);
sDefaults.putBoolean(KEY_ALLOW_LOCAL_DTMF_TONES_BOOL, true);
+ sDefaults.putBoolean(KEY_PLAY_CALL_RECORDING_TONE_BOOL, false);
sDefaults.putBoolean(KEY_APN_EXPAND_BOOL, true);
sDefaults.putBoolean(KEY_AUTO_RETRY_ENABLED_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_SETTINGS_ENABLE_BOOL, false);
@@ -1833,6 +1859,7 @@
sDefaults.putBoolean(KEY_HIDE_SIM_LOCK_SETTINGS_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_VOLTE_PROVISIONED_BOOL, false);
+ sDefaults.putBoolean(KEY_CALL_BARRING_VISIBILITY_BOOL, false);
sDefaults.putBoolean(KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL, false);
sDefaults.putBoolean(KEY_MDN_IS_ADDITIONAL_VOICEMAIL_NUMBER_BOOL, false);
sDefaults.putBoolean(KEY_OPERATOR_SELECTION_EXPAND_BOOL, true);
@@ -2033,6 +2060,7 @@
sDefaults.putBoolean(KEY_ALLOW_ADD_CALL_DURING_VIDEO_CALL_BOOL, true);
sDefaults.putBoolean(KEY_WIFI_CALLS_CAN_BE_HD_AUDIO, true);
sDefaults.putBoolean(KEY_VIDEO_CALLS_CAN_BE_HD_AUDIO, true);
+ sDefaults.putBoolean(KEY_GSM_CDMA_CALLS_CAN_BE_HD_AUDIO, false);
sDefaults.putBoolean(KEY_ALLOW_VIDEO_CALLING_FALLBACK_BOOL, true);
sDefaults.putStringArray(KEY_IMS_REASONINFO_MAPPING_STRING_ARRAY, null);
diff --git a/telephony/java/android/telephony/CellSignalStrengthCdma.java b/telephony/java/android/telephony/CellSignalStrengthCdma.java
index dfaaab9..ece1ee3 100644
--- a/telephony/java/android/telephony/CellSignalStrengthCdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthCdma.java
@@ -36,48 +36,14 @@
private int mEvdoEcio; // This value is the EVDO Ec/Io
private int mEvdoSnr; // Valid values are 0-8. 8 is the highest signal to noise ratio
- /**
- * Empty constructor
- *
- * @hide
- */
+ /** @hide */
public CellSignalStrengthCdma() {
setDefaultValues();
}
- /**
- * Constructor
- *
- * @hide
- */
+ /** @hide */
public CellSignalStrengthCdma(int cdmaDbm, int cdmaEcio, int evdoDbm, int evdoEcio,
int evdoSnr) {
- initialize(cdmaDbm, cdmaEcio, evdoDbm, evdoEcio, evdoSnr);
- }
-
- /**
- * Copy constructors
- *
- * @param s Source SignalStrength
- *
- * @hide
- */
- public CellSignalStrengthCdma(CellSignalStrengthCdma s) {
- copyFrom(s);
- }
-
- /**
- * Initialize all the values
- *
- * @param cdmaDbm
- * @param cdmaEcio
- * @param evdoDbm
- * @param evdoEcio
- * @param evdoSnr
- *
- * @hide
- */
- public void initialize(int cdmaDbm, int cdmaEcio, int evdoDbm, int evdoEcio, int evdoSnr) {
mCdmaDbm = cdmaDbm;
mCdmaEcio = cdmaEcio;
mEvdoDbm = evdoDbm;
@@ -85,9 +51,12 @@
mEvdoSnr = evdoSnr;
}
- /**
- * @hide
- */
+ /** @hide */
+ public CellSignalStrengthCdma(CellSignalStrengthCdma s) {
+ copyFrom(s);
+ }
+
+ /** @hide */
protected void copyFrom(CellSignalStrengthCdma s) {
mCdmaDbm = s.mCdmaDbm;
mCdmaEcio = s.mCdmaEcio;
@@ -96,9 +65,7 @@
mEvdoSnr = s.mEvdoSnr;
}
- /**
- * @hide
- */
+ /** @hide */
@Override
public CellSignalStrengthCdma copy() {
return new CellSignalStrengthCdma(this);
diff --git a/telephony/java/android/telephony/CellSignalStrengthGsm.java b/telephony/java/android/telephony/CellSignalStrengthGsm.java
index f68d2ca..8687cd1 100644
--- a/telephony/java/android/telephony/CellSignalStrengthGsm.java
+++ b/telephony/java/android/telephony/CellSignalStrengthGsm.java
@@ -34,80 +34,40 @@
private static final int GSM_SIGNAL_STRENGTH_GOOD = 8;
private static final int GSM_SIGNAL_STRENGTH_MODERATE = 5;
- private int mSignalStrength; // Valid values are (0-31, 99) as defined in TS 27.007 8.5
+ private int mSignalStrength; // in ASU; Valid values are (0-31, 99) as defined in TS 27.007 8.5
private int mBitErrorRate; // bit error rate (0-7, 99) as defined in TS 27.007 8.5
- private int mTimingAdvance;
+ private int mTimingAdvance; // range from 0-219 or Integer.MAX_VALUE if unknown
- /**
- * Empty constructor
- *
- * @hide
- */
+ /** @hide */
public CellSignalStrengthGsm() {
setDefaultValues();
}
- /**
- * Constructor
- *
- * @hide
- */
+ /** @hide */
public CellSignalStrengthGsm(int ss, int ber) {
- initialize(ss, ber);
+ this(ss, ber, Integer.MAX_VALUE);
}
- /**
- * Copy constructors
- *
- * @param s Source SignalStrength
- *
- * @hide
- */
- public CellSignalStrengthGsm(CellSignalStrengthGsm s) {
- copyFrom(s);
- }
-
- /**
- * Initialize all the values
- *
- * @param ss SignalStrength as ASU value
- * @param ber is Bit Error Rate
- *
- * @hide
- */
- public void initialize(int ss, int ber) {
- mSignalStrength = ss;
- mBitErrorRate = ber;
- mTimingAdvance = Integer.MAX_VALUE;
- }
-
- /**
- * Initialize all the values
- *
- * @param ss SignalStrength as ASU value
- * @param ber is Bit Error Rate
- * @param ta timing advance
- *
- * @hide
- */
- public void initialize(int ss, int ber, int ta) {
+ /** @hide */
+ public CellSignalStrengthGsm(int ss, int ber, int ta) {
mSignalStrength = ss;
mBitErrorRate = ber;
mTimingAdvance = ta;
}
- /**
- * @hide
- */
+ /** @hide */
+ public CellSignalStrengthGsm(CellSignalStrengthGsm s) {
+ copyFrom(s);
+ }
+
+ /** @hide */
protected void copyFrom(CellSignalStrengthGsm s) {
mSignalStrength = s.mSignalStrength;
mBitErrorRate = s.mBitErrorRate;
mTimingAdvance = s.mTimingAdvance;
}
- /**
- * @hide
- */
+ /** @hide */
@Override
public CellSignalStrengthGsm copy() {
return new CellSignalStrengthGsm(this);
diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java
index 6ffc8b6..f009fb1 100644
--- a/telephony/java/android/telephony/CellSignalStrengthLte.java
+++ b/telephony/java/android/telephony/CellSignalStrengthLte.java
@@ -37,50 +37,15 @@
private int mCqi;
private int mTimingAdvance;
- /**
- * Empty constructor
- *
- * @hide
- */
+ /** @hide */
public CellSignalStrengthLte() {
setDefaultValues();
}
- /**
- * Constructor
- *
- * @hide
- */
+ /** @hide */
public CellSignalStrengthLte(int signalStrength, int rsrp, int rsrq, int rssnr, int cqi,
int timingAdvance) {
- initialize(signalStrength, rsrp, rsrq, rssnr, cqi, timingAdvance);
- }
-
- /**
- * Copy constructors
- *
- * @param s Source SignalStrength
- *
- * @hide
- */
- public CellSignalStrengthLte(CellSignalStrengthLte s) {
- copyFrom(s);
- }
-
- /**
- * Initialize all the values
- *
- * @param lteSignalStrength
- * @param rsrp
- * @param rsrq
- * @param rssnr
- * @param cqi
- *
- * @hide
- */
- public void initialize(int lteSignalStrength, int rsrp, int rsrq, int rssnr, int cqi,
- int timingAdvance) {
- mSignalStrength = lteSignalStrength;
+ mSignalStrength = signalStrength;
mRsrp = rsrp;
mRsrq = rsrq;
mRssnr = rssnr;
@@ -88,25 +53,12 @@
mTimingAdvance = timingAdvance;
}
- /**
- * Initialize from the SignalStrength structure.
- *
- * @param ss
- *
- * @hide
- */
- public void initialize(SignalStrength ss, int timingAdvance) {
- mSignalStrength = ss.getLteSignalStrength();
- mRsrp = ss.getLteRsrp();
- mRsrq = ss.getLteRsrq();
- mRssnr = ss.getLteRssnr();
- mCqi = ss.getLteCqi();
- mTimingAdvance = timingAdvance;
+ /** @hide */
+ public CellSignalStrengthLte(CellSignalStrengthLte s) {
+ copyFrom(s);
}
- /**
- * @hide
- */
+ /** @hide */
protected void copyFrom(CellSignalStrengthLte s) {
mSignalStrength = s.mSignalStrength;
mRsrp = s.mRsrp;
@@ -116,9 +68,7 @@
mTimingAdvance = s.mTimingAdvance;
}
- /**
- * @hide
- */
+ /** @hide */
@Override
public CellSignalStrengthLte copy() {
return new CellSignalStrengthLte(this);
diff --git a/telephony/java/android/telephony/CellSignalStrengthWcdma.java b/telephony/java/android/telephony/CellSignalStrengthWcdma.java
index 2cd56b8..dd32a96 100644
--- a/telephony/java/android/telephony/CellSignalStrengthWcdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthWcdma.java
@@ -34,62 +34,32 @@
private static final int WCDMA_SIGNAL_STRENGTH_GOOD = 8;
private static final int WCDMA_SIGNAL_STRENGTH_MODERATE = 5;
- private int mSignalStrength; // Valid values are (0-31, 99) as defined in TS 27.007 8.5
- private int mBitErrorRate; // bit error rate (0-7, 99) as defined in TS 27.007 8.5
+ private int mSignalStrength; // in ASU; Valid values are (0-31, 99) as defined in TS 27.007 8.5
+ private int mBitErrorRate; // bit error rate (0-7, 99) as defined in TS 27.007 8.5
- /**
- * Empty constructor
- *
- * @hide
- */
+ /** @hide */
public CellSignalStrengthWcdma() {
setDefaultValues();
}
- /**
- * Constructor
- *
- * @hide
- */
+ /** @hide */
public CellSignalStrengthWcdma(int ss, int ber) {
- initialize(ss, ber);
- }
-
- /**
- * Copy constructors
- *
- * @param s Source SignalStrength
- *
- * @hide
- */
- public CellSignalStrengthWcdma(CellSignalStrengthWcdma s) {
- copyFrom(s);
- }
-
- /**
- * Initialize all the values
- *
- * @param ss SignalStrength as ASU value
- * @param ber is Bit Error Rate
- *
- * @hide
- */
- public void initialize(int ss, int ber) {
mSignalStrength = ss;
mBitErrorRate = ber;
}
- /**
- * @hide
- */
+ /** @hide */
+ public CellSignalStrengthWcdma(CellSignalStrengthWcdma s) {
+ copyFrom(s);
+ }
+
+ /** @hide */
protected void copyFrom(CellSignalStrengthWcdma s) {
mSignalStrength = s.mSignalStrength;
mBitErrorRate = s.mBitErrorRate;
}
- /**
- * @hide
- */
+ /** @hide */
@Override
public CellSignalStrengthWcdma copy() {
return new CellSignalStrengthWcdma(this);
diff --git a/telephony/java/android/telephony/LocationAccessPolicy.java b/telephony/java/android/telephony/LocationAccessPolicy.java
new file mode 100644
index 0000000..b362df9
--- /dev/null
+++ b/telephony/java/android/telephony/LocationAccessPolicy.java
@@ -0,0 +1,160 @@
+/*
+ * 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.telephony;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.app.ActivityManager;
+import android.app.AppOpsManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.location.LocationManager;
+import android.os.Binder;
+import android.os.Build;
+import android.os.Process;
+import android.os.Trace;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.util.SparseBooleanArray;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Helper for performing location access checks.
+ * @hide
+ */
+public final class LocationAccessPolicy {
+ /**
+ * API to determine if the caller has permissions to get cell location.
+ *
+ * @param pkgName Package name of the application requesting access
+ * @param uid The uid of the package
+ * @param pid The pid of the package
+ * @return boolean true or false if permissions is granted
+ */
+ public static boolean canAccessCellLocation(@NonNull Context context, @NonNull String pkgName,
+ int uid, int pid) throws SecurityException {
+ Trace.beginSection("TelephonyLocationCheck");
+ try {
+ // Always allow the phone process to access location. This avoid breaking legacy code
+ // that rely on public-facing APIs to access cell location, and it doesn't create a
+ // info leak risk because the cell location is stored in the phone process anyway.
+ if (uid == Process.PHONE_UID) {
+ return true;
+ }
+
+ // We always require the location permission and also require the
+ // location mode to be on for non-legacy apps. Legacy apps are
+ // required to be in the foreground to at least mitigate the case
+ // where a legacy app the user is not using tracks their location.
+ // Granting ACCESS_FINE_LOCATION to an app automatically grants it
+ // ACCESS_COARSE_LOCATION.
+
+ if (context.checkPermission(Manifest.permission.ACCESS_COARSE_LOCATION, pid, uid) ==
+ PackageManager.PERMISSION_DENIED) {
+ return false;
+ }
+ final int opCode = AppOpsManager.permissionToOpCode(
+ Manifest.permission.ACCESS_COARSE_LOCATION);
+ if (opCode != AppOpsManager.OP_NONE && context.getSystemService(AppOpsManager.class)
+ .noteOpNoThrow(opCode, uid, pkgName) != AppOpsManager.MODE_ALLOWED) {
+ return false;
+ }
+ if (!isLocationModeEnabled(context, UserHandle.getUserId(uid))
+ && !isLegacyForeground(context, pkgName, uid)) {
+ return false;
+ }
+ // If the user or profile is current, permission is granted.
+ // Otherwise, uid must have INTERACT_ACROSS_USERS_FULL permission.
+ return isCurrentProfile(context, uid) || checkInteractAcrossUsersFull(context);
+ } finally {
+ Trace.endSection();
+ }
+ }
+
+ private static boolean isLocationModeEnabled(@NonNull Context context, @UserIdInt int userId) {
+ int locationMode = Settings.Secure.getIntForUser(context.getContentResolver(),
+ Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF, userId);
+ return locationMode != Settings.Secure.LOCATION_MODE_OFF
+ && locationMode != Settings.Secure.LOCATION_MODE_SENSORS_ONLY;
+ }
+
+ private static boolean isLegacyForeground(@NonNull Context context, @NonNull String pkgName,
+ int uid) {
+ long token = Binder.clearCallingIdentity();
+ try {
+ return isLegacyVersion(context, pkgName) && isForegroundApp(context, uid);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ private static boolean isLegacyVersion(@NonNull Context context, @NonNull String pkgName) {
+ try {
+ if (context.getPackageManager().getApplicationInfo(pkgName, 0)
+ .targetSdkVersion <= Build.VERSION_CODES.O) {
+ return true;
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ // In case of exception, assume known app (more strict checking)
+ // Note: This case will never happen since checkPackage is
+ // called to verify validity before checking app's version.
+ }
+ return false;
+ }
+
+ private static boolean isForegroundApp(@NonNull Context context, int uid) {
+ final ActivityManager am = context.getSystemService(ActivityManager.class);
+ return am.getUidImportance(uid) <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
+ }
+
+ private static boolean checkInteractAcrossUsersFull(@NonNull Context context) {
+ return context.checkCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+ == PackageManager.PERMISSION_GRANTED;
+ }
+
+ private static boolean isCurrentProfile(@NonNull Context context, int uid) {
+ long token = Binder.clearCallingIdentity();
+ try {
+ final int currentUser = ActivityManager.getCurrentUser();
+ final int callingUserId = UserHandle.getUserId(uid);
+ if (callingUserId == currentUser) {
+ return true;
+ } else {
+ List<UserInfo> userProfiles = context.getSystemService(
+ UserManager.class).getProfiles(currentUser);
+ for (UserInfo user : userProfiles) {
+ if (user.id == callingUserId) {
+ return true;
+ }
+ }
+ }
+ return false;
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+}
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index debf43d..34f2dac 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -612,9 +612,9 @@
* onSubscriptionsChanged overridden.
*/
public void addOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener) {
- String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
+ String pkgName = mContext != null ? mContext.getOpPackageName() : "<unknown>";
if (DBG) {
- logd("register OnSubscriptionsChangedListener pkgForDebug=" + pkgForDebug
+ logd("register OnSubscriptionsChangedListener pkgName=" + pkgName
+ " listener=" + listener);
}
try {
@@ -623,7 +623,7 @@
ITelephonyRegistry tr = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
"telephony.registry"));
if (tr != null) {
- tr.addOnSubscriptionsChangedListener(pkgForDebug, listener.callback);
+ tr.addOnSubscriptionsChangedListener(pkgName, listener.callback);
}
} catch (RemoteException ex) {
// Should not happen
diff --git a/tests/ActivityManagerPerfTests/test-app/AndroidManifest.xml b/tests/ActivityManagerPerfTests/test-app/AndroidManifest.xml
index 7145110..021e386 100644
--- a/tests/ActivityManagerPerfTests/test-app/AndroidManifest.xml
+++ b/tests/ActivityManagerPerfTests/test-app/AndroidManifest.xml
@@ -14,12 +14,16 @@
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.frameworks.perftests.amteststestapp">
+ package="com.android.frameworks.perftests.amteststestapp">
<application android:name=".TestApplication">
<activity android:name=".TestActivity" android:exported="true"/>
+ <provider
+ android:authorities="com.android.frameworks.perftests.amteststestapp"
+ android:name=".TestContentProvider"
+ android:exported="true" />
<receiver
- android:name=".TestBroadcastReceiver"
- android:exported="true">
+ android:name=".TestBroadcastReceiver"
+ android:exported="true">
<intent-filter>
<action android:name="com.android.frameworks.perftests.ACTION_BROADCAST_MANIFEST_RECEIVE" />
<category android:name="android.intent.category.DEFAULT" />
diff --git a/tests/ActivityManagerPerfTests/test-app/src/com/android/frameworks/perftests/amteststestapp/TestContentProvider.java b/tests/ActivityManagerPerfTests/test-app/src/com/android/frameworks/perftests/amteststestapp/TestContentProvider.java
new file mode 100644
index 0000000..0940578
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/test-app/src/com/android/frameworks/perftests/amteststestapp/TestContentProvider.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.frameworks.perftests.amteststestapp;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+
+public class TestContentProvider extends ContentProvider {
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ return null;
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+ String sortOrder) {
+ return null;
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ return null;
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ return 0;
+ }
+
+ @Override
+ public boolean onCreate() {
+ return false;
+ }
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ return 0;
+ }
+}
diff --git a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ContentProviderPerfTest.java b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ContentProviderPerfTest.java
new file mode 100644
index 0000000..3bf56ce
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ContentProviderPerfTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.frameworks.perftests.am.tests;
+
+import android.content.ContentProviderClient;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.frameworks.perftests.am.util.TargetPackageUtils;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class ContentProviderPerfTest extends BasePerfTest {
+ /**
+ * Benchmark time to call ContentResolver.acquireContentProviderClient() when target package is
+ * running.
+ */
+ @Test
+ public void contentProviderRunning() {
+ runPerfFunction(() -> {
+ startTargetPackage();
+
+ long startTimeNs = System.nanoTime();
+ final ContentProviderClient contentProviderClient =
+ mContext.getContentResolver()
+ .acquireContentProviderClient(TargetPackageUtils.PACKAGE_NAME);
+ final long endTimeNs = System.nanoTime();
+
+ contentProviderClient.close();
+
+ return endTimeNs - startTimeNs;
+ });
+ }
+
+ /**
+ * Benchmark time to call ContentResolver.acquireContentProviderClient() when target package is
+ * not running.
+ */
+ @Test
+ public void contentProviderNotRunning() {
+ runPerfFunction(() -> {
+ final long startTimeNs = System.nanoTime();
+ final ContentProviderClient contentProviderClient =
+ mContext.getContentResolver().acquireContentProviderClient(
+ TargetPackageUtils.PACKAGE_NAME);
+ final long endTimeNs = System.nanoTime();
+
+ contentProviderClient.close();
+
+ return endTimeNs - startTimeNs;
+ });
+ }
+}
diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
index 1443fc1..063060f 100644
--- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
+++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
@@ -83,7 +83,7 @@
private static final String KEY_TRACE_DUMPINTERVAL = "tracedump_interval";
private static final String WEARABLE_ACTION_GOOGLE =
"com.google.android.wearable.action.GOOGLE";
- private static final int INITIAL_LAUNCH_IDLE_TIMEOUT = 60000; //60s to allow app to idle
+ private static final int INITIAL_LAUNCH_IDLE_TIMEOUT = 5000; //5s to allow app to idle
private static final int POST_LAUNCH_IDLE_TIMEOUT = 750; //750ms idle for non initial launches
private static final int BETWEEN_LAUNCH_SLEEP_TIMEOUT = 5000; //5s between launching apps
private static final String LAUNCH_SUB_DIRECTORY = "launch_logs";